kopia lustrzana https://github.com/ryukoposting/Signal-Android
				
				
				
			Add shared element transition for camera fab.
							rodzic
							
								
									33b88796e8
								
							
						
					
					
						commit
						7f2f5a182f
					
				|  | @ -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 | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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<View>(R.id.camera_fab) to "camera_fab") | ||||
|         FragmentNavigatorExtras( | ||||
|           requireView().findViewById<View>(R.id.camera_fab_new) to "camera_fab", | ||||
|           requireView().findViewById<View>(R.id.fab_new) to "new_convo_fab" | ||||
|         ) | ||||
|       ) | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -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<String>?, sharedElements: MutableList<View>?, sharedElementSnapshots: MutableList<View>?) { | ||||
|         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) | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:controlX1="0.4" | ||||
|     android:controlX2="0.0" | ||||
|     android:controlY1="0.2" | ||||
|     android:controlY2="1" /> | ||||
|  | @ -0,0 +1,2 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <accelerateDecelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android" /> | ||||
|  | @ -110,8 +110,7 @@ | |||
|             app:layout_behavior="org.thoughtcrime.securesms.util.views.SlideUpWithSnackbarBehavior"> | ||||
| 
 | ||||
|             <org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton | ||||
|                 android:transitionName="camera_fab" | ||||
|                 android:id="@+id/camera_fab" | ||||
|                 android:id="@+id/camera_fab_new" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginTop="8dp" | ||||
|  | @ -119,21 +118,56 @@ | |||
|                 android:layout_marginBottom="20dp" | ||||
|                 android:contentDescription="@string/conversation_list_fragment__open_camera_description" | ||||
|                 android:focusable="true" | ||||
|                 app:tint="@color/signal_icon_tint_secondary" | ||||
|                 app:backgroundTint="@color/conversation_list_camera_button_background" | ||||
|                 app:srcCompat="@drawable/ic_camera_solid_white_24" /> | ||||
|                 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" /> | ||||
| 
 | ||||
|             <org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton | ||||
|                 android:id="@+id/fab" | ||||
|                 android:id="@+id/fab_new" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginEnd="16dp" | ||||
|                 android:layout_marginBottom="16dp" | ||||
|                 android:contentDescription="@string/conversation_list_fragment__fab_content_description" | ||||
|                 android:focusable="true" | ||||
|                 app:tint="@color/core_white" | ||||
|                 android:theme="@style/Widget.Material3.FloatingActionButton.Secondary" | ||||
|                 android:visibility="gone" | ||||
|                 android:transitionName="new_convo_fab" | ||||
|                 app:backgroundTint="@color/signal_colorPrimaryContainer" | ||||
|                 app:srcCompat="@drawable/ic_compose_outline_24" | ||||
|                 app:tint="@color/signal_colorOnPrimaryContainer" | ||||
|                 tools:visibility="visible" /> | ||||
| 
 | ||||
|             <org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton | ||||
|                 android:id="@+id/camera_fab_old" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginTop="8dp" | ||||
|                 android:layout_marginEnd="16dp" | ||||
|                 android:layout_marginBottom="20dp" | ||||
|                 android:contentDescription="@string/conversation_list_fragment__open_camera_description" | ||||
|                 android:focusable="true" | ||||
|                 android:visibility="gone" | ||||
|                 app:backgroundTint="@color/conversation_list_camera_button_background" | ||||
|                 app:srcCompat="@drawable/ic_camera_solid_white_24" | ||||
|                 app:tint="@color/signal_icon_tint_secondary" /> | ||||
| 
 | ||||
|             <org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton | ||||
|                 android:id="@+id/fab_old" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginEnd="16dp" | ||||
|                 android:layout_marginBottom="16dp" | ||||
|                 android:contentDescription="@string/conversation_list_fragment__fab_content_description" | ||||
|                 android:focusable="true" | ||||
|                 android:visibility="gone" | ||||
|                 app:backgroundTint="@color/core_ultramarine" | ||||
|                 app:srcCompat="@drawable/ic_compose_solid_24" /> | ||||
|                 app:srcCompat="@drawable/ic_compose_solid_24" | ||||
|                 app:tint="@color/core_white" /> | ||||
| 
 | ||||
|             <ViewStub | ||||
|                 android:id="@+id/megaphone_container" | ||||
|  |  | |||
|  | @ -24,21 +24,38 @@ | |||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|     <org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton | ||||
|         android:id="@+id/camera_fab_shared_element_target" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="8dp" | ||||
|         android:layout_marginEnd="16dp" | ||||
|         android:layout_marginBottom="16dp" | ||||
|         android:focusable="true" | ||||
|         android:theme="@style/Widget.Material3.FloatingActionButton.Secondary" | ||||
|         android:transitionName="camera_fab" | ||||
|         app:elevation="0dp" | ||||
|         app:backgroundTint="@color/signal_colorSecondaryContainer" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:srcCompat="@drawable/ic_camera_outline_24" | ||||
|         app:tint="@color/signal_colorOnSecondaryContainer" /> | ||||
| 
 | ||||
|     <org.thoughtcrime.securesms.components.registration.PulsingFloatingActionButton | ||||
|         android:id="@+id/camera_fab" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="8dp" | ||||
|         android:layout_marginEnd="16dp" | ||||
|         android:layout_marginBottom="20dp" | ||||
|         android:layout_marginBottom="16dp" | ||||
|         android:contentDescription="@string/conversation_list_fragment__open_camera_description" | ||||
|         android:focusable="true" | ||||
|         android:theme="@style/Widget.Material3.FloatingActionButton.Secondary" | ||||
|         android:transitionName="camera_fab" | ||||
|         android:theme="@style/Widget.Material3.FloatingActionButton.Primary" | ||||
|         android:transitionName="new_convo_fab" | ||||
|         app:backgroundTint="@color/signal_colorPrimaryContainer" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:srcCompat="@drawable/ic_camera_outline_24" | ||||
|         app:srcCompat="@drawable/ic_compose_outline_24" | ||||
|         app:tint="@color/signal_colorOnPrimaryContainer" /> | ||||
| 
 | ||||
|     <TextView | ||||
|  |  | |||
|  | @ -0,0 +1,9 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <transitionSet android:duration="200" | ||||
|     android:interpolator="@anim/camera_fab_cubic_easing_interpolator" | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <transition class="org.thoughtcrime.securesms.animation.transitions.FabElevationFadeTransform" /> | ||||
|     <changeBounds/> | ||||
|     <changeTransform/> | ||||
|     <changeImageTransform/> | ||||
| </transitionSet> | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Alex Hart
						Alex Hart