Add shared element transition for camera fab.

This commit is contained in:
Alex Hart
2022-04-11 13:42:08 -03:00
committed by Greyson Parrelli
parent 33b88796e8
commit 7f2f5a182f
10 changed files with 174 additions and 19 deletions

View File

@@ -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
}
}
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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"
)
)
}
}

View File

@@ -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)