diff --git a/app/src/main/java/org/thoughtcrime/securesms/animation/transitions/FabElevationFadeTransform.kt b/app/src/main/java/org/thoughtcrime/securesms/animation/transitions/FabElevationFadeTransform.kt new file mode 100644 index 0000000000..f5be57cd13 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/animation/transitions/FabElevationFadeTransform.kt @@ -0,0 +1,53 @@ +package org.thoughtcrime.securesms.animation.transitions + +import android.animation.Animator +import android.animation.ValueAnimator +import android.content.Context +import android.transition.Transition +import android.transition.TransitionValues +import android.util.AttributeSet +import android.view.ViewGroup +import androidx.annotation.RequiresApi +import com.google.android.material.floatingactionbutton.FloatingActionButton + +@RequiresApi(21) +class FabElevationFadeTransform(context: Context, attrs: AttributeSet?) : Transition(context, attrs) { + + companion object { + private const val ELEVATION = "CrossfaderTransition.ELEVATION" + } + + override fun captureStartValues(transitionValues: TransitionValues) { + if (transitionValues.view is FloatingActionButton) { + transitionValues.values[ELEVATION] = transitionValues.view.elevation + } + } + + override fun captureEndValues(transitionValues: TransitionValues) { + if (transitionValues.view is FloatingActionButton) { + transitionValues.values[ELEVATION] = transitionValues.view.elevation + } + } + + override fun createAnimator(sceneRoot: ViewGroup?, startValues: TransitionValues?, endValues: TransitionValues?): Animator? { + if (startValues?.view !is FloatingActionButton || endValues?.view !is FloatingActionButton) { + return null + } + + val startElevation = startValues.view.elevation + val endElevation = endValues.view.elevation + if (startElevation == endElevation) { + return null + } + + return ValueAnimator.ofFloat( + startValues.values[ELEVATION] as Float, + endValues.values[ELEVATION] as Float + ).apply { + addUpdateListener { + val elevation = it.animatedValue as Float + endValues.view.elevation = elevation + } + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListArchiveFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListArchiveFragment.java index bca33195a7..1bf4337e28 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListArchiveFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListArchiveFragment.java @@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.util.ConversationUtil; +import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask; import org.thoughtcrime.securesms.util.views.Stub; @@ -70,10 +71,16 @@ public class ConversationListArchiveFragment extends ConversationListFragment im coordinator = view.findViewById(R.id.coordinator); list = view.findViewById(R.id.list); - fab = view.findViewById(R.id.fab); - cameraFab = view.findViewById(R.id.camera_fab); emptyState = new Stub<>(view.findViewById(R.id.empty_state)); + if (FeatureFlags.internalUser()) { + fab = view.findViewById(R.id.fab_new); + cameraFab = view.findViewById(R.id.camera_fab_new); + } else { + fab = view.findViewById(R.id.fab_old); + cameraFab = view.findViewById(R.id.camera_fab_old); + } + toolbar.get().setNavigationOnClickListener(v -> NavHostFragment.findNavController(this).popBackStack()); toolbar.get().setTitle(R.string.AndroidManifest_archived_conversations); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java index 7d3d087fd0..1b080d5ef8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -141,6 +141,7 @@ import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.AppStartup; import org.thoughtcrime.securesms.util.BottomSheetUtil; import org.thoughtcrime.securesms.util.ConversationUtil; +import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.PlayStoreUtil; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.SignalLocalMetrics; @@ -247,8 +248,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { coordinator = view.findViewById(R.id.coordinator); list = view.findViewById(R.id.list); - fab = view.findViewById(R.id.fab); - cameraFab = view.findViewById(R.id.camera_fab); searchEmptyState = view.findViewById(R.id.search_no_results); toolbarShadow = view.findViewById(R.id.conversation_list_toolbar_shadow); bottomActionBar = view.findViewById(R.id.conversation_list_bottom_action_bar); @@ -258,6 +257,17 @@ public class ConversationListFragment extends MainFragment implements ActionMode paymentNotificationView = new Stub<>(view.findViewById(R.id.payments_notification)); voiceNotePlayerViewStub = new Stub<>(view.findViewById(R.id.voice_note_player)); + if (FeatureFlags.internalUser()) { + fab = view.findViewById(R.id.fab_new); + cameraFab = view.findViewById(R.id.camera_fab_new); + + fab.setVisibility(View.VISIBLE); + cameraFab.setVisibility(View.VISIBLE); + } else { + fab = view.findViewById(R.id.fab_old); + cameraFab = view.findViewById(R.id.camera_fab_old); + } + Toolbar toolbar = getToolbar(view); toolbar.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt index e2ff1ac859..ac6b0a61a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/main/MainActivityListHostFragment.kt @@ -110,7 +110,10 @@ class MainActivityListHostFragment : Fragment(R.layout.main_activity_list_host_f R.id.action_conversationListFragment_to_storiesLandingFragment, null, null, - FragmentNavigatorExtras(requireView().findViewById(R.id.camera_fab) to "camera_fab") + FragmentNavigatorExtras( + requireView().findViewById(R.id.camera_fab_new) to "camera_fab", + requireView().findViewById(R.id.fab_new) to "new_convo_fab" + ) ) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt index d5eabbd435..c219f55fec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt @@ -13,11 +13,15 @@ import android.view.View import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.core.app.ActivityOptionsCompat +import androidx.core.app.SharedElementCallback import androidx.core.view.ViewCompat import androidx.fragment.app.viewModels import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar +import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.kotlin.subscribeBy import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.settings.DSLConfiguration import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter @@ -39,6 +43,7 @@ import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity import org.thoughtcrime.securesms.util.LifecycleDisposable import org.thoughtcrime.securesms.util.visible +import java.util.concurrent.TimeUnit /** * The "landing page" for Stories. @@ -46,7 +51,7 @@ import org.thoughtcrime.securesms.util.visible class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_landing_fragment) { private lateinit var emptyNotice: View - private lateinit var cameraFab: View + private lateinit var cameraFab: FloatingActionButton private val lifecycleDisposable = LifecycleDisposable() @@ -86,7 +91,16 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l emptyNotice = requireView().findViewById(R.id.empty_notice) cameraFab = requireView().findViewById(R.id.camera_fab) - sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(R.transition.change_transform) + sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(R.transition.change_transform_fabs) + setEnterSharedElementCallback(object : SharedElementCallback() { + override fun onSharedElementStart(sharedElementNames: MutableList?, sharedElements: MutableList?, sharedElementSnapshots: MutableList?) { + if (sharedElementNames?.contains("camera_fab") == true) { + lifecycleDisposable += Single.timer(200, TimeUnit.MILLISECONDS).subscribeBy { + cameraFab.setImageResource(R.drawable.ic_camera_outline_24) + } + } + } + }) cameraFab.setOnClickListener { Permissions.with(this) diff --git a/app/src/main/res/anim-v21/camera_fab_cubic_easing_interpolator.xml b/app/src/main/res/anim-v21/camera_fab_cubic_easing_interpolator.xml new file mode 100644 index 0000000000..870b232171 --- /dev/null +++ b/app/src/main/res/anim-v21/camera_fab_cubic_easing_interpolator.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/app/src/main/res/anim/camera_fab_cubic_easing_interpolator.xml b/app/src/main/res/anim/camera_fab_cubic_easing_interpolator.xml new file mode 100644 index 0000000000..dc1428476c --- /dev/null +++ b/app/src/main/res/anim/camera_fab_cubic_easing_interpolator.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/conversation_list_fragment.xml b/app/src/main/res/layout/conversation_list_fragment.xml index 0223da5cd1..e9f7c38cbf 100644 --- a/app/src/main/res/layout/conversation_list_fragment.xml +++ b/app/src/main/res/layout/conversation_list_fragment.xml @@ -110,8 +110,7 @@ app:layout_behavior="org.thoughtcrime.securesms.util.views.SlideUpWithSnackbarBehavior"> + android:theme="@style/Widget.Material3.FloatingActionButton.Secondary" + android:transitionName="camera_fab" + android:visibility="gone" + app:backgroundTint="@color/signal_colorSecondaryContainer" + app:srcCompat="@drawable/ic_camera_outline_24" + app:tint="@color/signal_colorOnSecondaryContainer" + tools:visibility="visible" /> + + + + + app:srcCompat="@drawable/ic_compose_solid_24" + app:tint="@color/core_white" /> + + + + + + + + \ No newline at end of file