mirror of
https://github.com/twofas/2fas-android.git
synced 2025-01-05 14:05:30 +01:00
Merge branch 'develop' into feature/material3
This commit is contained in:
commit
f4d7be59cf
@ -9,6 +9,8 @@
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<uses-permission
|
||||
android:name="com.google.android.gms.permission.AD_ID"
|
||||
tools:node="remove" />
|
||||
|
@ -9,6 +9,7 @@ import com.twofasapp.core.cipher.CipherService
|
||||
import com.twofasapp.core.cipher.CipherServiceImpl
|
||||
import com.twofasapp.permissions.CameraPermissionRequest
|
||||
import com.twofasapp.permissions.CameraPermissionRequestFlow
|
||||
import com.twofasapp.permissions.NotificationsPermissionRequestFlow
|
||||
import com.twofasapp.services.analytics.AnalyticsServiceFirebase
|
||||
import com.twofasapp.services.googledrive.GoogleDriveService
|
||||
import com.twofasapp.services.googledrive.GoogleDriveServiceImpl
|
||||
@ -39,6 +40,7 @@ val applicationModule = module {
|
||||
|
||||
factory { CameraPermissionRequest(activityContext()) }
|
||||
factory { CameraPermissionRequestFlow(activityContext()) }
|
||||
factory { NotificationsPermissionRequestFlow(activityContext()) }
|
||||
|
||||
single<Dispatchers> { AppDispatchers() }
|
||||
|
||||
|
@ -109,7 +109,7 @@ class ServiceItem(
|
||||
}
|
||||
|
||||
nextCode.pivotX = 0f
|
||||
nextCode.text = Spanner("Next token: ")
|
||||
nextCode.text = Spanner(root.context.getString(R.string.tokens__next_token, ""))
|
||||
.append(model.formatNextCode(), scaleSize(1.4f))
|
||||
|
||||
if (model.shouldShowNextToken.not() || isInEditMode || model.service.authType == ServiceDto.AuthType.HOTP) {
|
||||
|
@ -20,7 +20,7 @@
|
||||
style="@style/Toolbar.Back"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="Import from the file" />
|
||||
app:title="@string/backup__import_backup_file" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
@ -35,6 +35,7 @@ dependencies {
|
||||
implementation(libs.bundles.fastAdapter)
|
||||
implementation(libs.bundles.rxJava)
|
||||
implementation(libs.bundles.appCompat)
|
||||
implementation(libs.bundles.accompanist)
|
||||
implementation(libs.lottie)
|
||||
implementation(libs.timber)
|
||||
implementation(libs.kotlinCoroutines)
|
||||
|
@ -42,6 +42,7 @@ class BrowserExtensionModule : KoinModule {
|
||||
singleOf(::DeletePairedBrowserCase)
|
||||
|
||||
viewModelOf(::BrowserExtensionViewModel)
|
||||
viewModelOf(::BrowserExtensionPermissionViewModel)
|
||||
viewModelOf(::PairingScanViewModel)
|
||||
viewModelOf(::PairingProgressViewModel)
|
||||
viewModelOf(::BrowserExtensionRequestViewModel)
|
||||
|
@ -58,8 +58,9 @@ class BrowserExtensionRequestWorker(
|
||||
}
|
||||
),
|
||||
)
|
||||
showToast("Code sent successfully")
|
||||
showToast(context.getString(com.twofasapp.resources.R.string.extension__code_sent_msg))
|
||||
}
|
||||
|
||||
BrowserExtensionRequestPayload.Action.Deny -> {
|
||||
denyLoginRequestCase.invoke(payload.extensionId, payload.requestId)
|
||||
}
|
||||
@ -67,7 +68,7 @@ class BrowserExtensionRequestWorker(
|
||||
|
||||
|
||||
} catch (e: Exception) {
|
||||
showToast("Error occurred when sending code")
|
||||
showToast(context.getString(com.twofasapp.resources.R.string.extension__code_sent_error_msg))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,40 @@
|
||||
package com.twofasapp.browserextension.ui.main
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.rememberScaffoldState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@ -23,29 +44,71 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import com.twofasapp.design.compose.ButtonShape
|
||||
import com.twofasapp.design.compose.ButtonTextColor
|
||||
import com.twofasapp.design.compose.HeaderEntry
|
||||
import com.twofasapp.design.compose.SimpleEntry
|
||||
import com.twofasapp.design.compose.Toolbar
|
||||
import com.twofasapp.design.compose.dialogs.InputDialog
|
||||
import com.twofasapp.design.compose.dialogs.RationaleDialog
|
||||
import com.twofasapp.designsystem.TwTheme
|
||||
import com.twofasapp.designsystem.common.TwButton
|
||||
import com.twofasapp.designsystem.common.TwTopAppBar
|
||||
import com.twofasapp.designsystem.screen.CommonContent
|
||||
import com.twofasapp.designsystem.settings.SettingsHeader
|
||||
import com.twofasapp.designsystem.settings.SettingsLink
|
||||
import com.twofasapp.locale.TwLocale
|
||||
import com.twofasapp.extensions.openBrowserApp
|
||||
import com.twofasapp.navigation.SettingsDirections
|
||||
import com.twofasapp.navigation.SettingsRouter
|
||||
import com.twofasapp.resources.R
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@Composable
|
||||
fun BrowserExtensionScreen(
|
||||
openPairingScan: () -> Unit,
|
||||
openBrowserDetails: (String) -> Unit,
|
||||
viewModel: BrowserExtensionViewModel = koinViewModel(),
|
||||
internal fun RequestPermission(
|
||||
permission: String,
|
||||
rationaleTitle: String = "",
|
||||
rationaleText: String = "",
|
||||
onGranted: () -> Unit = {},
|
||||
onDismiss: () -> Unit = {},
|
||||
) {
|
||||
var showRationale by remember { mutableStateOf(false) }
|
||||
|
||||
val launcher = rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted ->
|
||||
if (isGranted) {
|
||||
onGranted()
|
||||
} else {
|
||||
showRationale = true
|
||||
}
|
||||
}
|
||||
|
||||
val permissionCheckResult = ContextCompat.checkSelfPermission(LocalContext.current, permission)
|
||||
if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
|
||||
onGranted()
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
launcher.launch(permission)
|
||||
}
|
||||
}
|
||||
|
||||
if (showRationale) {
|
||||
RationaleDialog(
|
||||
title = rationaleTitle, text = rationaleText, onDismiss = onDismiss
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun BrowserExtensionScreen(
|
||||
viewModel: BrowserExtensionViewModel = get(),
|
||||
router: SettingsRouter = get()
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsState().value
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val scope = rememberCoroutineScope()
|
||||
var askForPermission by remember { mutableStateOf(false) }
|
||||
|
||||
viewModel.onPairClick = { openPairingScan() }
|
||||
Scaffold(
|
||||
@ -55,24 +118,30 @@ fun BrowserExtensionScreen(
|
||||
if (uiState.isLoading) return@Scaffold
|
||||
|
||||
if (uiState.pairedBrowsers.isEmpty()) {
|
||||
EmptyScreen(
|
||||
onPairBrowserClick = openPairingScan,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
.padding(16.dp)
|
||||
)
|
||||
EmptyScreen(router = router, padding = padding, onAddClick = { askForPermission = true })
|
||||
} else {
|
||||
ContentScreen(
|
||||
onBrowserClick = openBrowserDetails,
|
||||
onPairBrowserClick = openPairingScan,
|
||||
viewModel = viewModel,
|
||||
uiState = uiState,
|
||||
padding = padding
|
||||
router = router,
|
||||
onAddClick = { askForPermission = true },
|
||||
padding = padding,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (askForPermission) {
|
||||
RequestPermission(
|
||||
permission = Manifest.permission.CAMERA,
|
||||
onGranted = { router.navigate(SettingsDirections.PairingScan) },
|
||||
onDismiss = { askForPermission = false },
|
||||
rationaleTitle = stringResource(id = R.string.permissions__camera_permission),
|
||||
rationaleText = stringResource(id = R.string.permissions__camera_permission_description),
|
||||
)
|
||||
}
|
||||
|
||||
uiState.getMostRecentEvent()?.let {
|
||||
when (it) {
|
||||
is BrowserExtensionUiState.Event.ShowSnackbarError -> {
|
||||
@ -86,28 +155,36 @@ fun BrowserExtensionScreen(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
private fun ContentScreen(
|
||||
onBrowserClick: (String) -> Unit,
|
||||
onPairBrowserClick: () -> Unit,
|
||||
viewModel: BrowserExtensionViewModel,
|
||||
uiState: BrowserExtensionUiState,
|
||||
router: SettingsRouter,
|
||||
onAddClick: () -> Unit,
|
||||
padding: PaddingValues,
|
||||
) {
|
||||
val activity = LocalContext.current as Activity
|
||||
val permissionState = rememberPermissionState(permission = Manifest.permission.POST_NOTIFICATIONS)
|
||||
|
||||
LazyColumn(modifier = Modifier.padding(padding)) {
|
||||
item { SettingsHeader(TwLocale.strings.browserExtPairedDevices) }
|
||||
|
||||
items(uiState.pairedBrowsers, key = { it.id }) {
|
||||
SettingsLink(it.name, onClick = { onBrowserClick(it.id) }, subtitle = TwLocale.formatDate(it.pairedAt))
|
||||
SimpleEntry(title = it.name,
|
||||
iconVisibleWhenNotSet = true,
|
||||
subtitle = it.formatPairedAt(),
|
||||
click = { router.navigate(SettingsDirections.BrowserDetails(extensionId = it.id)) })
|
||||
}
|
||||
|
||||
item {
|
||||
TwButton(
|
||||
text = "+ ${TwLocale.strings.browserExtAddNew}",
|
||||
onClick = onPairBrowserClick,
|
||||
height = TwTheme.dimen.buttonHeightSmall,
|
||||
modifier = Modifier.padding(start = 72.dp, top = 6.dp, bottom = 2.dp)
|
||||
)
|
||||
Button(
|
||||
onClick = { onAddClick() }, shape = ButtonShape(), modifier = Modifier.padding(start = 72.dp, top = 6.dp, bottom = 2.dp)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.browser__add_new).uppercase(), color = ButtonTextColor())
|
||||
}
|
||||
}
|
||||
|
||||
item { SettingsHeader(TwLocale.strings.browserExtDeviceName) }
|
||||
@ -121,14 +198,30 @@ private fun ContentScreen(
|
||||
iconEndClick = { viewModel.onEditDeviceClick() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.showRationaleDialog) {
|
||||
RationaleDialog(
|
||||
title = stringResource(id = R.string.permissions__camera_permission),
|
||||
text = stringResource(id = R.string.permissions__camera_permission_description),
|
||||
onDismiss = { viewModel.onRationaleDialogDismiss() }
|
||||
)
|
||||
if (permissionState.status.isGranted.not()) {
|
||||
item {
|
||||
Divider(Modifier.padding(top = 24.dp, bottom = 24.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.browser__push_notifications_content),
|
||||
style = MaterialTheme.typography.body2.copy(fontSize = 14.sp, color = MaterialTheme.colors.primary),
|
||||
modifier = Modifier.padding(start = 72.dp, bottom = 8.dp, end = 16.dp)
|
||||
)
|
||||
}
|
||||
item {
|
||||
Button(
|
||||
onClick = {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", activity.packageName, null))
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
activity.startActivity(intent)
|
||||
},
|
||||
shape = ButtonShape(),
|
||||
modifier = Modifier.padding(start = 72.dp, top = 6.dp, bottom = 2.dp)
|
||||
) {
|
||||
Text(text = "Enable Notifications".uppercase(), color = ButtonTextColor())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.showEditDeviceDialog) {
|
||||
@ -144,19 +237,36 @@ private fun ContentScreen(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptyScreen(
|
||||
onPairBrowserClick: () -> Unit,
|
||||
modifier: Modifier,
|
||||
internal fun EmptyScreen(
|
||||
router: SettingsRouter,
|
||||
padding: PaddingValues,
|
||||
onAddClick: () -> Unit,
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
CommonContent(
|
||||
image = painterResource(id = R.drawable.browser_extension_start_image),
|
||||
titleText = TwLocale.strings.browserExtHeader,
|
||||
descriptionText = "${TwLocale.strings.browserExtBody1}\n${TwLocale.strings.browserExtBody2}",
|
||||
ctaPrimaryText = TwLocale.strings.browserExtCta,
|
||||
ctaPrimaryClick = onPairBrowserClick,
|
||||
description = {
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
) {
|
||||
val (content, pair) = createRefs()
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp), horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier
|
||||
.constrainAs(content) {
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(pair.top)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
}
|
||||
.padding(vertical = 16.dp)) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.browser_extension_start_image),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.height(130.dp)
|
||||
.offset(y = (-16).dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append("${TwLocale.strings.browserExtMore1} ")
|
||||
@ -171,7 +281,38 @@ private fun EmptyScreen(
|
||||
.padding(top = 16.dp)
|
||||
.clickable { uriHandler.openUri(TwLocale.links.browserExt) },
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.browser__info_description_first) + "\n\n" + stringResource(id = R.string.browser__info_description_second),
|
||||
style = MaterialTheme.typography.body1,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append(stringResource(id = R.string.browser__more_info) + " ")
|
||||
withStyle(style = SpanStyle(MaterialTheme.colors.primary)) {
|
||||
append(stringResource(id = R.string.browser__more_info_link_title))
|
||||
}
|
||||
}, style = MaterialTheme.typography.body2, modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.align(CenterHorizontally)
|
||||
.clickable {
|
||||
activity?.openBrowserApp(url = "https://2fas.com/be")
|
||||
}, textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Button(onClick = { onAddClick() }, shape = ButtonShape(), modifier = Modifier
|
||||
.height(48.dp)
|
||||
.constrainAs(pair) {
|
||||
bottom.linkTo(parent.bottom, margin = 16.dp)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.browser__pair_with_web_browser).uppercase(), color = ButtonTextColor())
|
||||
}
|
||||
}
|
||||
}
|
@ -9,8 +9,6 @@ data class BrowserExtensionUiState(
|
||||
val isLoading: Boolean = true,
|
||||
val pairedBrowsers: List<PairedBrowser> = emptyList(),
|
||||
val mobileDevice: MobileDevice? = null,
|
||||
val isCameraPermissionGranted: Boolean = false,
|
||||
val showRationaleDialog: Boolean = false,
|
||||
val showEditDeviceDialog: Boolean = false,
|
||||
override val events: List<Event> = emptyList(),
|
||||
) : UiState<BrowserExtensionUiState, BrowserExtensionUiState.Event> {
|
||||
|
@ -7,21 +7,15 @@ import com.twofasapp.browserextension.domain.FetchPairedBrowsersCase
|
||||
import com.twofasapp.browserextension.domain.ObserveMobileDeviceCase
|
||||
import com.twofasapp.browserextension.domain.ObservePairedBrowsersCase
|
||||
import com.twofasapp.browserextension.domain.UpdateMobileDeviceCase
|
||||
import com.twofasapp.permissions.CameraPermissionRequestFlow
|
||||
import com.twofasapp.permissions.PermissionStatus
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class BrowserExtensionViewModel(
|
||||
private val dispatchers: Dispatchers,
|
||||
private val cameraPermissionRequest: CameraPermissionRequestFlow,
|
||||
private val observeMobileDeviceCase: ObserveMobileDeviceCase,
|
||||
private val observePairedBrowsersCase: ObservePairedBrowsersCase,
|
||||
private val updateMobileDeviceCase: UpdateMobileDeviceCase,
|
||||
@ -57,27 +51,6 @@ class BrowserExtensionViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun onPairBrowserClick() {
|
||||
cameraPermissionRequest.execute()
|
||||
.take(1)
|
||||
.onEach {
|
||||
when (it) {
|
||||
PermissionStatus.GRANTED -> {
|
||||
onPairClick()
|
||||
}
|
||||
|
||||
PermissionStatus.DENIED -> Unit
|
||||
PermissionStatus.DENIED_NEVER_ASK -> _uiState.update { state ->
|
||||
state.copy(showRationaleDialog = true)
|
||||
}
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
fun onRationaleDialogDismiss() {
|
||||
_uiState.update { it.copy(showRationaleDialog = false) }
|
||||
}
|
||||
|
||||
fun onEditDeviceClick() {
|
||||
_uiState.update { it.copy(showEditDeviceDialog = true) }
|
||||
}
|
||||
|
@ -0,0 +1,121 @@
|
||||
package com.twofasapp.browserextension.ui.main.permission
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.constraintlayout.compose.ConstraintLayout
|
||||
import com.twofasapp.browserextension.ui.main.RequestPermission
|
||||
import com.twofasapp.design.compose.ButtonHeight
|
||||
import com.twofasapp.design.compose.ButtonShape
|
||||
import com.twofasapp.design.compose.ButtonTextColor
|
||||
import com.twofasapp.design.compose.Toolbar
|
||||
import com.twofasapp.navigation.SettingsDirections
|
||||
import com.twofasapp.navigation.SettingsRouter
|
||||
import com.twofasapp.resources.R
|
||||
import org.koin.androidx.compose.get
|
||||
|
||||
@Composable
|
||||
internal fun BrowserExtensionPermissionScreen(
|
||||
router: SettingsRouter = get(),
|
||||
) {
|
||||
// Launched only on >= TIRAMISU
|
||||
var askForPermission by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Toolbar(title = stringResource(id = R.string.browser__browser_extension)) {
|
||||
router.navigate(SettingsDirections.GoBack)
|
||||
}
|
||||
}
|
||||
) { padding ->
|
||||
|
||||
ConstraintLayout(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
val (content, pair) = createRefs()
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.constrainAs(content) {
|
||||
top.linkTo(parent.top)
|
||||
bottom.linkTo(pair.top)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
}
|
||||
.padding(vertical = 16.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.browser_extension_permission_image),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.height(130.dp)
|
||||
.offset(y = (-16).dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.browser__push_notifications_title),
|
||||
style = MaterialTheme.typography.h6,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.browser__push_notifications_content),
|
||||
style = MaterialTheme.typography.body1,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { askForPermission = true },
|
||||
shape = ButtonShape(),
|
||||
modifier = Modifier
|
||||
.height(ButtonHeight())
|
||||
.constrainAs(pair) {
|
||||
bottom.linkTo(parent.bottom, margin = 16.dp)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.commons__continue).uppercase(), color = ButtonTextColor())
|
||||
}
|
||||
|
||||
if (askForPermission) {
|
||||
RequestPermission(
|
||||
permission = Manifest.permission.POST_NOTIFICATIONS,
|
||||
onGranted = { router.navigateBack() },
|
||||
onDismiss = {
|
||||
askForPermission = false
|
||||
router.navigateBack()
|
||||
},
|
||||
rationaleTitle = stringResource(id = R.string.browser__push_notifications_title),
|
||||
rationaleText = stringResource(id = R.string.browser__push_notifications_content),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.twofasapp.browserextension.ui.main.permission
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
class BrowserExtensionPermissionScreenFactory {
|
||||
|
||||
@Composable
|
||||
fun create() {
|
||||
BrowserExtensionPermissionScreen()
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.twofasapp.browserextension.ui.main.permission
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.twofasapp.base.BaseViewModel
|
||||
import com.twofasapp.permissions.NotificationsPermissionRequestFlow
|
||||
import com.twofasapp.permissions.PermissionStatus
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class BrowserExtensionPermissionViewModel(
|
||||
private val notificationsPermissionRequestFlow: NotificationsPermissionRequestFlow,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val permissionStatus = MutableStateFlow<PermissionStatus?>(null)
|
||||
|
||||
fun askForPermission() {
|
||||
viewModelScope.launch {
|
||||
notificationsPermissionRequestFlow.execute()
|
||||
.take(1)
|
||||
.collect { status ->
|
||||
println("dupa: $status")
|
||||
permissionStatus.update { status }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,18 @@
|
||||
package com.twofasapp.browserextension.ui.pairing.progress
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -29,16 +32,20 @@ import com.twofasapp.design.compose.AnimatedContent
|
||||
import com.twofasapp.design.compose.ButtonHeight
|
||||
import com.twofasapp.design.compose.ButtonShape
|
||||
import com.twofasapp.design.compose.ButtonTextColor
|
||||
import com.twofasapp.designsystem.common.TwTopAppBar
|
||||
import com.twofasapp.design.compose.Toolbar
|
||||
import com.twofasapp.navigation.SettingsDirections
|
||||
import com.twofasapp.navigation.SettingsRouter
|
||||
import com.twofasapp.resources.R
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import org.koin.androidx.compose.get
|
||||
|
||||
@Composable
|
||||
fun PairingProgressScreen(
|
||||
openMain: () -> Unit,
|
||||
openPairingScan: () -> Unit,
|
||||
extensionId: String,
|
||||
viewModel: PairingProgressViewModel = koinViewModel(),
|
||||
viewModel: PairingProgressViewModel = get(),
|
||||
router: SettingsRouter = get(),
|
||||
notificationManager: NotificationManager = get()
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsState()
|
||||
viewModel.pairBrowser(extensionId)
|
||||
@ -50,16 +57,8 @@ fun PairingProgressScreen(
|
||||
) { padding ->
|
||||
AnimatedContent(
|
||||
condition = uiState.value.isPairing,
|
||||
contentWhenTrue = { ProgressContent(Modifier.fillMaxSize().padding(padding)) },
|
||||
contentWhenFalse = {
|
||||
ResultContent(
|
||||
onContinueClick = { openMain() },
|
||||
onScanAgainClick = { openPairingScan() },
|
||||
uiState.value.isPairingSuccess,
|
||||
uiState.value.code,
|
||||
modifier = Modifier.fillMaxSize().padding(padding)
|
||||
)
|
||||
},
|
||||
contentWhenTrue = { ProgressContent() },
|
||||
contentWhenFalse = { ResultContent(uiState.value.isPairingSuccess, uiState.value.code, router, notificationManager) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -78,7 +77,8 @@ internal fun ResultContent(
|
||||
onScanAgainClick: () -> Unit = {},
|
||||
isSuccess: Boolean,
|
||||
code: Int? = null,
|
||||
modifier: Modifier
|
||||
router: SettingsRouter,
|
||||
notificationManager: NotificationManager,
|
||||
) {
|
||||
val image = if (isSuccess) R.drawable.browser_extension_success_image else R.drawable.browser_extension_error_image
|
||||
|
||||
@ -96,12 +96,18 @@ internal fun ResultContent(
|
||||
|
||||
val cta = if (isSuccess) R.string.commons__continue else R.string.browser__result_error_cta
|
||||
|
||||
val ctaAction: () -> Unit = {
|
||||
if (isSuccess) {
|
||||
onContinueClick()
|
||||
val ctaAction: () -> Unit = if (isSuccess) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (notificationManager.areNotificationsEnabled()) {
|
||||
{ router.navigate(SettingsDirections.GoBack) }
|
||||
} else {
|
||||
{ router.navigate(SettingsDirections.Permission) }
|
||||
}
|
||||
} else {
|
||||
onScanAgainClick()
|
||||
{ router.navigate(SettingsDirections.GoBack) }
|
||||
}
|
||||
} else {
|
||||
{ router.navigate(SettingsDirections.PairingScan) }
|
||||
}
|
||||
ConstraintLayout(
|
||||
modifier = modifier
|
||||
|
@ -16,6 +16,7 @@ class PairingProgressViewModel(
|
||||
private val dispatchers: Dispatchers,
|
||||
private val registerMobileDeviceCase: RegisterMobileDeviceCase,
|
||||
private val pairBrowserCase: PairBrowserCase,
|
||||
private val notificationsPermissionRequestFlow: NotificationsPermissionRequestFlow,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(PairingProgressUiState())
|
||||
|
@ -79,7 +79,7 @@ class BrowserExtensionRequestActivity : BaseComponentActivity() {
|
||||
item { HeaderItem(browserName = uiState.browserName, payload.domain, modifier = Modifier.animateItemPlacement()) }
|
||||
|
||||
if (uiState.suggestedServices.isNotEmpty()) {
|
||||
item { SectionItem(title = "Suggested", modifier = Modifier.animateItemPlacement()) }
|
||||
item { SectionItem(title = stringResource(id = R.string.extension__services_suggested_header), modifier = Modifier.animateItemPlacement()) }
|
||||
items(uiState.suggestedServices, key = { it.id }) {
|
||||
|
||||
ServiceItem(
|
||||
@ -94,7 +94,13 @@ class BrowserExtensionRequestActivity : BaseComponentActivity() {
|
||||
if (uiState.otherServices.isNotEmpty()) {
|
||||
item {
|
||||
SectionItem(
|
||||
title = if (uiState.suggestedServices.isEmpty()) "All services" else "Other services",
|
||||
title = stringResource(
|
||||
id = if (uiState.suggestedServices.isEmpty()) {
|
||||
R.string.extension__services_all_header
|
||||
} else {
|
||||
R.string.extension__services_other_header
|
||||
}
|
||||
),
|
||||
modifier = Modifier.animateItemPlacement()
|
||||
)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ object AppConfig {
|
||||
|
||||
private const val verMajor = 4
|
||||
private const val verMinor = 2
|
||||
private const val verPatch = 2
|
||||
private const val verPatch = 3
|
||||
private const val verInternal = 0
|
||||
|
||||
const val versionCode = verMajor * 1000000 + verMinor * 10000 + verPatch * 100 + verInternal
|
||||
|
@ -26,6 +26,7 @@ accompanistPlaceholder = { module = "com.google.accompanist:accompanist-placehol
|
||||
accompanistSystemUi = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
|
||||
accompanistPager = { module = "com.google.accompanist:accompanist-pager", version.ref = "accompanist" }
|
||||
accompanistPagerIndicators = { module = "com.google.accompanist:accompanist-pager-indicators", version.ref = "accompanist" }
|
||||
accompanistPermissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
||||
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
|
||||
coilCompose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
|
||||
composeActivity = { module = "androidx.activity:activity-compose", version.ref = "composeActivity" }
|
||||
@ -153,6 +154,7 @@ accompanist = [
|
||||
"accompanistSystemUi",
|
||||
"accompanistPager",
|
||||
"accompanistPagerIndicators",
|
||||
"accompanistPermissions"
|
||||
]
|
||||
coil = [
|
||||
"coil",
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.twofasapp.permissions
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.twofasapp.permissions.internal.PermissionRequest
|
||||
import com.twofasapp.permissions.internal.PermissionRequestFlow
|
||||
|
||||
class NotificationsPermissionRequestFlow(activity: Activity) : PermissionRequestFlow(activity) {
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
override val permission: String = Manifest.permission.POST_NOTIFICATIONS
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="560dp"
|
||||
android:height="400dp"
|
||||
android:viewportWidth="560"
|
||||
android:viewportHeight="400">
|
||||
<path
|
||||
android:pathData="M475.5,22H155.5C143.07,22 133,32.07 133,44.5C133,56.93 143.07,67 155.5,67H475.5C487.93,67 498,56.93 498,44.5C498,32.07 487.93,22 475.5,22Z"
|
||||
android:fillColor="#A50006"/>
|
||||
<path
|
||||
android:pathData="M27,375V87C27,60.49 48.49,39 75,39H415C441.51,39 463,60.49 463,87V132.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M463,377.5V312"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M379,83.67H136.67C121.94,83.67 110,71.73 110,57"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M245,67C247.76,67 250,64.76 250,62C250,59.24 247.76,57 245,57C242.24,57 240,59.24 240,62C240,64.76 242.24,67 245,67Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M490.49,235H242.1C232.66,235 225,242.65 225,252.1C225,261.54 232.66,269.19 242.1,269.19H490.49C499.93,269.19 507.59,261.54 507.59,252.1C507.59,242.65 499.93,235 490.49,235Z"
|
||||
android:fillColor="#FF8095"/>
|
||||
<path
|
||||
android:pathData="M210,184.37C210,183.15 210.94,182.17 212.16,182.17C213.38,182.17 214.36,183.14 214.36,184.37V185.31C215.58,183.55 217.35,182 220.3,182C224.58,182 227.07,184.88 227.07,189.27V199.42C227.07,200.64 226.13,201.58 224.91,201.58C223.69,201.58 222.71,200.64 222.71,199.42V190.6C222.71,187.65 221.24,185.96 218.64,185.96C216.04,185.96 214.36,187.72 214.36,190.68V199.43C214.36,200.65 213.39,201.59 212.16,201.59C210.93,201.59 210,200.65 210,199.43V184.38V184.37Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M231,192V191.93C231,186.49 235.32,182 241.15,182C246.98,182 251.27,186.43 251.27,191.86V191.93C251.27,197.33 246.95,201.83 241.08,201.83C235.21,201.83 231,197.4 231,192ZM246.91,192V191.93C246.91,188.58 244.5,185.81 241.08,185.81C237.66,185.81 235.36,188.55 235.36,191.86V191.93C235.36,195.24 237.77,198.01 241.15,198.01C244.53,198.01 246.91,195.27 246.91,192Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M256.59,196.15V186.14H255.87C254.83,186.14 254,185.31 254,184.27C254,183.23 254.83,182.4 255.87,182.4H256.59V179.16C256.59,177.97 257.56,177 258.79,177C260.02,177 260.95,177.97 260.95,179.16V182.4H264.37C265.41,182.4 266.28,183.23 266.28,184.27C266.28,185.31 265.42,186.14 264.37,186.14H260.95V195.46C260.95,197.15 261.81,197.84 263.29,197.84C263.79,197.84 264.23,197.73 264.37,197.73C265.34,197.73 266.2,198.52 266.2,199.53C266.2,200.32 265.66,200.97 265.05,201.22C264.11,201.54 263.21,201.72 262.06,201.72C258.86,201.72 256.59,200.32 256.59,196.14V196.15Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M271,177.12C271,175.82 272.08,175 273.48,175C274.88,175 275.96,175.83 275.96,177.12V177.34C275.96,178.64 274.88,179.5 273.48,179.5C272.08,179.5 271,178.64 271,177.34V177.12ZM271.32,184.21C271.32,182.99 272.26,182.01 273.48,182.01C274.7,182.01 275.68,182.98 275.68,184.21V199.26C275.68,200.48 274.71,201.42 273.48,201.42C272.25,201.42 271.32,200.48 271.32,199.26V184.21Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M281.6,186.23H280.84C279.83,186.23 279,185.44 279,184.43C279,183.42 279.83,182.59 280.84,182.59H281.6V181.19C281.6,179.1 282.14,177.52 283.15,176.51C284.16,175.5 285.56,175 287.43,175C288.3,175 289.01,175.07 289.63,175.18C290.42,175.29 291.14,176.01 291.14,176.98C291.14,177.95 290.31,178.82 289.31,178.78C289.06,178.74 288.7,178.71 288.41,178.71C286.75,178.71 285.89,179.61 285.89,181.59V182.63H289.27C290.31,182.63 291.11,183.42 291.11,184.43C291.11,185.44 290.28,186.23 289.27,186.23H285.96V199.51C285.96,200.7 284.99,201.67 283.76,201.67C282.53,201.67 281.6,200.7 281.6,199.51V186.23ZM294.09,177.38C294.09,176.08 295.17,175.26 296.57,175.26C297.97,175.26 299.05,176.09 299.05,177.38V177.6C299.05,178.9 297.97,179.76 296.57,179.76C295.17,179.76 294.09,178.9 294.09,177.6V177.38ZM294.41,184.47C294.41,183.25 295.35,182.27 296.57,182.27C297.79,182.27 298.77,183.24 298.77,184.47V199.52C298.77,200.74 297.8,201.68 296.57,201.68C295.34,201.68 294.41,200.74 294.41,199.52V184.47Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M304,192V191.93C304,186.53 308.17,182 313.9,182C316.89,182 318.94,182.97 320.56,184.38C320.85,184.63 321.24,185.17 321.24,185.89C321.24,187.01 320.34,187.87 319.22,187.87C318.68,187.87 318.21,187.65 317.93,187.44C316.81,186.5 315.59,185.82 313.86,185.82C310.69,185.82 308.35,188.56 308.35,191.87V191.94C308.35,195.32 310.69,198.02 314.04,198.02C315.77,198.02 317.1,197.34 318.29,196.33C318.54,196.11 318.97,195.86 319.48,195.86C320.52,195.86 321.35,196.72 321.35,197.77C321.35,198.35 321.13,198.81 320.74,199.14C319.05,200.76 317,201.84 313.83,201.84C308.18,201.84 304,197.41 304,192.01V192Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M324,195.79V195.72C324,191.62 327.2,189.6 331.85,189.6C333.97,189.6 335.49,189.92 336.96,190.39V189.92C336.96,187.22 335.3,185.78 332.25,185.78C330.59,185.78 329.23,186.07 328.04,186.54C327.79,186.61 327.57,186.65 327.36,186.65C326.35,186.65 325.53,185.86 325.53,184.85C325.53,184.06 326.07,183.37 326.72,183.12C328.52,182.44 330.35,182 332.84,182C335.68,182 337.81,182.76 339.14,184.12C340.54,185.49 341.19,187.5 341.19,189.99V199.35C341.19,200.54 340.25,201.44 339.07,201.44C337.81,201.44 336.95,200.58 336.95,199.6V198.88C335.65,200.43 333.67,201.65 330.76,201.65C327.2,201.65 324.03,199.6 324.03,195.78L324,195.79ZM337.03,194.42V193.12C335.91,192.69 334.44,192.36 332.71,192.36C329.9,192.36 328.25,193.55 328.25,195.53V195.6C328.25,197.44 329.87,198.48 331.96,198.48C334.84,198.48 337.04,196.82 337.04,194.41L337.03,194.42Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M347.59,196.15V186.14H346.87C345.83,186.14 345,185.31 345,184.27C345,183.23 345.83,182.4 346.87,182.4H347.59V179.16C347.59,177.97 348.56,177 349.79,177C351.02,177 351.95,177.97 351.95,179.16V182.4H355.37C356.41,182.4 357.28,183.23 357.28,184.27C357.28,185.31 356.42,186.14 355.37,186.14H351.95V195.46C351.95,197.15 352.81,197.84 354.29,197.84C354.79,197.84 355.23,197.73 355.37,197.73C356.34,197.73 357.21,198.52 357.21,199.53C357.21,200.32 356.67,200.97 356.06,201.22C355.12,201.54 354.23,201.72 353.07,201.72C349.87,201.72 347.6,200.32 347.6,196.14L347.59,196.15Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M361,177.12C361,175.82 362.08,175 363.48,175C364.88,175 365.96,175.83 365.96,177.12V177.34C365.96,178.64 364.88,179.5 363.48,179.5C362.08,179.5 361,178.64 361,177.34V177.12ZM361.32,184.21C361.32,182.99 362.26,182.01 363.48,182.01C364.7,182.01 365.68,182.98 365.68,184.21V199.26C365.68,200.48 364.71,201.42 363.48,201.42C362.25,201.42 361.32,200.48 361.32,199.26V184.21Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M370.01,192V191.93C370.01,186.49 374.33,182 380.16,182C385.99,182 390.27,186.43 390.27,191.86V191.93C390.27,197.33 385.95,201.83 380.08,201.83C374.21,201.83 370,197.4 370,192H370.01ZM385.92,192V191.93C385.92,188.58 383.51,185.81 380.09,185.81C376.67,185.81 374.37,188.55 374.37,191.86V191.93C374.37,195.24 376.78,198.01 380.16,198.01C383.54,198.01 385.92,195.27 385.92,192Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M395,184.37C395,183.15 395.94,182.17 397.16,182.17C398.38,182.17 399.36,183.14 399.36,184.37V185.31C400.58,183.55 402.35,182 405.3,182C409.58,182 412.07,184.88 412.07,189.27V199.42C412.07,200.64 411.13,201.58 409.91,201.58C408.69,201.58 407.71,200.64 407.71,199.42V190.6C407.71,187.65 406.24,185.96 403.64,185.96C401.04,185.96 399.36,187.72 399.36,190.68V199.43C399.36,200.65 398.39,201.59 397.16,201.59C395.93,201.59 395,200.65 395,199.43V184.38V184.37Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M102.64,150H501C518.67,150 533,164.33 533,182V257C533,274.67 518.67,289 501,289H83C65.33,289 51,274.67 51,257V182C51,178 51.73,174.18 53.07,170.65"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M172.04,283.55L148.02,301.25C143.63,304.49 137.63,304.49 133.24,301.25L109.22,283.55C100.28,276.96 95,266.52 95,255.41V202.1C95,198.61 97.26,195.52 100.6,194.47L121.02,188.02C133.79,183.99 147.48,183.99 160.25,188.02L180.67,194.47C184,195.52 186.27,198.61 186.27,202.1V255.41C186.27,266.52 180.99,276.96 172.05,283.55H172.04Z"
|
||||
android:fillColor="#ED1B24"/>
|
||||
<path
|
||||
android:pathData="M154.01,229C154.01,221.84 148.22,216.03 141.07,216C133.87,215.97 128,221.81 128,229C128,233.78 130.58,237.96 134.43,240.22C135.05,240.58 135.37,241.3 135.2,241.99L132.02,255.38C131.78,256.39 132.55,257.37 133.59,257.37H148.42C149.46,257.37 150.23,256.4 149.99,255.38L146.81,241.99C146.64,241.29 146.96,240.58 147.58,240.22C151.42,237.96 154,233.79 154,229.01L154.01,229Z"
|
||||
android:fillColor="#ED1B24"/>
|
||||
<path
|
||||
android:pathData="M145.89,229.45C145.89,221.5 139.46,215.04 131.52,215C123.52,214.96 117,221.45 117,229.45C117,234.76 119.87,239.4 124.14,241.91C124.83,242.31 125.18,243.11 125,243.88L121.47,258.76C121.2,259.89 122.06,260.97 123.21,260.97H139.69C140.85,260.97 141.7,259.89 141.43,258.76L137.9,243.88C137.72,243.11 138.07,242.31 138.76,241.91C143.03,239.4 145.9,234.76 145.9,229.45H145.89Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M160.04,277.55L136.02,295.25C131.63,298.49 125.63,298.49 121.24,295.25L97.22,277.55C88.28,270.96 83,260.52 83,249.41V196.1C83,192.61 85.26,189.52 88.6,188.47L109.02,182.02C121.79,177.99 135.48,177.99 148.25,182.02L168.67,188.47C172,189.52 174.27,192.61 174.27,196.1V249.41C174.27,260.52 168.99,270.96 160.05,277.55H160.04Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M142.01,223C142.01,215.84 136.22,210.03 129.07,210C121.92,209.97 116,215.81 116,223C116,227.78 118.58,231.96 122.43,234.22C123.05,234.58 123.37,235.3 123.2,235.99L120.02,249.38C119.78,250.39 120.55,251.37 121.59,251.37H136.42C137.46,251.37 138.23,250.4 137.99,249.38L134.81,235.99C134.64,235.29 134.96,234.58 135.58,234.22C139.42,231.96 142,227.79 142,223.01L142.01,223Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M505.59,219H226.1C221.38,219 217.11,220.91 214.01,224.01C210.92,227.1 209,231.38 209,236.1C209,242.28 212.28,247.7 217.2,250.7C219.79,252.29 222.84,253.2 226.09,253.2H329.75H328.58"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M486,311.67H76.67C61.94,311.67 50,299.73 50,285"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
@ -0,0 +1,117 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="560dp"
|
||||
android:height="400dp"
|
||||
android:viewportWidth="560"
|
||||
android:viewportHeight="400">
|
||||
<path
|
||||
android:pathData="M475.5,22H155.5C143.07,22 133,32.07 133,44.5C133,56.93 143.07,67 155.5,67H475.5C487.93,67 498,56.93 498,44.5C498,32.07 487.93,22 475.5,22Z"
|
||||
android:fillColor="#A50006"/>
|
||||
<path
|
||||
android:pathData="M27,375V87C27,60.49 48.49,39 75,39H415C441.51,39 463,60.49 463,87V132.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M463,377.5V312"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M379,83.67H136.67C121.94,83.67 110,71.73 110,57"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M245,67C247.76,67 250,64.76 250,62C250,59.24 247.76,57 245,57C242.24,57 240,59.24 240,62C240,64.76 242.24,67 245,67Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M490.49,235H242.1C232.66,235 225,242.65 225,252.1C225,261.54 232.66,269.19 242.1,269.19H490.49C499.93,269.19 507.59,261.54 507.59,252.1C507.59,242.65 499.93,235 490.49,235Z"
|
||||
android:fillColor="#FF8095"/>
|
||||
<path
|
||||
android:pathData="M210,184.37C210,183.15 210.94,182.17 212.16,182.17C213.38,182.17 214.36,183.14 214.36,184.37V185.31C215.58,183.55 217.35,182 220.3,182C224.58,182 227.07,184.88 227.07,189.27V199.42C227.07,200.64 226.13,201.58 224.91,201.58C223.69,201.58 222.71,200.64 222.71,199.42V190.6C222.71,187.65 221.24,185.96 218.64,185.96C216.04,185.96 214.36,187.72 214.36,190.68V199.43C214.36,200.65 213.39,201.59 212.16,201.59C210.93,201.59 210,200.65 210,199.43V184.38V184.37Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M231,192V191.93C231,186.49 235.32,182 241.15,182C246.98,182 251.27,186.43 251.27,191.86V191.93C251.27,197.33 246.95,201.83 241.08,201.83C235.21,201.83 231,197.4 231,192ZM246.91,192V191.93C246.91,188.58 244.5,185.81 241.08,185.81C237.66,185.81 235.36,188.55 235.36,191.86V191.93C235.36,195.24 237.77,198.01 241.15,198.01C244.53,198.01 246.91,195.27 246.91,192Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M256.59,196.15V186.14H255.87C254.83,186.14 254,185.31 254,184.27C254,183.23 254.83,182.4 255.87,182.4H256.59V179.16C256.59,177.97 257.56,177 258.79,177C260.02,177 260.95,177.97 260.95,179.16V182.4H264.37C265.41,182.4 266.28,183.23 266.28,184.27C266.28,185.31 265.42,186.14 264.37,186.14H260.95V195.46C260.95,197.15 261.81,197.84 263.29,197.84C263.79,197.84 264.23,197.73 264.37,197.73C265.34,197.73 266.2,198.52 266.2,199.53C266.2,200.32 265.66,200.97 265.05,201.22C264.11,201.54 263.21,201.72 262.06,201.72C258.86,201.72 256.59,200.32 256.59,196.14V196.15Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M271,177.12C271,175.82 272.08,175 273.48,175C274.88,175 275.96,175.83 275.96,177.12V177.34C275.96,178.64 274.88,179.5 273.48,179.5C272.08,179.5 271,178.64 271,177.34V177.12ZM271.32,184.21C271.32,182.99 272.26,182.01 273.48,182.01C274.7,182.01 275.68,182.98 275.68,184.21V199.26C275.68,200.48 274.71,201.42 273.48,201.42C272.25,201.42 271.32,200.48 271.32,199.26V184.21Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M281.6,186.23H280.84C279.83,186.23 279,185.44 279,184.43C279,183.42 279.83,182.59 280.84,182.59H281.6V181.19C281.6,179.1 282.14,177.52 283.15,176.51C284.16,175.5 285.56,175 287.43,175C288.3,175 289.01,175.07 289.63,175.18C290.42,175.29 291.14,176.01 291.14,176.98C291.14,177.95 290.31,178.82 289.31,178.78C289.06,178.74 288.7,178.71 288.41,178.71C286.75,178.71 285.89,179.61 285.89,181.59V182.63H289.27C290.31,182.63 291.11,183.42 291.11,184.43C291.11,185.44 290.28,186.23 289.27,186.23H285.96V199.51C285.96,200.7 284.99,201.67 283.76,201.67C282.53,201.67 281.6,200.7 281.6,199.51V186.23ZM294.09,177.38C294.09,176.08 295.17,175.26 296.57,175.26C297.97,175.26 299.05,176.09 299.05,177.38V177.6C299.05,178.9 297.97,179.76 296.57,179.76C295.17,179.76 294.09,178.9 294.09,177.6V177.38ZM294.41,184.47C294.41,183.25 295.35,182.27 296.57,182.27C297.79,182.27 298.77,183.24 298.77,184.47V199.52C298.77,200.74 297.8,201.68 296.57,201.68C295.34,201.68 294.41,200.74 294.41,199.52V184.47Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M304,192V191.93C304,186.53 308.17,182 313.9,182C316.89,182 318.94,182.97 320.56,184.38C320.85,184.63 321.24,185.17 321.24,185.89C321.24,187.01 320.34,187.87 319.22,187.87C318.68,187.87 318.21,187.65 317.93,187.44C316.81,186.5 315.59,185.82 313.86,185.82C310.69,185.82 308.35,188.56 308.35,191.87V191.94C308.35,195.32 310.69,198.02 314.04,198.02C315.77,198.02 317.1,197.34 318.29,196.33C318.54,196.11 318.97,195.86 319.48,195.86C320.52,195.86 321.35,196.72 321.35,197.77C321.35,198.35 321.13,198.81 320.74,199.14C319.05,200.76 317,201.84 313.83,201.84C308.18,201.84 304,197.41 304,192.01V192Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M324,195.79V195.72C324,191.62 327.2,189.6 331.85,189.6C333.97,189.6 335.49,189.92 336.96,190.39V189.92C336.96,187.22 335.3,185.78 332.25,185.78C330.59,185.78 329.23,186.07 328.04,186.54C327.79,186.61 327.57,186.65 327.36,186.65C326.35,186.65 325.53,185.86 325.53,184.85C325.53,184.06 326.07,183.37 326.72,183.12C328.52,182.44 330.35,182 332.84,182C335.68,182 337.81,182.76 339.14,184.12C340.54,185.49 341.19,187.5 341.19,189.99V199.35C341.19,200.54 340.25,201.44 339.07,201.44C337.81,201.44 336.95,200.58 336.95,199.6V198.88C335.65,200.43 333.67,201.65 330.76,201.65C327.2,201.65 324.03,199.6 324.03,195.78L324,195.79ZM337.03,194.42V193.12C335.91,192.69 334.44,192.36 332.71,192.36C329.9,192.36 328.25,193.55 328.25,195.53V195.6C328.25,197.44 329.87,198.48 331.96,198.48C334.84,198.48 337.04,196.82 337.04,194.41L337.03,194.42Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M347.59,196.15V186.14H346.87C345.83,186.14 345,185.31 345,184.27C345,183.23 345.83,182.4 346.87,182.4H347.59V179.16C347.59,177.97 348.56,177 349.79,177C351.02,177 351.95,177.97 351.95,179.16V182.4H355.37C356.41,182.4 357.28,183.23 357.28,184.27C357.28,185.31 356.42,186.14 355.37,186.14H351.95V195.46C351.95,197.15 352.81,197.84 354.29,197.84C354.79,197.84 355.23,197.73 355.37,197.73C356.34,197.73 357.21,198.52 357.21,199.53C357.21,200.32 356.67,200.97 356.06,201.22C355.12,201.54 354.23,201.72 353.07,201.72C349.87,201.72 347.6,200.32 347.6,196.14L347.59,196.15Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M361,177.12C361,175.82 362.08,175 363.48,175C364.88,175 365.96,175.83 365.96,177.12V177.34C365.96,178.64 364.88,179.5 363.48,179.5C362.08,179.5 361,178.64 361,177.34V177.12ZM361.32,184.21C361.32,182.99 362.26,182.01 363.48,182.01C364.7,182.01 365.68,182.98 365.68,184.21V199.26C365.68,200.48 364.71,201.42 363.48,201.42C362.25,201.42 361.32,200.48 361.32,199.26V184.21Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M370.01,192V191.93C370.01,186.49 374.33,182 380.16,182C385.99,182 390.27,186.43 390.27,191.86V191.93C390.27,197.33 385.95,201.83 380.08,201.83C374.21,201.83 370,197.4 370,192H370.01ZM385.92,192V191.93C385.92,188.58 383.51,185.81 380.09,185.81C376.67,185.81 374.37,188.55 374.37,191.86V191.93C374.37,195.24 376.78,198.01 380.16,198.01C383.54,198.01 385.92,195.27 385.92,192Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M395,184.37C395,183.15 395.94,182.17 397.16,182.17C398.38,182.17 399.36,183.14 399.36,184.37V185.31C400.58,183.55 402.35,182 405.3,182C409.58,182 412.07,184.88 412.07,189.27V199.42C412.07,200.64 411.13,201.58 409.91,201.58C408.69,201.58 407.71,200.64 407.71,199.42V190.6C407.71,187.65 406.24,185.96 403.64,185.96C401.04,185.96 399.36,187.72 399.36,190.68V199.43C399.36,200.65 398.39,201.59 397.16,201.59C395.93,201.59 395,200.65 395,199.43V184.38V184.37Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M102.64,150H501C518.67,150 533,164.33 533,182V257C533,274.67 518.67,289 501,289H83C65.33,289 51,274.67 51,257V182C51,178 51.73,174.18 53.07,170.65"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M172.04,283.55L148.02,301.25C143.63,304.49 137.63,304.49 133.24,301.25L109.22,283.55C100.28,276.96 95,266.52 95,255.41V202.1C95,198.61 97.26,195.52 100.6,194.47L121.02,188.02C133.79,183.99 147.48,183.99 160.25,188.02L180.67,194.47C184,195.52 186.27,198.61 186.27,202.1V255.41C186.27,266.52 180.99,276.96 172.05,283.55H172.04Z"
|
||||
android:fillColor="#ED1B24"/>
|
||||
<path
|
||||
android:pathData="M154.01,229C154.01,221.84 148.22,216.03 141.07,216C133.87,215.97 128,221.81 128,229C128,233.78 130.58,237.96 134.43,240.22C135.05,240.58 135.37,241.3 135.2,241.99L132.02,255.38C131.78,256.39 132.55,257.37 133.59,257.37H148.42C149.46,257.37 150.23,256.4 149.99,255.38L146.81,241.99C146.64,241.29 146.96,240.58 147.58,240.22C151.42,237.96 154,233.79 154,229.01L154.01,229Z"
|
||||
android:fillColor="#ED1B24"/>
|
||||
<path
|
||||
android:pathData="M145.89,229.45C145.89,221.5 139.46,215.04 131.52,215C123.52,214.96 117,221.45 117,229.45C117,234.76 119.87,239.4 124.14,241.91C124.83,242.31 125.18,243.11 125,243.88L121.47,258.76C121.2,259.89 122.06,260.97 123.21,260.97H139.69C140.85,260.97 141.7,259.89 141.43,258.76L137.9,243.88C137.72,243.11 138.07,242.31 138.76,241.91C143.03,239.4 145.9,234.76 145.9,229.45H145.89Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M160.04,277.55L136.02,295.25C131.63,298.49 125.63,298.49 121.24,295.25L97.22,277.55C88.28,270.96 83,260.52 83,249.41V196.1C83,192.61 85.26,189.52 88.6,188.47L109.02,182.02C121.79,177.99 135.48,177.99 148.25,182.02L168.67,188.47C172,189.52 174.27,192.61 174.27,196.1V249.41C174.27,260.52 168.99,270.96 160.05,277.55H160.04Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M142.01,223C142.01,215.84 136.22,210.03 129.07,210C121.92,209.97 116,215.81 116,223C116,227.78 118.58,231.96 122.43,234.22C123.05,234.58 123.37,235.3 123.2,235.99L120.02,249.38C119.78,250.39 120.55,251.37 121.59,251.37H136.42C137.46,251.37 138.23,250.4 137.99,249.38L134.81,235.99C134.64,235.29 134.96,234.58 135.58,234.22C139.42,231.96 142,227.79 142,223.01L142.01,223Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M505.59,219H226.1C221.38,219 217.11,220.91 214.01,224.01C210.92,227.1 209,231.38 209,236.1C209,242.28 212.28,247.7 217.2,250.7C219.79,252.29 222.84,253.2 226.09,253.2H329.75H328.58"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M486,311.67H76.67C61.94,311.67 50,299.73 50,285"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
@ -3,7 +3,14 @@ package com.twofasapp.services.ui.badge
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
@ -14,6 +21,7 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.twofasapp.design.compose.dialogs.internal.BaseDialog
|
||||
import com.twofasapp.design.theme.textPrimary
|
||||
@ -59,7 +67,19 @@ internal fun ColorBadgeDialog(
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
|
||||
Text(
|
||||
text = it.displayName,
|
||||
stringResource(
|
||||
id = when (it) {
|
||||
Tint.Default -> com.twofasapp.resources.R.string.color__neutral
|
||||
Tint.LightBlue -> com.twofasapp.resources.R.string.color__light_blue
|
||||
Tint.Indigo -> com.twofasapp.resources.R.string.color__indigo
|
||||
Tint.Purple -> com.twofasapp.resources.R.string.color__purple
|
||||
Tint.Turquoise -> com.twofasapp.resources.R.string.color__turquoise
|
||||
Tint.Green -> com.twofasapp.resources.R.string.color__green
|
||||
Tint.Red -> com.twofasapp.resources.R.string.color__red
|
||||
Tint.Orange -> com.twofasapp.resources.R.string.color__orange
|
||||
Tint.Yellow -> com.twofasapp.resources.R.string.color__yellow
|
||||
}
|
||||
),
|
||||
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.textPrimary),
|
||||
modifier = Modifier
|
||||
.align(CenterVertically)
|
||||
|
@ -75,7 +75,7 @@ internal fun ChangeBrandScreen(
|
||||
topBar = {
|
||||
ToolbarWithSearch(
|
||||
title = stringResource(id = R.string.customization_change_brand),
|
||||
searchHint = "Search",
|
||||
searchHint = stringResource(id = R.string.commons__search),
|
||||
onSearchValueChanged = { brandViewModel.applySearchFilter(it) }
|
||||
) { router.navigateBack() }
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ internal fun ChangeLabelScreen(
|
||||
Toolbar(title = stringResource(id = R.string.customization_edit_label), actions = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
viewModel.updateLabel(labelText.value.uppercase(), labelTint.value?: Tint.LightBlue)
|
||||
viewModel.updateLabel(labelText.value.uppercase(), labelTint.value ?: Tint.LightBlue)
|
||||
router.navigateBack()
|
||||
},
|
||||
enabled = labelText.value.isNotBlank() && labelText.value.isNotEmpty()
|
||||
@ -85,7 +85,7 @@ internal fun ChangeLabelScreen(
|
||||
Box(modifier = Modifier.padding(24.dp)) {
|
||||
TextFieldOutlined(
|
||||
value = labelText.value,
|
||||
label = { Text(text = "Label (1 or 2 characters)") },
|
||||
label = { Text(text = stringResource(id = R.string.tokens__label_characters_title)) },
|
||||
maxChars = 2,
|
||||
onValueChange = { labelText.value = it.uppercase() },
|
||||
keyboardOptions = KeyboardOptions.Default.copy(capitalization = KeyboardCapitalization.Characters),
|
||||
@ -112,7 +112,19 @@ internal fun ChangeLabelScreen(
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = it.displayName,
|
||||
stringResource(
|
||||
id = when (it) {
|
||||
Tint.Default -> com.twofasapp.resources.R.string.color__neutral
|
||||
Tint.LightBlue -> com.twofasapp.resources.R.string.color__light_blue
|
||||
Tint.Indigo -> com.twofasapp.resources.R.string.color__indigo
|
||||
Tint.Purple -> com.twofasapp.resources.R.string.color__purple
|
||||
Tint.Turquoise -> com.twofasapp.resources.R.string.color__turquoise
|
||||
Tint.Green -> com.twofasapp.resources.R.string.color__green
|
||||
Tint.Red -> com.twofasapp.resources.R.string.color__red
|
||||
Tint.Orange -> com.twofasapp.resources.R.string.color__orange
|
||||
Tint.Yellow -> com.twofasapp.resources.R.string.color__yellow
|
||||
}
|
||||
),
|
||||
style = MaterialTheme.typography.caption.copy(color = MaterialTheme.colors.textPrimary),
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterHorizontally)
|
||||
|
@ -23,7 +23,6 @@ import com.twofasapp.design.compose.Toolbar
|
||||
import com.twofasapp.design.compose.dialogs.ConfirmDialog
|
||||
import com.twofasapp.design.theme.divider
|
||||
import com.twofasapp.design.theme.textSecondary
|
||||
import com.twofasapp.navigation.ServiceDirections
|
||||
import com.twofasapp.navigation.ServiceRouter
|
||||
import com.twofasapp.resources.R
|
||||
import com.twofasapp.services.ui.ServiceViewModel
|
||||
@ -43,12 +42,12 @@ internal fun DomainAssignmentScreen(
|
||||
|
||||
Scaffold(
|
||||
topBar = { Toolbar(title = stringResource(id = R.string.browser__browser_extension)) { router.navigateBack() } }
|
||||
) {
|
||||
) { _ ->
|
||||
|
||||
if (showConfirmDialog.value) {
|
||||
ConfirmDialog(
|
||||
title = "Remove domain?",
|
||||
text = "The next time you use the browser extension to login to ${clickedDomainName.value}, you’ll be asked to pair this domain again.",
|
||||
title = stringResource(id = R.string.browser__deleting_extension_pairing_title),
|
||||
text = stringResource(id = R.string.browser__deleting_extension_pairing_content, clickedDomainName.value),
|
||||
onPositive = {
|
||||
showConfirmDialog.value = false
|
||||
viewModel.deleteDomainAssignment(clickedDomainName.value)
|
||||
@ -65,7 +64,7 @@ internal fun DomainAssignmentScreen(
|
||||
LazyColumn {
|
||||
item {
|
||||
Text(
|
||||
text = "List of paired domains.",
|
||||
text = stringResource(id = R.string.browser__paired_domains_list_title),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 72.dp, end = 16.dp, top = 24.dp, bottom = 24.dp),
|
||||
|
@ -135,11 +135,19 @@ internal fun ServiceScreen(
|
||||
}
|
||||
|
||||
Scaffold(topBar = {
|
||||
Toolbar(title = if (service.id == 0L) "Add service" else "Customize service", actions = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (service.id == 0L) {
|
||||
viewModel.tryInsertService(replaceIfExists = false)
|
||||
Toolbar(
|
||||
title = if (service.id == 0L) activity!!.getString(R.string.tokens__add_service_title) else activity!!.getString(R.string.tokens__customize_service_title),
|
||||
actions = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (service.id == 0L) {
|
||||
viewModel.tryInsertService(replaceIfExists = false)
|
||||
} else {
|
||||
viewModel.saveService()
|
||||
}
|
||||
},
|
||||
enabled = if (service.id == 0L) {
|
||||
uiState.isInputNameValid && uiState.isInputSecretValid && uiState.isInputInfoValid
|
||||
} else {
|
||||
viewModel.saveService()
|
||||
}
|
||||
@ -153,7 +161,7 @@ internal fun ServiceScreen(
|
||||
Text(text = stringResource(id = R.string.commons__save))
|
||||
}
|
||||
|
||||
}) {
|
||||
}) {
|
||||
activity?.onBackPressed()
|
||||
}
|
||||
}) { padding ->
|
||||
|
Loading…
Reference in New Issue
Block a user