kopia lustrzana https://github.com/ryukoposting/Signal-Android
Fix several conversation settings feedback issues.
* Mute icon in wrong location in RTL * No exit animation when dismissing conversation settings * Thumbnails flicker when you come back to conversation settings * Rounded corners for mute dialog don't match other dialogs * Mute button in note-to-self conversation settings * Explore adding contact details to the contact bottom sheetfork-5.53.8
rodzic
5675f080f2
commit
f2a490b07e
|
@ -7,6 +7,8 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class MuteDialog extends AlertDialog {
|
public class MuteDialog extends AlertDialog {
|
||||||
|
@ -29,7 +31,7 @@ public class MuteDialog extends AlertDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void show(final Context context, final @NonNull MuteSelectionListener listener, @Nullable Runnable cancelListener) {
|
public static void show(final Context context, final @NonNull MuteSelectionListener listener, @Nullable Runnable cancelListener) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
|
||||||
builder.setTitle(R.string.MuteDialog_mute_notifications);
|
builder.setTitle(R.string.MuteDialog_mute_notifications);
|
||||||
builder.setItems(R.array.mute_durations, new DialogInterface.OnClickListener() {
|
builder.setItems(R.array.mute_durations, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,6 +11,7 @@ import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.core.animation.addListener
|
||||||
import androidx.fragment.app.FragmentContainerView
|
import androidx.fragment.app.FragmentContainerView
|
||||||
|
|
||||||
private const val BOUNDS = "signal.wipedowntransition.bottom"
|
private const val BOUNDS = "signal.wipedowntransition.bottom"
|
||||||
|
@ -51,6 +52,12 @@ class WipeDownTransition(context: Context, attrs: AttributeSet?) : Transition(co
|
||||||
val startBottom: Rect = startValues.values[BOUNDS] as? Rect ?: Rect().apply { view.getLocalVisibleRect(this) }
|
val startBottom: Rect = startValues.values[BOUNDS] as? Rect ?: Rect().apply { view.getLocalVisibleRect(this) }
|
||||||
val endBottom: Rect = endValues.values[BOUNDS] as? Rect ?: Rect().apply { view.getLocalVisibleRect(this) }
|
val endBottom: Rect = endValues.values[BOUNDS] as? Rect ?: Rect().apply { view.getLocalVisibleRect(this) }
|
||||||
|
|
||||||
return ObjectAnimator.ofObject(view, "clipBounds", RectEvaluator(), startBottom, endBottom)
|
return ObjectAnimator.ofObject(view, "clipBounds", RectEvaluator(), startBottom, endBottom).apply {
|
||||||
|
addListener(
|
||||||
|
onEnd = {
|
||||||
|
view.clipBounds = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,8 +72,8 @@ public class FromTextView extends EmojiTextView {
|
||||||
|
|
||||||
setText(builder);
|
setText(builder);
|
||||||
|
|
||||||
if (recipient.isBlocked()) setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_block_grey600_18dp, 0, 0, 0);
|
if (recipient.isBlocked()) setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_block_grey600_18dp, 0, 0, 0);
|
||||||
else if (recipient.isMuted()) setCompoundDrawablesWithIntrinsicBounds(getMuted(), null, null, null);
|
else if (recipient.isMuted()) setCompoundDrawablesRelativeWithIntrinsicBounds(getMuted(), null, null, null);
|
||||||
else setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
else setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ConversationSettingsActivity : DSLSettingsActivity(), ConversationSettings
|
||||||
|
|
||||||
override fun finish() {
|
override fun finish() {
|
||||||
super.finish()
|
super.finish()
|
||||||
overridePendingTransition(0, R.anim.fade_out)
|
overridePendingTransition(0, R.anim.slide_fade_to_bottom)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -432,6 +432,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
||||||
customPref(
|
customPref(
|
||||||
SharedMediaPreference.Model(
|
SharedMediaPreference.Model(
|
||||||
mediaCursor = state.sharedMedia,
|
mediaCursor = state.sharedMedia,
|
||||||
|
mediaIds = state.sharedMediaIds,
|
||||||
onMediaRecordClick = { mediaRecord, isLtr ->
|
onMediaRecordClick = { mediaRecord, isLtr ->
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
MediaPreviewActivity.intentFromMediaRecord(requireContext(), mediaRecord, isLtr),
|
MediaPreviewActivity.intentFromMediaRecord(requireContext(), mediaRecord, isLtr),
|
||||||
|
|
|
@ -15,6 +15,7 @@ data class ConversationSettingsState(
|
||||||
val disappearingMessagesLifespan: Int = 0,
|
val disappearingMessagesLifespan: Int = 0,
|
||||||
val canModifyBlockedState: Boolean = false,
|
val canModifyBlockedState: Boolean = false,
|
||||||
val sharedMedia: Cursor? = null,
|
val sharedMedia: Cursor? = null,
|
||||||
|
val sharedMediaIds: List<Long> = listOf(),
|
||||||
private val sharedMediaLoaded: Boolean = false,
|
private val sharedMediaLoaded: Boolean = false,
|
||||||
private val specificSettingsState: SpecificSettingsState,
|
private val specificSettingsState: SpecificSettingsState,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -10,12 +10,14 @@ import org.signal.core.util.ThreadUtil
|
||||||
import org.signal.core.util.concurrent.SignalExecutors
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
|
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
|
||||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference
|
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference
|
||||||
|
import org.thoughtcrime.securesms.database.AttachmentDatabase
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
import org.thoughtcrime.securesms.groups.LiveGroup
|
import org.thoughtcrime.securesms.groups.LiveGroup
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil
|
import org.thoughtcrime.securesms.recipients.RecipientUtil
|
||||||
|
import org.thoughtcrime.securesms.util.CursorUtil
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||||
import org.thoughtcrime.securesms.util.SingleLiveEvent
|
import org.thoughtcrime.securesms.util.SingleLiveEvent
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
||||||
|
@ -58,7 +60,19 @@ sealed class ConversationSettingsViewModel(
|
||||||
openedMediaCursors.add(cursor.get())
|
openedMediaCursors.add(cursor.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
state.copy(sharedMedia = cursor.orNull(), sharedMediaLoaded = true)
|
val ids: List<Long> = cursor.transform<List<Long>> {
|
||||||
|
val result = mutableListOf<Long>()
|
||||||
|
while (it.moveToNext()) {
|
||||||
|
result.add(CursorUtil.requireLong(it, AttachmentDatabase.ROW_ID))
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}.or(listOf())
|
||||||
|
|
||||||
|
state.copy(
|
||||||
|
sharedMedia = cursor.orNull(),
|
||||||
|
sharedMediaIds = ids,
|
||||||
|
sharedMediaLoaded = true
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
cursor.orNull().ensureClosed()
|
cursor.orNull().ensureClosed()
|
||||||
state.copy(sharedMedia = null)
|
state.copy(sharedMedia = null)
|
||||||
|
@ -125,7 +139,7 @@ sealed class ConversationSettingsViewModel(
|
||||||
isAudioAvailable = !recipient.isGroup && !recipient.isSelf,
|
isAudioAvailable = !recipient.isGroup && !recipient.isSelf,
|
||||||
isAudioSecure = recipient.registered == RecipientDatabase.RegisteredState.REGISTERED,
|
isAudioSecure = recipient.registered == RecipientDatabase.RegisteredState.REGISTERED,
|
||||||
isMuted = recipient.isMuted,
|
isMuted = recipient.isMuted,
|
||||||
isMuteAvailable = true,
|
isMuteAvailable = !recipient.isSelf,
|
||||||
isSearchAvailable = true
|
isSearchAvailable = true
|
||||||
),
|
),
|
||||||
disappearingMessagesLifespan = recipient.expireMessages,
|
disappearingMessagesLifespan = recipient.expireMessages,
|
||||||
|
|
|
@ -22,10 +22,16 @@ object SharedMediaPreference {
|
||||||
|
|
||||||
class Model(
|
class Model(
|
||||||
val mediaCursor: Cursor,
|
val mediaCursor: Cursor,
|
||||||
|
val mediaIds: List<Long>,
|
||||||
val onMediaRecordClick: (MediaDatabase.MediaRecord, Boolean) -> Unit
|
val onMediaRecordClick: (MediaDatabase.MediaRecord, Boolean) -> Unit
|
||||||
) : PreferenceModel<Model>() {
|
) : PreferenceModel<Model>() {
|
||||||
override fun areItemsTheSame(newItem: Model): Boolean {
|
override fun areItemsTheSame(newItem: Model): Boolean {
|
||||||
return newItem.mediaCursor == mediaCursor
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(newItem: Model): Boolean {
|
||||||
|
return super.areContentsTheSame(newItem) &&
|
||||||
|
mediaIds == newItem.mediaIds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ import kotlin.Unit;
|
||||||
*/
|
*/
|
||||||
public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
||||||
|
|
||||||
public static final int REQUEST_CODE_ADD_CONTACT = 1111;
|
public static final int REQUEST_CODE_SYSTEM_CONTACT_SHEET = 1111;
|
||||||
|
|
||||||
private static final String ARGS_RECIPIENT_ID = "RECIPIENT_ID";
|
private static final String ARGS_RECIPIENT_ID = "RECIPIENT_ID";
|
||||||
private static final String ARGS_GROUP_ID = "GROUP_ID";
|
private static final String ARGS_GROUP_ID = "GROUP_ID";
|
||||||
|
@ -65,6 +65,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
private Button blockButton;
|
private Button blockButton;
|
||||||
private Button unblockButton;
|
private Button unblockButton;
|
||||||
private Button addContactButton;
|
private Button addContactButton;
|
||||||
|
private Button contactDetailsButton;
|
||||||
private Button addToGroupButton;
|
private Button addToGroupButton;
|
||||||
private Button viewSafetyNumberButton;
|
private Button viewSafetyNumberButton;
|
||||||
private Button makeGroupAdminButton;
|
private Button makeGroupAdminButton;
|
||||||
|
@ -73,6 +74,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
private ProgressBar adminActionBusy;
|
private ProgressBar adminActionBusy;
|
||||||
private View noteToSelfDescription;
|
private View noteToSelfDescription;
|
||||||
private View buttonStrip;
|
private View buttonStrip;
|
||||||
|
private View interactionsContainer;
|
||||||
|
|
||||||
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
|
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
|
||||||
@Nullable GroupId groupId)
|
@Nullable GroupId groupId)
|
||||||
|
@ -110,6 +112,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
blockButton = view.findViewById(R.id.rbs_block_button);
|
blockButton = view.findViewById(R.id.rbs_block_button);
|
||||||
unblockButton = view.findViewById(R.id.rbs_unblock_button);
|
unblockButton = view.findViewById(R.id.rbs_unblock_button);
|
||||||
addContactButton = view.findViewById(R.id.rbs_add_contact_button);
|
addContactButton = view.findViewById(R.id.rbs_add_contact_button);
|
||||||
|
contactDetailsButton = view.findViewById(R.id.rbs_contact_details_button);
|
||||||
addToGroupButton = view.findViewById(R.id.rbs_add_to_group_button);
|
addToGroupButton = view.findViewById(R.id.rbs_add_to_group_button);
|
||||||
viewSafetyNumberButton = view.findViewById(R.id.rbs_view_safety_number_button);
|
viewSafetyNumberButton = view.findViewById(R.id.rbs_view_safety_number_button);
|
||||||
makeGroupAdminButton = view.findViewById(R.id.rbs_make_group_admin_button);
|
makeGroupAdminButton = view.findViewById(R.id.rbs_make_group_admin_button);
|
||||||
|
@ -118,6 +121,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
adminActionBusy = view.findViewById(R.id.rbs_admin_action_busy);
|
adminActionBusy = view.findViewById(R.id.rbs_admin_action_busy);
|
||||||
noteToSelfDescription = view.findViewById(R.id.rbs_note_to_self_description);
|
noteToSelfDescription = view.findViewById(R.id.rbs_note_to_self_description);
|
||||||
buttonStrip = view.findViewById(R.id.button_strip);
|
buttonStrip = view.findViewById(R.id.button_strip);
|
||||||
|
interactionsContainer = view.findViewById(R.id.interactions_container);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +139,8 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
viewModel = ViewModelProviders.of(this, factory).get(RecipientDialogViewModel.class);
|
viewModel = ViewModelProviders.of(this, factory).get(RecipientDialogViewModel.class);
|
||||||
|
|
||||||
viewModel.getRecipient().observe(getViewLifecycleOwner(), recipient -> {
|
viewModel.getRecipient().observe(getViewLifecycleOwner(), recipient -> {
|
||||||
|
interactionsContainer.setVisibility(recipient.isSelf() ? View.GONE : View.VISIBLE);
|
||||||
|
|
||||||
avatar.setFallbackPhotoProvider(new Recipient.FallbackPhotoProvider() {
|
avatar.setFallbackPhotoProvider(new Recipient.FallbackPhotoProvider() {
|
||||||
@Override
|
@Override
|
||||||
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
||||||
|
@ -232,9 +238,18 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
} else {
|
} else {
|
||||||
addContactButton.setVisibility(View.VISIBLE);
|
addContactButton.setVisibility(View.VISIBLE);
|
||||||
addContactButton.setOnClickListener(v -> {
|
addContactButton.setOnClickListener(v -> {
|
||||||
startActivityForResult(RecipientExporter.export(recipient).asAddContactIntent(), REQUEST_CODE_ADD_CONTACT);
|
startActivityForResult(RecipientExporter.export(recipient).asAddContactIntent(), REQUEST_CODE_SYSTEM_CONTACT_SHEET);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (recipient.isSystemContact() && !recipient.isGroup() && !recipient.isSelf()) {
|
||||||
|
contactDetailsButton.setVisibility(View.VISIBLE);
|
||||||
|
contactDetailsButton.setOnClickListener(v -> {
|
||||||
|
startActivityForResult(new Intent(Intent.ACTION_VIEW, recipient.getContactUri()), REQUEST_CODE_SYSTEM_CONTACT_SHEET);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
contactDetailsButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
viewModel.getCanAddToAGroup().observe(getViewLifecycleOwner(), canAdd -> {
|
viewModel.getCanAddToAGroup().observe(getViewLifecycleOwner(), canAdd -> {
|
||||||
|
@ -288,8 +303,8 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_ADD_CONTACT) {
|
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_SYSTEM_CONTACT_SHEET) {
|
||||||
viewModel.onAddedToContacts();
|
viewModel.refreshRecipient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ final class RecipientDialogViewModel extends ViewModel {
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAddedToContacts() {
|
void refreshRecipient() {
|
||||||
recipientDialogRepository.refreshRecipient();
|
recipientDialogRepository.refreshRecipient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
android:textAppearance="@style/Signal.Text.Body"
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
android:textColor="@color/signal_text_primary"
|
android:textColor="@color/signal_text_primary"
|
||||||
app:drawableStartCompat="@drawable/ic_photo_album_24"
|
app:drawableStartCompat="@drawable/ic_photo_album_24"
|
||||||
|
app:drawableTint="@color/signal_icon_tint_primary"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
|
@ -96,6 +96,7 @@
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:id="@+id/interactions_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
@ -192,6 +193,18 @@
|
||||||
app:drawableStartCompat="@drawable/ic_plus_24"
|
app:drawableStartCompat="@drawable/ic_plus_24"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/rbs_contact_details_button"
|
||||||
|
style="@style/Widget.Signal.Button.TextButton.Drawable"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
android:text="@string/ConversationSettingsFragment__contact_details"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableStartCompat="@drawable/ic_profile_circle_24"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/rbs_view_safety_number_button"
|
android:id="@+id/rbs_view_safety_number_button"
|
||||||
style="@style/Widget.Signal.Button.TextButton.Drawable"
|
style="@style/Widget.Signal.Button.TextButton.Drawable"
|
||||||
|
|
|
@ -65,5 +65,6 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Signal.ConversationSettings.WindowAnimation" parent="android:style/Animation" >
|
<style name="Signal.ConversationSettings.WindowAnimation" parent="android:style/Animation" >
|
||||||
|
<item name="android:windowExitAnimation">@anim/slide_fade_to_bottom</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Ładowanie…
Reference in New Issue