From e584a90f810ddd29328da5ae6c42e0e73a09c394 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 9 Jul 2021 09:46:00 -0300 Subject: [PATCH] Fix several voice note beta bugs. * Sim label positioning * Bad player state when navigating to and from conversations * Scrolling date header placement --- .../voice/VoiceNoteMediaController.java | 18 +++++++++--------- .../components/voice/VoiceNotePlayerView.kt | 2 ++ .../conversation/ConversationActivity.java | 5 +++++ .../conversation/ConversationFragment.java | 9 ++++++--- .../conversation/ConversationViewModel.java | 19 +++++++++++++++++++ .../conversation_item_footer_incoming.xml | 5 +++-- .../res/layout/voice_note_player_view.xml | 10 ++++++++-- 7 files changed, 52 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaController.java b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaController.java index d94682e1d1..0c0ee10b24 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaController.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaController.java @@ -264,19 +264,19 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver { MediaControllerCompat.setMediaController(activity, mediaController); - mediaController.registerCallback(mediaControllerCompatCallback); + MediaMetadataCompat mediaMetadataCompat = mediaController.getMetadata(); + if (canExtractPlaybackInformationFromMetadata(mediaMetadataCompat)) { + VoiceNotePlaybackState newState = extractStateFromMetadata(mediaController, mediaMetadataCompat, null); - if (Objects.equals(voiceNotePlaybackState.getValue(), VoiceNotePlaybackState.NONE)) { - MediaMetadataCompat mediaMetadataCompat = mediaController.getMetadata(); - if (canExtractPlaybackInformationFromMetadata(mediaMetadataCompat)) { - VoiceNotePlaybackState newState = extractStateFromMetadata(mediaController, mediaMetadataCompat, null); - - if (newState != null) { - voiceNotePlaybackState.postValue(newState); - } + if (newState != null) { + voiceNotePlaybackState.postValue(newState); + } else { + voiceNotePlaybackState.postValue(VoiceNotePlaybackState.NONE); } } + mediaController.registerCallback(mediaControllerCompatCallback); + mediaControllerCompatCallback.onPlaybackStateChanged(mediaController.getPlaybackState()); } catch (RemoteException e) { Log.w(TAG, "onConnected: Failed to set media controller", e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerView.kt b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerView.kt index ed17a593e3..ec2251a26a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlayerView.kt @@ -52,6 +52,8 @@ class VoiceNotePlayerView @JvmOverloads constructor( speedView = findViewById(R.id.voice_note_player_speed) closeButton = findViewById(R.id.voice_note_player_close) + infoView.isSelected = true + val speedTouchTarget: View = findViewById(R.id.voice_note_player_speed_touch_target) speedTouchTarget.setOnClickListener { speedView.performClick() diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index cb7b996d55..d9215d81af 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -3392,6 +3392,11 @@ public class ConversationActivity extends PassphraseRequiredActivity draftViewModel.deleteVoiceNoteDraft(); } + @Override + public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() { + return voiceNoteMediaController; + } + // Listeners private final class DeleteCanceledVoiceNoteListener implements ListenableFuture.Listener { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index c81e6869e8..251c35c844 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -81,6 +81,7 @@ import org.thoughtcrime.securesms.components.TooltipPopup; import org.thoughtcrime.securesms.components.TypingStatusRepository; import org.thoughtcrime.securesms.components.recyclerview.SmoothScrollingLinearLayoutManager; import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity; +import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner; import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState; import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.contactshare.ContactUtil; @@ -334,6 +335,9 @@ public class ConversationFragment extends LoggingFragment { conversationUpdateTick = new ConversationUpdateTick(this::updateConversationItemTimestamps); getViewLifecycleOwner().getLifecycle().addObserver(conversationUpdateTick); + listener.getVoiceNoteMediaController().getVoiceNotePlayerViewState().observe(getViewLifecycleOwner(), state -> conversationViewModel.setInlinePlayerVisible(state.isPresent())); + conversationViewModel.getScrollDateTopMargin().observe(getViewLifecycleOwner(), topMargin -> ViewUtil.setTopMargin(scrollDateHeader, topMargin)); + return view; } @@ -1280,15 +1284,14 @@ public class ConversationFragment extends LoggingFragment { public void onGlobalLayout() { Rect rect = new Rect(); toolbar.getGlobalVisibleRect(rect); - ViewUtil.setTopMargin(scrollDateHeader, rect.bottom + ViewUtil.dpToPx(8)); + conversationViewModel.setToolbarBottom(rect.bottom + ViewUtil.dpToPx(8)); ViewUtil.setTopMargin(conversationBanner, rect.bottom + ViewUtil.dpToPx(16)); toolbar.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); - } - public interface ConversationFragmentListener { + public interface ConversationFragmentListener extends VoiceNoteMediaControllerOwner { void setThreadId(long threadId); void handleReplyMessage(ConversationMessage conversationMessage); void onMessageActionToolbarOpened(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java index 6bf73d360d..81063e22fe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationViewModel.java @@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.DefaultValueLiveData; import org.thoughtcrime.securesms.util.SingleLiveEvent; +import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; import org.whispersystems.libsignal.util.Pair; @@ -69,6 +70,9 @@ public class ConversationViewModel extends ViewModel { private final LiveData wallpaper; private final SingleLiveEvent events; private final LiveData chatColors; + private final MutableLiveData toolbarBottom; + private final MutableLiveData inlinePlayerHeight; + private final LiveData scrollDateTopMargin; private final Map> sessionMemberCache = new HashMap<>(); @@ -87,6 +91,9 @@ public class ConversationViewModel extends ViewModel { this.events = new SingleLiveEvent<>(); this.pagingController = new ProxyPagingController(); this.messageObserver = pagingController::onDataInvalidated; + this.toolbarBottom = new MutableLiveData<>(); + this.inlinePlayerHeight = new MutableLiveData<>(); + this.scrollDateTopMargin = Transformations.distinctUntilChanged(LiveDataUtil.combineLatest(toolbarBottom, inlinePlayerHeight, Integer::sum)); LiveData recipientLiveData = LiveDataUtil.mapAsync(recipientId, Recipient::resolved); LiveData threadAndRecipient = LiveDataUtil.combineLatest(threadId, recipientLiveData, ThreadAndRecipient::new); @@ -144,6 +151,14 @@ public class ConversationViewModel extends ViewModel { Recipient::getChatColors); } + void setToolbarBottom(int bottom) { + toolbarBottom.postValue(bottom); + } + + void setInlinePlayerVisible(boolean isVisible) { + inlinePlayerHeight.postValue(isVisible ? ViewUtil.dpToPx(36) : 0); + } + void onAttachmentKeyboardOpen() { mediaRepository.getMediaInBucket(context, Media.ALL_MEDIA_BUCKET_ID, recentMedia::postValue); } @@ -162,6 +177,10 @@ public class ConversationViewModel extends ViewModel { this.threadId.postValue(-1L); } + @NonNull LiveData getScrollDateTopMargin() { + return scrollDateTopMargin; + } + @NonNull LiveData canShowAsBubble() { return canShowAsBubble; } diff --git a/app/src/main/res/layout/conversation_item_footer_incoming.xml b/app/src/main/res/layout/conversation_item_footer_incoming.xml index 184795a9d2..3de1d63e8b 100644 --- a/app/src/main/res/layout/conversation_item_footer_incoming.xml +++ b/app/src/main/res/layout/conversation_item_footer_incoming.xml @@ -84,10 +84,11 @@ android:maxWidth="140dp" android:maxLines="1" android:visibility="gone" + app:layout_constraintStart_toEndOf="@id/date_and_expiry_wrapper" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/footer_insecure_indicator" app:layout_constraintTop_toTopOf="parent" - tools:text="to SIM1" /> + tools:text="Sim Op" /> diff --git a/app/src/main/res/layout/voice_note_player_view.xml b/app/src/main/res/layout/voice_note_player_view.xml index 845628df83..8d3da16fa4 100644 --- a/app/src/main/res/layout/voice_note_player_view.xml +++ b/app/src/main/res/layout/voice_note_player_view.xml @@ -22,15 +22,21 @@ android:id="@+id/voice_note_player_info" android:layout_width="0dp" android:layout_height="wrap_content" + android:ellipsize="marquee" android:gravity="center_vertical" + android:marqueeRepeatLimit="marquee_forever" android:minHeight="36dp" + android:paddingStart="0dp" + android:paddingEnd="13dp" + android:singleLine="true" android:textAppearance="@style/TextAppearance.Signal.Body2" android:textColor="@color/signal_icon_tint_primary" + app:layout_constrainedWidth="true" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/voice_note_player_speed" + app:layout_constraintEnd_toStartOf="@id/voice_note_player_speed_touch_target" app:layout_constraintStart_toEndOf="@id/voice_note_player_play_pause_toggle" app:layout_constraintTop_toTopOf="parent" - tools:text="Miles Morales · 5:20" /> + tools:text="Miles Morales in Some strange spider-man group · 5:20" />