Fix NPE when returning to profile from background.

Also generally improves saved-state management for Profile editor.
This commit is contained in:
Alex Hart 2020-01-28 14:57:17 -04:00 committed by GitHub
parent e3878ffde7
commit 4ae7d56db4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 22 deletions

View File

@ -31,8 +31,10 @@ public class EditProfileActivity extends BaseActionBarActivity implements EditPr
setContentView(R.layout.profile_create_activity); setContentView(R.layout.profile_create_activity);
NavGraph graph = Navigation.findNavController(this, R.id.nav_host_fragment).getGraph(); if (bundle == null) {
Navigation.findNavController(this, R.id.nav_host_fragment).setGraph(graph, getIntent().getExtras()); NavGraph graph = Navigation.findNavController(this, R.id.nav_host_fragment).getGraph();
Navigation.findNavController(this, R.id.nav_host_fragment).setGraph(graph, getIntent().getExtras());
}
} }
@Override @Override

View File

@ -57,7 +57,8 @@ import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.SHOW_
public class EditProfileFragment extends Fragment { public class EditProfileFragment extends Fragment {
private static final String TAG = Log.tag(EditProfileFragment.class); private static final String TAG = Log.tag(EditProfileFragment.class);
private static final String AVATAR_STATE = "avatar";
private Toolbar toolbar; private Toolbar toolbar;
private View title; private View title;
@ -115,7 +116,7 @@ public class EditProfileFragment extends Fragment {
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
initializeResources(view); initializeResources(view);
initializeViewModel(requireArguments().getBoolean(EXCLUDE_SYSTEM, false)); initializeViewModel(requireArguments().getBoolean(EXCLUDE_SYSTEM, false), savedInstanceState != null);
initializeProfileName(); initializeProfileName();
initializeProfileAvatar(); initializeProfileAvatar();
initializeUsername(); initializeUsername();
@ -123,6 +124,20 @@ public class EditProfileFragment extends Fragment {
requireActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); requireActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
} }
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putByteArray(AVATAR_STATE, viewModel.getAvatarSnapshot());
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey(AVATAR_STATE)) {
viewModel.setAvatar(savedInstanceState.getByteArray(AVATAR_STATE));
}
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults); Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
@ -181,9 +196,9 @@ public class EditProfileFragment extends Fragment {
} }
} }
private void initializeViewModel(boolean excludeSystem) { private void initializeViewModel(boolean excludeSystem, boolean hasSavedInstanceState) {
EditProfileRepository repository = new EditProfileRepository(requireContext(), excludeSystem); EditProfileRepository repository = new EditProfileRepository(requireContext(), excludeSystem);
EditProfileViewModel.Factory factory = new EditProfileViewModel.Factory(repository); EditProfileViewModel.Factory factory = new EditProfileViewModel.Factory(repository, hasSavedInstanceState);
viewModel = ViewModelProviders.of(this, factory).get(EditProfileViewModel.class); viewModel = ViewModelProviders.of(this, factory).get(EditProfileViewModel.class);
} }
@ -246,17 +261,17 @@ public class EditProfileFragment extends Fragment {
} }
private void initializeProfileName() { private void initializeProfileName() {
viewModel.profileName().observe(this, profileName -> { viewModel.givenName().observe(this, givenName -> updateFieldIfNeeded(this.givenName, givenName));
updateFieldIfNeeded(givenName, profileName.getGivenName()); viewModel.familyName().observe(this, familyName -> updateFieldIfNeeded(this.familyName, familyName));
updateFieldIfNeeded(familyName, profileName.getFamilyName());
viewModel.profileName().observe(this, profileName -> {
preview.setText(profileName.toString());
boolean validEntry = !profileName.isGivenNameEmpty(); boolean validEntry = !profileName.isGivenNameEmpty();
finishButton.setEnabled(validEntry); finishButton.setEnabled(validEntry);
finishButton.setAlpha(validEntry ? 1f : 0.5f); finishButton.setAlpha(validEntry ? 1f : 0.5f);
preview.setText(profileName.toString());
}); });
} }

View File

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.profiles.edit; package org.thoughtcrime.securesms.profiles.edit;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
@ -22,19 +23,30 @@ class EditProfileViewModel extends ViewModel {
private final MutableLiveData<Optional<String>> internalUsername = new MutableLiveData<>(); private final MutableLiveData<Optional<String>> internalUsername = new MutableLiveData<>();
private final EditProfileRepository repository; private final EditProfileRepository repository;
private EditProfileViewModel(@NonNull EditProfileRepository repository) { private EditProfileViewModel(@NonNull EditProfileRepository repository, boolean hasInstanceState) {
this.repository = repository; this.repository = repository;
repository.getCurrentUsername(internalUsername::postValue); repository.getCurrentUsername(internalUsername::postValue);
repository.getCurrentProfileName(name -> {
givenName.setValue(name.getGivenName()); if (!hasInstanceState) {
familyName.setValue(name.getFamilyName()); repository.getCurrentProfileName(name -> {
}); givenName.setValue(name.getGivenName());
repository.getCurrentAvatar(internalAvatar::setValue); familyName.setValue(name.getFamilyName());
});
repository.getCurrentAvatar(internalAvatar::setValue);
}
}
public LiveData<String> givenName() {
return Transformations.distinctUntilChanged(givenName);
}
public LiveData<String> familyName() {
return Transformations.distinctUntilChanged(familyName);
} }
public LiveData<ProfileName> profileName() { public LiveData<ProfileName> profileName() {
return internalProfileName; return Transformations.distinctUntilChanged(internalProfileName);
} }
public LiveData<byte[]> avatar() { public LiveData<byte[]> avatar() {
@ -49,6 +61,11 @@ class EditProfileViewModel extends ViewModel {
return internalAvatar.getValue() != null; return internalAvatar.getValue() != null;
} }
@MainThread
public byte[] getAvatarSnapshot() {
return internalAvatar.getValue();
}
public void setGivenName(String givenName) { public void setGivenName(String givenName) {
this.givenName.setValue(givenName); this.givenName.setValue(givenName);
} }
@ -73,16 +90,18 @@ class EditProfileViewModel extends ViewModel {
static class Factory implements ViewModelProvider.Factory { static class Factory implements ViewModelProvider.Factory {
private final EditProfileRepository repository; private final EditProfileRepository repository;
private final boolean hasInstanceState;
Factory(EditProfileRepository repository) { Factory(@NonNull EditProfileRepository repository, boolean hasInstanceState) {
this.repository = repository; this.repository = repository;
this.hasInstanceState = hasInstanceState;
} }
@NonNull @NonNull
@Override @Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection unchecked //noinspection unchecked
return (T) new EditProfileViewModel(repository); return (T) new EditProfileViewModel(repository, hasInstanceState);
} }
} }
} }