mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-17 23:43:34 +01:00
Fix snackbar durations.
This commit is contained in:
committed by
jeffrey-signal
parent
bb21363ca8
commit
305c32cfc5
@@ -43,7 +43,6 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.systemBarsPadding
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
||||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
|
||||||
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
|
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
|
||||||
@@ -83,6 +82,7 @@ import kotlinx.coroutines.flow.distinctUntilChangedBy
|
|||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.signal.core.ui.compose.Snackbars
|
||||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||||
import org.signal.core.util.getSerializableCompat
|
import org.signal.core.util.getSerializableCompat
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
@@ -325,7 +325,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
|||||||
mainNavigationViewModel.snackbarRegistry.emit(
|
mainNavigationViewModel.snackbarRegistry.emit(
|
||||||
SnackbarState(
|
SnackbarState(
|
||||||
message = getString(R.string.CallQualitySheet__thanks_for_your_feedback),
|
message = getString(R.string.CallQualitySheet__thanks_for_your_feedback),
|
||||||
duration = SnackbarDuration.Short,
|
duration = Snackbars.Duration.SHORT,
|
||||||
hostKey = MainSnackbarHostKey.Chat,
|
hostKey = MainSnackbarHostKey.Chat,
|
||||||
fallbackKey = MainSnackbarHostKey.MainChrome
|
fallbackKey = MainSnackbarHostKey.MainChrome
|
||||||
)
|
)
|
||||||
@@ -903,7 +903,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
|||||||
mainNavigationViewModel.snackbarRegistry.emit(
|
mainNavigationViewModel.snackbarRegistry.emit(
|
||||||
SnackbarState(
|
SnackbarState(
|
||||||
message = getString(R.string.VerifyBackupKey__backup_key_correct),
|
message = getString(R.string.VerifyBackupKey__backup_key_correct),
|
||||||
duration = SnackbarDuration.Short,
|
duration = Snackbars.Duration.SHORT,
|
||||||
hostKey = MainSnackbarHostKey.MainChrome
|
hostKey = MainSnackbarHostKey.MainChrome
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import android.view.View
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
@@ -22,6 +21,7 @@ import io.reactivex.rxjava3.core.BackpressureStrategy
|
|||||||
import io.reactivex.rxjava3.kotlin.Flowables
|
import io.reactivex.rxjava3.kotlin.Flowables
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.signal.core.ui.compose.Snackbars
|
||||||
import org.signal.core.util.DimensionUnit
|
import org.signal.core.util.DimensionUnit
|
||||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||||
import org.signal.core.util.concurrent.addTo
|
import org.signal.core.util.concurrent.addTo
|
||||||
@@ -458,7 +458,7 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal
|
|||||||
mainNavigationViewModel.snackbarRegistry.emit(
|
mainNavigationViewModel.snackbarRegistry.emit(
|
||||||
SnackbarState(
|
SnackbarState(
|
||||||
message = snackbarMessage,
|
message = snackbarMessage,
|
||||||
duration = SnackbarDuration.Short,
|
duration = Snackbars.Duration.SHORT,
|
||||||
hostKey = MainSnackbarHostKey.MainChrome
|
hostKey = MainSnackbarHostKey.MainChrome
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import org.signal.core.util.AppUtil
|
import org.signal.core.util.AppUtil
|
||||||
import org.signal.core.util.ThreadUtil
|
import org.signal.core.util.ThreadUtil
|
||||||
import org.signal.core.util.concurrent.SignalExecutors
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
@@ -33,6 +32,8 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
|||||||
import org.thoughtcrime.securesms.components.settings.app.privacy.advanced.AdvancedPrivacySettingsRepository
|
import org.thoughtcrime.securesms.components.settings.app.privacy.advanced.AdvancedPrivacySettingsRepository
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository
|
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository
|
||||||
import org.thoughtcrime.securesms.components.settings.configure
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
|
import org.thoughtcrime.securesms.components.snackbars.SnackbarState
|
||||||
|
import org.thoughtcrime.securesms.components.snackbars.makeSnackbar
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||||
import org.thoughtcrime.securesms.database.JobDatabase
|
import org.thoughtcrime.securesms.database.JobDatabase
|
||||||
import org.thoughtcrime.securesms.database.LocalMetricsDatabase
|
import org.thoughtcrime.securesms.database.LocalMetricsDatabase
|
||||||
@@ -100,7 +101,11 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
|||||||
|
|
||||||
setFragmentResultListener(CallQualityBottomSheetFragment.REQUEST_KEY) { _, bundle ->
|
setFragmentResultListener(CallQualityBottomSheetFragment.REQUEST_KEY) { _, bundle ->
|
||||||
if (bundle.getBoolean(CallQualityBottomSheetFragment.REQUEST_KEY, false)) {
|
if (bundle.getBoolean(CallQualityBottomSheetFragment.REQUEST_KEY, false)) {
|
||||||
Snackbar.make(requireView(), R.string.CallQualitySheet__thanks_for_your_feedback, Snackbar.LENGTH_SHORT).show()
|
makeSnackbar(
|
||||||
|
SnackbarState(
|
||||||
|
message = getString(R.string.CallQualitySheet__thanks_for_your_feedback)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Box
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -31,7 +30,9 @@ import org.signal.core.ui.compose.Dividers
|
|||||||
import org.signal.core.ui.compose.Previews
|
import org.signal.core.ui.compose.Previews
|
||||||
import org.signal.core.ui.compose.Rows
|
import org.signal.core.ui.compose.Rows
|
||||||
import org.signal.core.ui.compose.Scaffolds
|
import org.signal.core.ui.compose.Scaffolds
|
||||||
|
import org.signal.core.ui.compose.Snackbars
|
||||||
import org.signal.core.ui.compose.Texts
|
import org.signal.core.ui.compose.Texts
|
||||||
|
import org.signal.core.ui.compose.showSnackbar
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
import org.thoughtcrime.securesms.compose.StatusBarColorNestedScrollConnection
|
import org.thoughtcrime.securesms.compose.StatusBarColorNestedScrollConnection
|
||||||
@@ -73,7 +74,7 @@ class PhoneNumberPrivacySettingsFragment : ComposeFragment() {
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
snackbarHostState.showSnackbar(
|
snackbarHostState.showSnackbar(
|
||||||
message = snackbarMessage,
|
message = snackbarMessage,
|
||||||
duration = SnackbarDuration.Short
|
duration = Snackbars.Duration.SHORT
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,12 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.components.snackbars
|
package org.thoughtcrime.securesms.components.snackbars
|
||||||
|
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.signal.core.ui.compose.Snackbars
|
||||||
|
|
||||||
fun Fragment.makeSnackbar(state: SnackbarState) {
|
fun Fragment.makeSnackbar(state: SnackbarState) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
@@ -18,9 +21,10 @@ fun Fragment.makeSnackbar(state: SnackbarState) {
|
|||||||
requireView(),
|
requireView(),
|
||||||
state.message,
|
state.message,
|
||||||
when (state.duration) {
|
when (state.duration) {
|
||||||
SnackbarDuration.Short -> Snackbar.LENGTH_SHORT
|
Snackbars.Duration.SHORT -> Snackbar.LENGTH_SHORT
|
||||||
SnackbarDuration.Long -> Snackbar.LENGTH_LONG
|
Snackbars.Duration.LONG -> Snackbar.LENGTH_LONG
|
||||||
SnackbarDuration.Indefinite -> Snackbar.LENGTH_INDEFINITE
|
Snackbars.Duration.INDEFINITE -> Snackbar.LENGTH_INDEFINITE
|
||||||
|
else -> Snackbar.LENGTH_INDEFINITE
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,4 +34,11 @@ fun Fragment.makeSnackbar(state: SnackbarState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
snackbar.show()
|
snackbar.show()
|
||||||
|
|
||||||
|
if (state.duration is Snackbars.Duration.Custom) {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
delay(state.duration.duration)
|
||||||
|
snackbar.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
package org.thoughtcrime.securesms.components.snackbars
|
package org.thoughtcrime.securesms.components.snackbars
|
||||||
|
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.compose.material3.SnackbarDuration
|
import org.signal.core.ui.compose.Snackbars
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,15 +16,15 @@ import org.thoughtcrime.securesms.R
|
|||||||
* @property actionState Optional action button configuration.
|
* @property actionState Optional action button configuration.
|
||||||
* @property showProgress Whether to show a progress indicator in the snackbar.
|
* @property showProgress Whether to show a progress indicator in the snackbar.
|
||||||
* @property duration How long the snackbar should be displayed.
|
* @property duration How long the snackbar should be displayed.
|
||||||
* @property hostKey The target host where this snackbar should be displayed.
|
* @property hostKey The target host where this snackbar should be displayed. Defaults to [SnackbarHostKey.Global]
|
||||||
* @property fallbackKey Optional host to fallback upon if the host key is not registered. Defaults to the Global key.
|
* @property fallbackKey Optional host to fallback upon if the host key is not registered. Defaults to the Global key.
|
||||||
*/
|
*/
|
||||||
data class SnackbarState(
|
data class SnackbarState(
|
||||||
val message: String,
|
val message: String,
|
||||||
val actionState: ActionState? = null,
|
val actionState: ActionState? = null,
|
||||||
val showProgress: Boolean = false,
|
val showProgress: Boolean = false,
|
||||||
val duration: SnackbarDuration = SnackbarDuration.Long,
|
val duration: Snackbars.Duration = Snackbars.Duration.SHORT,
|
||||||
val hostKey: SnackbarHostKey,
|
val hostKey: SnackbarHostKey = SnackbarHostKey.Global,
|
||||||
val fallbackKey: SnackbarHostKey? = SnackbarHostKey.Global
|
val fallbackKey: SnackbarHostKey? = SnackbarHostKey.Global
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.compose.material3.SnackbarDuration;
|
import org.signal.core.ui.compose.Snackbars;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||||
@@ -152,7 +152,7 @@ public class ConversationListArchiveFragment extends ConversationListFragment
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
SnackbarDuration.Long,
|
Snackbars.Duration.LONG,
|
||||||
MainSnackbarHostKey.MainChrome.INSTANCE,
|
MainSnackbarHostKey.MainChrome.INSTANCE,
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.annotation.PluralsRes;
|
import androidx.annotation.PluralsRes;
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
import androidx.compose.material3.SnackbarDuration;
|
import org.signal.core.ui.compose.Snackbars;
|
||||||
import androidx.compose.ui.platform.ComposeView;
|
import androidx.compose.ui.platform.ComposeView;
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -991,7 +991,7 @@ public class ConversationListFragment extends MainFragment implements Conversati
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
showProgress,
|
showProgress,
|
||||||
SnackbarDuration.Long,
|
Snackbars.Duration.LONG,
|
||||||
MainSnackbarHostKey.MainChrome.INSTANCE,
|
MainSnackbarHostKey.MainChrome.INSTANCE,
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
@@ -1075,7 +1075,7 @@ public class ConversationListFragment extends MainFragment implements Conversati
|
|||||||
getString(R.string.conversation_list__you_can_only_pin_up_to_d_chats, MAXIMUM_PINNED_CONVERSATIONS),
|
getString(R.string.conversation_list__you_can_only_pin_up_to_d_chats, MAXIMUM_PINNED_CONVERSATIONS),
|
||||||
null,
|
null,
|
||||||
false,
|
false,
|
||||||
SnackbarDuration.Long,
|
Snackbars.Duration.LONG,
|
||||||
MainSnackbarHostKey.MainChrome.INSTANCE,
|
MainSnackbarHostKey.MainChrome.INSTANCE,
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
@@ -1441,7 +1441,7 @@ public class ConversationListFragment extends MainFragment implements Conversati
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
SnackbarDuration.Long,
|
Snackbars.Duration.LONG,
|
||||||
MainSnackbarHostKey.MainChrome.INSTANCE,
|
MainSnackbarHostKey.MainChrome.INSTANCE,
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.signal.core.ui.compose.AllDevicePreviews
|
|||||||
import org.signal.core.ui.compose.Dialogs
|
import org.signal.core.ui.compose.Dialogs
|
||||||
import org.signal.core.ui.compose.Previews
|
import org.signal.core.ui.compose.Previews
|
||||||
import org.signal.core.ui.compose.Snackbars
|
import org.signal.core.ui.compose.Snackbars
|
||||||
|
import org.signal.core.ui.compose.showSnackbar
|
||||||
import org.thoughtcrime.securesms.components.snackbars.SnackbarHostKey
|
import org.thoughtcrime.securesms.components.snackbars.SnackbarHostKey
|
||||||
import org.thoughtcrime.securesms.components.snackbars.SnackbarState
|
import org.thoughtcrime.securesms.components.snackbars.SnackbarState
|
||||||
import org.thoughtcrime.securesms.components.snackbars.rememberSnackbarState
|
import org.thoughtcrime.securesms.components.snackbars.rememberSnackbarState
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import android.content.Intent
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -34,6 +33,7 @@ import org.signal.core.ui.compose.Previews
|
|||||||
import org.signal.core.ui.compose.Rows
|
import org.signal.core.ui.compose.Rows
|
||||||
import org.signal.core.ui.compose.Scaffolds
|
import org.signal.core.ui.compose.Scaffolds
|
||||||
import org.signal.core.ui.compose.Snackbars
|
import org.signal.core.ui.compose.Snackbars
|
||||||
|
import org.signal.core.ui.compose.showSnackbar
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeyDisplayFragment
|
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeyDisplayFragment
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
@@ -146,7 +146,7 @@ class AdvancedPinSettingsFragment : ComposeFragment() {
|
|||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
viewModel.snackbarHostState.showSnackbar(
|
viewModel.snackbarHostState.showSnackbar(
|
||||||
message = getString(R.string.ApplicationPreferencesActivity_pin_disabled),
|
message = getString(R.string.ApplicationPreferencesActivity_pin_disabled),
|
||||||
duration = SnackbarDuration.Long
|
duration = Snackbars.Duration.LONG
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import androidx.compose.material3.IconButton
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SecondaryTabRow
|
import androidx.compose.material3.SecondaryTabRow
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.SnackbarResult
|
import androidx.compose.material3.SnackbarResult
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
@@ -78,6 +77,7 @@ import org.signal.core.ui.compose.copied.androidx.compose.DragAndDropEvent
|
|||||||
import org.signal.core.ui.compose.copied.androidx.compose.DraggableItem
|
import org.signal.core.ui.compose.copied.androidx.compose.DraggableItem
|
||||||
import org.signal.core.ui.compose.copied.androidx.compose.dragContainer
|
import org.signal.core.ui.compose.copied.androidx.compose.dragContainer
|
||||||
import org.signal.core.ui.compose.copied.androidx.compose.rememberDragDropState
|
import org.signal.core.ui.compose.copied.androidx.compose.rememberDragDropState
|
||||||
|
import org.signal.core.ui.compose.showSnackbar
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.components.menu.ActionItem
|
import org.thoughtcrime.securesms.components.menu.ActionItem
|
||||||
@@ -625,7 +625,7 @@ private fun SnackbarHost(
|
|||||||
if (snackbarMessage != null) {
|
if (snackbarMessage != null) {
|
||||||
val result = hostState.showSnackbar(
|
val result = hostState.showSnackbar(
|
||||||
message = snackbarMessage,
|
message = snackbarMessage,
|
||||||
duration = SnackbarDuration.Short,
|
duration = Snackbars.Duration.SHORT,
|
||||||
withDismissAction = false
|
withDismissAction = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.components.snackbars
|
package org.thoughtcrime.securesms.components.snackbars
|
||||||
|
|
||||||
import androidx.compose.material3.SnackbarDuration
|
|
||||||
import androidx.core.util.Consumer
|
import androidx.core.util.Consumer
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
@@ -10,6 +9,7 @@ import io.mockk.mockk
|
|||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.signal.core.ui.compose.Snackbars
|
||||||
|
|
||||||
class SnackbarStateConsumerRegistryTest {
|
class SnackbarStateConsumerRegistryTest {
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ class SnackbarStateConsumerRegistryTest {
|
|||||||
message = "Test message",
|
message = "Test message",
|
||||||
hostKey = hostKey,
|
hostKey = hostKey,
|
||||||
fallbackKey = fallbackKey,
|
fallbackKey = fallbackKey,
|
||||||
duration = SnackbarDuration.Short
|
duration = Snackbars.Duration.SHORT
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,16 @@ import androidx.compose.material3.SnackbarData
|
|||||||
import androidx.compose.material3.SnackbarDuration
|
import androidx.compose.material3.SnackbarDuration
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.SnackbarResult
|
||||||
import androidx.compose.material3.SnackbarVisuals
|
import androidx.compose.material3.SnackbarVisuals
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.signal.core.ui.compose.theme.LocalSnackbarColors
|
import org.signal.core.ui.compose.theme.LocalSnackbarColors
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properly themed Snackbars. Since these use internal color state, we need to
|
* Properly themed Snackbars. Since these use internal color state, we need to
|
||||||
@@ -21,6 +27,48 @@ import org.signal.core.ui.compose.theme.LocalSnackbarColors
|
|||||||
* allow for quick and easy access to the proper theming for snackbars.
|
* allow for quick and easy access to the proper theming for snackbars.
|
||||||
*/
|
*/
|
||||||
object Snackbars {
|
object Snackbars {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snackbar duration that allows specifying exact durations or using predefined
|
||||||
|
* durations that match view-based snackbar timings.
|
||||||
|
*
|
||||||
|
* Compose's default [SnackbarDuration] values are significantly longer than view-based snackbars:
|
||||||
|
* - Compose Short = 4000ms vs View-based LENGTH_SHORT = 1500ms
|
||||||
|
* - Compose Long = 10000ms vs View-based LENGTH_LONG = 2750ms
|
||||||
|
*
|
||||||
|
* This sealed class provides durations that match view-based behavior for consistency.
|
||||||
|
*/
|
||||||
|
sealed class Duration {
|
||||||
|
abstract val duration: kotlin.time.Duration?
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/** 1500ms - matches view-based Snackbar.LENGTH_SHORT */
|
||||||
|
@JvmField
|
||||||
|
val SHORT: Duration = Short
|
||||||
|
|
||||||
|
/** 2750ms - matches view-based Snackbar.LENGTH_LONG */
|
||||||
|
@JvmField
|
||||||
|
val LONG: Duration = Long
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val INDEFINITE: Duration = Indefinite
|
||||||
|
}
|
||||||
|
|
||||||
|
private data object Short : Duration() {
|
||||||
|
override val duration: kotlin.time.Duration = 1500.milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
private data object Long : Duration() {
|
||||||
|
override val duration: kotlin.time.Duration = 2750.milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
private data object Indefinite : Duration() {
|
||||||
|
override val duration: kotlin.time.Duration? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Custom(override val duration: kotlin.time.Duration) : Duration()
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Host(snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier) {
|
fun Host(snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier) {
|
||||||
SnackbarHost(hostState = snackbarHostState, modifier = modifier) {
|
SnackbarHost(hostState = snackbarHostState, modifier = modifier) {
|
||||||
@@ -42,6 +90,55 @@ object Snackbars {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a snackbar with custom duration support.
|
||||||
|
*
|
||||||
|
* Unlike the standard [SnackbarHostState.showSnackbar] which only supports Compose's
|
||||||
|
* [SnackbarDuration] (Short=4s, Long=10s, Indefinite), this function allows specifying
|
||||||
|
* exact durations via [Snackbars.Duration], including durations that match view-based snackbars.
|
||||||
|
*
|
||||||
|
* @param message The message to display in the snackbar.
|
||||||
|
* @param actionLabel Optional action label to show. If null, no action button is shown.
|
||||||
|
* @param withDismissAction Whether to show a dismiss action (X button).
|
||||||
|
* @param duration The duration to show the snackbar. Defaults to [Snackbars.Duration.SHORT] (1500ms).
|
||||||
|
* @return [SnackbarResult] indicating whether the snackbar was dismissed or the action was performed.
|
||||||
|
*/
|
||||||
|
suspend fun SnackbarHostState.showSnackbar(
|
||||||
|
message: String,
|
||||||
|
actionLabel: String? = null,
|
||||||
|
withDismissAction: Boolean = false,
|
||||||
|
duration: Snackbars.Duration = Snackbars.Duration.SHORT
|
||||||
|
): SnackbarResult {
|
||||||
|
val durationValue = duration.duration
|
||||||
|
|
||||||
|
return if (durationValue == null) {
|
||||||
|
showSnackbar(
|
||||||
|
message = message,
|
||||||
|
actionLabel = actionLabel,
|
||||||
|
withDismissAction = withDismissAction,
|
||||||
|
duration = SnackbarDuration.Indefinite
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
coroutineScope {
|
||||||
|
val dismissJob = launch {
|
||||||
|
delay(durationValue)
|
||||||
|
currentSnackbarData?.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = showSnackbar(
|
||||||
|
message = message,
|
||||||
|
actionLabel = actionLabel,
|
||||||
|
withDismissAction = withDismissAction,
|
||||||
|
duration = SnackbarDuration.Indefinite
|
||||||
|
)
|
||||||
|
|
||||||
|
dismissJob.cancel()
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@DayNightPreviews
|
@DayNightPreviews
|
||||||
@Composable
|
@Composable
|
||||||
private fun SnackbarPreview() {
|
private fun SnackbarPreview() {
|
||||||
|
|||||||
Reference in New Issue
Block a user