Updated on 2026-08-14
This commit is contained in:
parent
291a07c435
commit
9278297133
27 changed files with 244 additions and 72 deletions
|
|
@ -187,7 +187,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
private fun initWithConfigDependency(config: Config) {
|
||||
shopService = TangemShopService(this, config.shopify!!)
|
||||
initAnalytics(this, config)
|
||||
initFeedbackManager(this, preferencesStorage, foregroundActivityObserver)
|
||||
initFeedbackManager(this, preferencesStorage, foregroundActivityObserver, store)
|
||||
}
|
||||
|
||||
private fun initAnalytics(application: Application, config: Config) {
|
||||
|
|
@ -213,6 +213,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
context: Context,
|
||||
preferencesStorage: PreferencesStorage,
|
||||
foregroundActivityObserver: ForegroundActivityObserver,
|
||||
store: Store<AppState>,
|
||||
) {
|
||||
fun initAdditionalFeedbackInfo(context: Context): AdditionalFeedbackInfo = AdditionalFeedbackInfo().apply {
|
||||
appVersion = try {
|
||||
|
|
@ -246,7 +247,7 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
val feedbackManager = FeedbackManager(
|
||||
infoHolder = additionalFeedbackInfo,
|
||||
logCollector = tangemLogCollector,
|
||||
chatManager = ChatManager(preferencesStorage, foregroundActivityObserver),
|
||||
chatManager = ChatManager(preferencesStorage, foregroundActivityObserver, store),
|
||||
)
|
||||
store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ data class ZendeskConfig(
|
|||
val url: String,
|
||||
) : ChatConfig
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class SprinklrConfig(
|
||||
@Json(name = "appID")
|
||||
val appId: String,
|
||||
@Json(name = "baseURL")
|
||||
val baseUrl: String,
|
||||
) : ChatConfig
|
||||
|
|
@ -5,18 +5,21 @@ import com.tangem.tap.ForegroundActivityObserver
|
|||
import com.tangem.tap.common.chat.opener.ChatOpener
|
||||
import com.tangem.tap.common.chat.opener.implementation.SprinklrChatOpener
|
||||
import com.tangem.tap.common.chat.opener.implementation.ZendeskChatOpener
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.persistence.PreferencesStorage
|
||||
import org.rekotlin.Store
|
||||
|
||||
class ChatManager(
|
||||
private val preferencesStorage: PreferencesStorage,
|
||||
private val foregroundActivityObserver: ForegroundActivityObserver,
|
||||
private val store: Store<AppState>,
|
||||
) {
|
||||
private val openers = mutableMapOf<ChatConfig, ChatOpener>()
|
||||
|
||||
fun open(config: ChatConfig, feedbackDataBuilder: (Context) -> String) {
|
||||
val opener = openers.getOrPut(config) {
|
||||
when (config) {
|
||||
is SprinklrConfig -> SprinklrChatOpener()
|
||||
is SprinklrConfig -> SprinklrChatOpener(config, store)
|
||||
is ZendeskConfig -> ZendeskChatOpener(config, preferencesStorage, foregroundActivityObserver)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,21 @@
|
|||
package com.tangem.tap.common.chat.opener.implementation
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.tap.common.chat.SprinklrConfig
|
||||
import com.tangem.tap.common.chat.opener.ChatOpener
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.sprinklr.redux.SprinklrAction
|
||||
import org.rekotlin.Store
|
||||
|
||||
internal class SprinklrChatOpener : ChatOpener {
|
||||
internal class SprinklrChatOpener(
|
||||
private val config: SprinklrConfig,
|
||||
private val store: Store<AppState>,
|
||||
) : ChatOpener {
|
||||
override fun open(feedbackDataBuilder: (Context) -> String) {
|
||||
// TODO: Open activity with Sprinklr WebView, will be in further MRs
|
||||
store.dispatch(SprinklrAction.SetConfig(config))
|
||||
store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Sprinklr))
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,7 @@ import androidx.compose.material.Icon
|
|||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.ripple.LocalRippleTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -133,18 +131,6 @@ fun ClearButton(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for disable ripple if button is enable = false
|
||||
*/
|
||||
@Composable
|
||||
fun ToggledRippleTheme(
|
||||
isEnabled: Boolean,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val theme = LocalRippleTheme provides if (isEnabled) LocalRippleTheme.current else NoRippleTheme()
|
||||
CompositionLocalProvider(theme) { content() }
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ButtonTest() {
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
package com.tangem.tap.common.compose
|
||||
|
||||
import androidx.compose.material.ripple.RippleAlpha
|
||||
import androidx.compose.material.ripple.RippleTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class NoRippleTheme : RippleTheme {
|
||||
@Composable
|
||||
override fun defaultColor() = Color.Unspecified
|
||||
|
||||
@Composable
|
||||
override fun rippleAlpha(): RippleAlpha = RippleAlpha(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import com.tangem.tap.features.onboarding.products.wallet.ui.OnboardingWalletFra
|
|||
import com.tangem.tap.features.saveWallet.ui.SaveWalletBottomSheetFragment
|
||||
import com.tangem.tap.features.send.ui.SendFragment
|
||||
import com.tangem.tap.features.shop.ui.ShopFragment
|
||||
import com.tangem.tap.features.sprinklr.ui.SprinklrFragment
|
||||
import com.tangem.tap.features.tokens.addCustomToken.AddCustomTokenFragment
|
||||
import com.tangem.tap.features.tokens.ui.AddTokensFragment
|
||||
import com.tangem.tap.features.wallet.ui.WalletDetailsFragment
|
||||
|
|
@ -120,5 +121,6 @@ private fun fragmentFactory(screen: AppScreen): Fragment {
|
|||
AppScreen.Welcome -> WelcomeFragment()
|
||||
AppScreen.SaveWallet -> SaveWalletBottomSheetFragment()
|
||||
AppScreen.WalletSelector -> WalletSelectorBottomSheetFragment()
|
||||
AppScreen.Sprinklr -> SprinklrFragment()
|
||||
}
|
||||
}
|
||||
|
|
@ -13,11 +13,12 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWallet
|
|||
import com.tangem.tap.features.saveWallet.redux.SaveWalletReducer
|
||||
import com.tangem.tap.features.send.redux.reducers.SendScreenReducer
|
||||
import com.tangem.tap.features.shop.redux.ShopReducer
|
||||
import com.tangem.tap.features.sprinklr.redux.SprinklrReducer
|
||||
import com.tangem.tap.features.tokens.redux.TokensReducer
|
||||
import com.tangem.tap.features.wallet.redux.reducers.WalletReducer
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.features.walletSelector.redux.WalletSelectorReducer
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeReducer
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import org.rekotlin.Action
|
||||
|
||||
fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder): AppState {
|
||||
|
|
@ -42,6 +43,7 @@ fun appReducer(action: Action, state: AppState?, appStateHolder: AppStateHolder)
|
|||
welcomeState = WelcomeReducer.reduce(action, state),
|
||||
saveWalletState = SaveWalletReducer.reduce(action, state),
|
||||
walletSelectorState = WalletSelectorReducer.reduce(action, state),
|
||||
sprinklrState = SprinklrReducer.reduce(action, state),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import com.tangem.tap.features.send.redux.middlewares.SendMiddleware
|
|||
import com.tangem.tap.features.send.redux.states.SendState
|
||||
import com.tangem.tap.features.shop.redux.ShopMiddleware
|
||||
import com.tangem.tap.features.shop.redux.ShopState
|
||||
import com.tangem.tap.features.sprinklr.redux.SprinklrMiddleware
|
||||
import com.tangem.tap.features.sprinklr.redux.SprinklrState
|
||||
import com.tangem.tap.features.tokens.redux.TokensMiddleware
|
||||
import com.tangem.tap.features.tokens.redux.TokensState
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
|
|
@ -60,6 +62,7 @@ data class AppState(
|
|||
val welcomeState: WelcomeState = WelcomeState(),
|
||||
val saveWalletState: SaveWalletState = SaveWalletState(),
|
||||
val walletSelectorState: WalletSelectorState = WalletSelectorState(),
|
||||
val sprinklrState: SprinklrState = SprinklrState(),
|
||||
) : StateType {
|
||||
|
||||
val domainState: DomainState
|
||||
|
|
@ -94,6 +97,7 @@ data class AppState(
|
|||
WalletSelectorMiddleware().middleware,
|
||||
LockUserWalletsTimerMiddleware().middleware,
|
||||
AccessCodeRequestPolicyMiddleware().middleware,
|
||||
SprinklrMiddleware().middleware,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.common.LogConfig
|
|||
import com.tangem.domain.common.ProductType
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.chat.SprinklrConfig
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
|
|
@ -111,7 +110,7 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di
|
|||
|
||||
// if config not set -> try to get it based on a scanResponse.productType
|
||||
val unsafeChatConfig = action.chatConfig ?: when {
|
||||
scanResponse?.isSaltPay() == true -> config.saltPayConfig?.sprinklrAppID?.let(::SprinklrConfig)
|
||||
scanResponse?.isSaltPay() == true -> config.saltPayConfig?.sprinklr
|
||||
else -> config.zendesk
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,4 +26,5 @@ enum class AppScreen(
|
|||
Welcome,
|
||||
SaveWallet(isDialogFragment = true),
|
||||
WalletSelector(isDialogFragment = true),
|
||||
Sprinklr,
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.saltPay
|
||||
|
||||
import com.tangem.tap.common.chat.SprinklrConfig
|
||||
import org.spongycastle.util.encoders.Base64.toBase64String
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class SaltPayConfig(
|
||||
val sprinklrAppID: String,
|
||||
val sprinklr: SprinklrConfig,
|
||||
val kycProvider: KYCProvider,
|
||||
val credentials: Credentials,
|
||||
) {
|
||||
companion object {
|
||||
fun stub(): SaltPayConfig {
|
||||
return SaltPayConfig(
|
||||
sprinklrAppID = "",
|
||||
sprinklr = SprinklrConfig("", ""),
|
||||
kycProvider = KYCProvider("", "", "", ""),
|
||||
credentials = Credentials("", ""),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import android.app.Dialog
|
|||
import android.content.Context
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.tap.common.chat.SprinklrConfig
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.feedback.SupportInfo
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -21,14 +20,14 @@ class NoFundsForActivationDialog {
|
|||
setTitle(R.string.saltpay_error_no_gas_title)
|
||||
setMessage(R.string.saltpay_error_no_gas_message)
|
||||
setPositiveButton(R.string.chat_button_title) { _, _ ->
|
||||
val sprinklrAppId = store.state.globalState.configManager?.config
|
||||
val sprinklrConfig = store.state.globalState.configManager?.config
|
||||
?.saltPayConfig
|
||||
?.sprinklrAppID
|
||||
?.sprinklr
|
||||
.guard {
|
||||
store.dispatchDebugErrorNotification("SaltPayConfig not initialized")
|
||||
return@setPositiveButton
|
||||
}
|
||||
store.dispatch(GlobalAction.OpenChat(SupportInfo(), SprinklrConfig(sprinklrAppId)))
|
||||
store.dispatch(GlobalAction.OpenChat(SupportInfo(), sprinklrConfig))
|
||||
}
|
||||
setNegativeButton(R.string.common_cancel) { _, _ ->
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.tap.features.sprinklr.redux
|
||||
|
||||
import com.tangem.tap.common.chat.SprinklrConfig
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed interface SprinklrAction : Action {
|
||||
data class SetConfig(val config: SprinklrConfig) : SprinklrAction
|
||||
data class UpdateUrl(val url: String) : SprinklrAction
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.tap.features.sprinklr.redux
|
||||
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.Middleware
|
||||
|
||||
internal class SprinklrMiddleware {
|
||||
val middleware: Middleware<AppState> = { _, appStateProvider ->
|
||||
{ next ->
|
||||
{ action ->
|
||||
val appState = appStateProvider()
|
||||
if (action is SprinklrAction && appState != null) {
|
||||
handleAction(action)
|
||||
}
|
||||
next(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAction(action: SprinklrAction) {
|
||||
when (action) {
|
||||
is SprinklrAction.SetConfig -> createUrl()
|
||||
is SprinklrAction.UpdateUrl -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun createUrl() {
|
||||
// TODO: Create Sprinklr URL, will be in further MRs
|
||||
val url = "https://prod-live-chat.sprinklr.com/" +
|
||||
"page?appId=60c1d169c96beb5bf5a326f3_app_950954&device=MOBILE&enableClose=true&zoom=false"
|
||||
store.dispatchOnMain(SprinklrAction.UpdateUrl(url))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.tap.features.sprinklr.redux
|
||||
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import org.rekotlin.Action
|
||||
|
||||
internal object SprinklrReducer {
|
||||
fun reduce(action: Action, state: AppState): SprinklrState {
|
||||
return if (action is SprinklrAction) {
|
||||
internalReduce(action, state.sprinklrState)
|
||||
} else state.sprinklrState
|
||||
}
|
||||
|
||||
private fun internalReduce(action: SprinklrAction, state: SprinklrState): SprinklrState {
|
||||
return when (action) {
|
||||
is SprinklrAction.SetConfig -> state
|
||||
is SprinklrAction.UpdateUrl -> state.copy(url = action.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.tap.features.sprinklr.redux
|
||||
|
||||
data class SprinklrState(
|
||||
val url: String = "",
|
||||
)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.tap.features.sprinklr.ui
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.tangem.core.ui.fragments.ComposeFragment
|
||||
|
||||
internal class SprinklrFragment : ComposeFragment<SprinklrScreenState>() {
|
||||
private val viewModel by viewModels<SprinklrViewModel>()
|
||||
|
||||
@Composable
|
||||
override fun provideState(): State<SprinklrScreenState> {
|
||||
return viewModel.state.collectAsState()
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun ScreenContent(modifier: Modifier, state: SprinklrScreenState) {
|
||||
BackHandler(onBack = state.onNavigateBack)
|
||||
SprinklrScreenContent(
|
||||
modifier = modifier
|
||||
.systemBarsPadding()
|
||||
.imePadding(),
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.tap.features.sprinklr.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.google.accompanist.web.WebView
|
||||
import com.google.accompanist.web.rememberWebViewState
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Composable
|
||||
internal fun SprinklrScreenContent(
|
||||
state: SprinklrScreenState,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
WebView(
|
||||
modifier = modifier,
|
||||
state = rememberWebViewState(url = state.initialUrl),
|
||||
onCreated = { webView ->
|
||||
with(webView.settings) {
|
||||
javaScriptEnabled = true
|
||||
domStorageEnabled = true
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.tap.features.sprinklr.ui
|
||||
|
||||
internal data class SprinklrScreenState(
|
||||
val initialUrl: String = "",
|
||||
val onNavigateBack: () -> Unit = {},
|
||||
)
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.tap.features.sprinklr.ui
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.sprinklr.redux.SprinklrState
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
internal class SprinklrViewModel : ViewModel(), StoreSubscriber<SprinklrState> {
|
||||
private val stateInternal = MutableStateFlow(SprinklrScreenState())
|
||||
val state = stateInternal.asStateFlow()
|
||||
|
||||
init {
|
||||
subscribeToStoreChanges()
|
||||
}
|
||||
|
||||
override fun newState(state: SprinklrState) {
|
||||
stateInternal.update { prevState ->
|
||||
prevState.copy(
|
||||
initialUrl = state.url,
|
||||
onNavigateBack = this::navigateBack,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
private fun subscribeToStoreChanges() {
|
||||
store.subscribe(this) { appState ->
|
||||
appState.skip { old, new -> old.sprinklrState == new.sprinklrState }
|
||||
.select { it.sprinklrState }
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateBack() {
|
||||
store.dispatchOnMain(NavigationAction.PopBackTo())
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,6 @@ import com.tangem.domain.redux.domainStore
|
|||
import com.tangem.tap.common.compose.AddCustomTokenWarning
|
||||
import com.tangem.tap.common.compose.ClosePopupTrigger
|
||||
import com.tangem.tap.common.compose.ComposeDialogManager
|
||||
import com.tangem.tap.common.compose.ToggledRippleTheme
|
||||
import com.tangem.tap.common.compose.keyboardAsState
|
||||
import com.tangem.tap.domain.moduleMessage.ModuleMessageConverter
|
||||
import com.tangem.tap.features.tokens.addCustomToken.compose.test.TestCase
|
||||
|
|
@ -66,7 +65,7 @@ import kotlinx.coroutines.launch
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
private class AddCustomTokenScreen {} // for simple search
|
||||
private class AddCustomTokenScreen // for simple search
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
|
|
@ -91,11 +90,13 @@ fun AddCustomTokenScreen(
|
|||
},
|
||||
sheetPeekHeight = 0.dp,
|
||||
) {
|
||||
Column() {
|
||||
TestCasesList(onItemClick = {
|
||||
selectedTestCase.value = it
|
||||
toggleBottomSheet()
|
||||
})
|
||||
Column {
|
||||
TestCasesList(
|
||||
onItemClick = {
|
||||
selectedTestCase.value = it
|
||||
toggleBottomSheet()
|
||||
},
|
||||
)
|
||||
ScreenContent(state, closePopupTrigger)
|
||||
}
|
||||
}
|
||||
|
|
@ -228,23 +229,21 @@ private fun AddCustomTokenFab(
|
|||
FloatingActionButtonDefaults.elevation()
|
||||
}
|
||||
|
||||
ToggledRippleTheme(isEnabled) {
|
||||
ExtendedFloatingActionButton(
|
||||
modifier = modifier,
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Add,
|
||||
tint = contentColor,
|
||||
contentDescription = "Add",
|
||||
)
|
||||
},
|
||||
text = { Text(text = stringResource(id = R.string.common_add)) },
|
||||
onClick = { if (isEnabled) onClick() },
|
||||
backgroundColor = backgroundColor,
|
||||
contentColor = contentColor,
|
||||
elevation = elevation,
|
||||
)
|
||||
}
|
||||
ExtendedFloatingActionButton(
|
||||
modifier = modifier,
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Add,
|
||||
tint = contentColor,
|
||||
contentDescription = "Add",
|
||||
)
|
||||
},
|
||||
text = { Text(text = stringResource(id = R.string.common_add)) },
|
||||
onClick = { if (isEnabled) onClick() },
|
||||
backgroundColor = backgroundColor,
|
||||
contentColor = contentColor,
|
||||
elevation = elevation,
|
||||
)
|
||||
}
|
||||
|
||||
data class ScreenFieldData(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue