mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 08:39:22 +01:00
Made setting profile name and About synchronous operations.
This commit is contained in:
@@ -9,30 +9,30 @@ import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.dd.CircularProgressButton;
|
||||
|
||||
import org.signal.core.util.BreakIteratorCompat;
|
||||
import org.signal.core.util.EditTextUtil;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.ProfileUploadJob;
|
||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.StringUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.adapter.AlwaysChangedDiffUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
||||
@@ -60,9 +60,11 @@ public class EditAboutFragment extends Fragment implements ManageProfileActivity
|
||||
new AboutPreset("\uD83D\uDE80", R.string.EditAboutFragment_working_on_something_new)
|
||||
);
|
||||
|
||||
private ImageView emojiView;
|
||||
private EditText bodyView;
|
||||
private TextView countView;
|
||||
private ImageView emojiView;
|
||||
private EditText bodyView;
|
||||
private TextView countView;
|
||||
private CircularProgressButton saveButton;
|
||||
private EditAboutViewModel viewModel;
|
||||
|
||||
private String selectedEmoji;
|
||||
|
||||
@@ -76,6 +78,9 @@ public class EditAboutFragment extends Fragment implements ManageProfileActivity
|
||||
this.emojiView = view.findViewById(R.id.edit_about_emoji);
|
||||
this.bodyView = view.findViewById(R.id.edit_about_body);
|
||||
this.countView = view.findViewById(R.id.edit_about_count);
|
||||
this.saveButton = view.findViewById(R.id.edit_about_save);
|
||||
|
||||
initializeViewModel();
|
||||
|
||||
view.<Toolbar>findViewById(R.id.toolbar)
|
||||
.setNavigationOnClickListener(v -> Navigation.findNavController(view)
|
||||
@@ -92,9 +97,13 @@ public class EditAboutFragment extends Fragment implements ManageProfileActivity
|
||||
.show(requireFragmentManager(), "BOTTOM");
|
||||
});
|
||||
|
||||
view.findViewById(R.id.edit_about_save).setOnClickListener(this::onSaveClicked);
|
||||
view.findViewById(R.id.edit_about_clear).setOnClickListener(v -> onClearClicked());
|
||||
|
||||
saveButton.setOnClickListener(v -> viewModel.onSaveClicked(requireContext(),
|
||||
bodyView.getText().toString(),
|
||||
selectedEmoji));
|
||||
|
||||
|
||||
RecyclerView presetList = view.findViewById(R.id.edit_about_presets);
|
||||
PresetAdapter presetAdapter = new PresetAdapter();
|
||||
|
||||
@@ -135,6 +144,13 @@ public class EditAboutFragment extends Fragment implements ManageProfileActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeViewModel() {
|
||||
this.viewModel = ViewModelProviders.of(this).get(EditAboutViewModel.class);
|
||||
|
||||
viewModel.getSaveState().observe(getViewLifecycleOwner(), this::presentSaveState);
|
||||
viewModel.getEvents().observe(getViewLifecycleOwner(), this::presentEvent);
|
||||
}
|
||||
|
||||
private void presentCount(@NonNull String aboutBody) {
|
||||
BreakIteratorCompat breakIterator = BreakIteratorCompat.getInstance();
|
||||
breakIterator.setText(aboutBody);
|
||||
@@ -148,14 +164,26 @@ public class EditAboutFragment extends Fragment implements ManageProfileActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void onSaveClicked(View view) {
|
||||
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
|
||||
DatabaseFactory.getRecipientDatabase(requireContext()).setAbout(Recipient.self().getId(), bodyView.getText().toString(), selectedEmoji);
|
||||
ApplicationDependencies.getJobManager().add(new ProfileUploadJob());
|
||||
return null;
|
||||
}, (nothing) -> {
|
||||
Navigation.findNavController(view).popBackStack();
|
||||
});
|
||||
private void presentSaveState(@NonNull EditAboutViewModel.SaveState state) {
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
saveButton.setIndeterminateProgressMode(false);
|
||||
saveButton.setProgress(0);
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
saveButton.setIndeterminateProgressMode(true);
|
||||
saveButton.setProgress(50);
|
||||
break;
|
||||
case DONE:
|
||||
Navigation.findNavController(requireView()).popBackStack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void presentEvent(@NonNull EditAboutViewModel.Event event) {
|
||||
if (event == EditAboutViewModel.Event.NETWORK_FAILURE) {
|
||||
Toast.makeText(requireContext(), R.string.EditProfileNameFragment_failed_to_save_due_to_network_issues_try_again_later, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void onClearClicked() {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.thoughtcrime.securesms.profiles.manage;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||
|
||||
public final class EditAboutViewModel extends ViewModel {
|
||||
|
||||
private final ManageProfileRepository repository;
|
||||
private final MutableLiveData<SaveState> saveState;
|
||||
private final SingleLiveEvent<Event> events;
|
||||
|
||||
public EditAboutViewModel() {
|
||||
this.repository = new ManageProfileRepository();
|
||||
this.saveState = new MutableLiveData<>(SaveState.IDLE);
|
||||
this.events = new SingleLiveEvent<>();
|
||||
}
|
||||
|
||||
@NonNull LiveData<SaveState> getSaveState() {
|
||||
return saveState;
|
||||
}
|
||||
|
||||
@NonNull LiveData<Event> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
void onSaveClicked(@NonNull Context context, @NonNull String about, @NonNull String emoji) {
|
||||
saveState.setValue(SaveState.IN_PROGRESS);
|
||||
repository.setAbout(context, about, emoji, result -> {
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
saveState.postValue(SaveState.DONE);
|
||||
break;
|
||||
case FAILURE_NETWORK:
|
||||
saveState.postValue(SaveState.IDLE);
|
||||
events.postValue(Event.NETWORK_FAILURE);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
enum SaveState {
|
||||
IDLE, IN_PROGRESS, DONE
|
||||
}
|
||||
|
||||
enum Event {
|
||||
NETWORK_FAILURE
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,17 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import com.dd.CircularProgressButton;
|
||||
|
||||
import org.signal.core.util.EditTextUtil;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
@@ -31,8 +35,10 @@ public class EditProfileNameFragment extends Fragment {
|
||||
|
||||
public static final int NAME_MAX_GLYPHS = 26;
|
||||
|
||||
private EditText givenName;
|
||||
private EditText familyName;
|
||||
private EditText givenName;
|
||||
private EditText familyName;
|
||||
private CircularProgressButton saveButton;
|
||||
private EditProfileNameViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
@@ -43,6 +49,9 @@ public class EditProfileNameFragment extends Fragment {
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
this.givenName = view.findViewById(R.id.edit_profile_name_given_name);
|
||||
this.familyName = view.findViewById(R.id.edit_profile_name_family_name);
|
||||
this.saveButton = view.findViewById(R.id.edit_profile_name_save);
|
||||
|
||||
initializeViewModel();
|
||||
|
||||
this.givenName.setText(Recipient.self().getProfileName().getGivenName());
|
||||
this.familyName.setText(Recipient.self().getProfileName().getFamilyName());
|
||||
@@ -57,19 +66,38 @@ public class EditProfileNameFragment extends Fragment {
|
||||
this.givenName.addTextChangedListener(new AfterTextChanged(EditProfileNameFragment::trimFieldToMaxByteLength));
|
||||
this.familyName.addTextChangedListener(new AfterTextChanged(EditProfileNameFragment::trimFieldToMaxByteLength));
|
||||
|
||||
view.findViewById(R.id.edit_profile_name_save).setOnClickListener(this::onSaveClicked);
|
||||
saveButton.setOnClickListener(v -> viewModel.onSaveClicked(requireContext(),
|
||||
givenName.getText().toString(),
|
||||
familyName.getText().toString()));
|
||||
}
|
||||
|
||||
private void onSaveClicked(View view) {
|
||||
ProfileName profileName = ProfileName.fromParts(givenName.getText().toString(), familyName.getText().toString());
|
||||
private void initializeViewModel() {
|
||||
this.viewModel = ViewModelProviders.of(this).get(EditProfileNameViewModel.class);
|
||||
|
||||
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
|
||||
DatabaseFactory.getRecipientDatabase(requireContext()).setProfileName(Recipient.self().getId(), profileName);
|
||||
ApplicationDependencies.getJobManager().add(new ProfileUploadJob());
|
||||
return null;
|
||||
}, (nothing) -> {
|
||||
Navigation.findNavController(view).popBackStack();
|
||||
});
|
||||
viewModel.getSaveState().observe(getViewLifecycleOwner(), this::presentSaveState);
|
||||
viewModel.getEvents().observe(getViewLifecycleOwner(), this::presentEvent);
|
||||
}
|
||||
|
||||
private void presentSaveState(@NonNull EditProfileNameViewModel.SaveState state) {
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
saveButton.setIndeterminateProgressMode(false);
|
||||
saveButton.setProgress(0);
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
saveButton.setIndeterminateProgressMode(true);
|
||||
saveButton.setProgress(50);
|
||||
break;
|
||||
case DONE:
|
||||
Navigation.findNavController(requireView()).popBackStack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void presentEvent(@NonNull EditProfileNameViewModel.Event event) {
|
||||
if (event == EditProfileNameViewModel.Event.NETWORK_FAILURE) {
|
||||
Toast.makeText(requireContext(), R.string.EditProfileNameFragment_failed_to_save_due_to_network_issues_try_again_later, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static void trimFieldToMaxByteLength(Editable s) {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.thoughtcrime.securesms.profiles.manage;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||
|
||||
public final class EditProfileNameViewModel extends ViewModel {
|
||||
|
||||
private final ManageProfileRepository repository;
|
||||
private final MutableLiveData<SaveState> saveState;
|
||||
private final SingleLiveEvent<Event> events;
|
||||
|
||||
public EditProfileNameViewModel() {
|
||||
this.repository = new ManageProfileRepository();
|
||||
this.saveState = new MutableLiveData<>(SaveState.IDLE);
|
||||
this.events = new SingleLiveEvent<>();
|
||||
}
|
||||
|
||||
@NonNull LiveData<SaveState> getSaveState() {
|
||||
return saveState;
|
||||
}
|
||||
|
||||
@NonNull LiveData<Event> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
void onSaveClicked(@NonNull Context context, @NonNull String givenName, @NonNull String familyName) {
|
||||
saveState.setValue(SaveState.IN_PROGRESS);
|
||||
repository.setName(context, ProfileName.fromParts(givenName, familyName), result -> {
|
||||
switch (result) {
|
||||
case SUCCESS:
|
||||
saveState.postValue(SaveState.DONE);
|
||||
break;
|
||||
case FAILURE_NETWORK:
|
||||
saveState.postValue(SaveState.IDLE);
|
||||
events.postValue(Event.NETWORK_FAILURE);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
enum SaveState {
|
||||
IDLE, IN_PROGRESS, DONE
|
||||
}
|
||||
|
||||
enum Event {
|
||||
NETWORK_FAILURE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.thoughtcrime.securesms.profiles.manage;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ProfileUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
final class ManageProfileRepository {
|
||||
|
||||
private static final String TAG = Log.tag(ManageProfileRepository.class);
|
||||
|
||||
public void setName(@NonNull Context context, @NonNull ProfileName profileName, @NonNull Consumer<Result> callback) {
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
ProfileUtil.uploadProfileWithName(context, profileName);
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileName(Recipient.self().getId(), profileName);
|
||||
callback.accept(Result.SUCCESS);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to upload profile during name change.", e);
|
||||
callback.accept(Result.FAILURE_NETWORK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setAbout(@NonNull Context context, @NonNull String about, @NonNull String emoji, @NonNull Consumer<Result> callback) {
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
try {
|
||||
ProfileUtil.uploadProfileWithAbout(context, about, emoji);
|
||||
DatabaseFactory.getRecipientDatabase(context).setAbout(Recipient.self().getId(), about, emoji);
|
||||
callback.accept(Result.SUCCESS);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Failed to upload profile during name change.", e);
|
||||
callback.accept(Result.FAILURE_NETWORK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
enum Result {
|
||||
SUCCESS, FAILURE_NETWORK
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user