mirror of
https://github.com/twofas/2fas-android.git
synced 2025-01-05 14:05:30 +01:00
Add notifications permission
This commit is contained in:
parent
7927edf99b
commit
43ad8d9114
@ -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" />
|
||||
|
@ -11,6 +11,7 @@ import com.twofasapp.environment.AppConfig
|
||||
import com.twofasapp.externalimport.domain.GoogleAuthenticatorImporter
|
||||
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
|
||||
@ -43,6 +44,7 @@ val applicationModule = module {
|
||||
|
||||
factory { CameraPermissionRequest(activityContext()) }
|
||||
factory { CameraPermissionRequestFlow(activityContext()) }
|
||||
factory { NotificationsPermissionRequestFlow(activityContext()) }
|
||||
|
||||
single<Dispatchers> { AppDispatchers() }
|
||||
|
||||
|
@ -6,6 +6,7 @@ import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.composable
|
||||
import com.twofasapp.browserextension.ui.browser.BrowserDetailsScreenFactory
|
||||
import com.twofasapp.browserextension.ui.main.BrowserExtensionScreenFactory
|
||||
import com.twofasapp.browserextension.ui.main.permission.BrowserExtensionPermissionScreenFactory
|
||||
import com.twofasapp.browserextension.ui.pairing.progress.PairingProgressScreenFactory
|
||||
import com.twofasapp.browserextension.ui.pairing.scan.PairingScanScreenFactory
|
||||
import com.twofasapp.settings.ui.main.SettingsMainScreenFactory
|
||||
@ -19,6 +20,7 @@ class SettingsRouterImpl(
|
||||
private val pairingProgressScreenFactory: PairingProgressScreenFactory,
|
||||
private val pairingScanScreenFactory: PairingScanScreenFactory,
|
||||
private val browserDetailsScreenFactory: BrowserDetailsScreenFactory,
|
||||
private val browserExtensionPermissionScreenFactory: BrowserExtensionPermissionScreenFactory,
|
||||
) : SettingsRouter() {
|
||||
|
||||
companion object {
|
||||
@ -29,6 +31,7 @@ class SettingsRouterImpl(
|
||||
private const val BROWSER_EXTENSION = "browser_extension"
|
||||
private const val BROWSER_DETAILS = "browser_details/{$ARG_EXTENSION_ID}"
|
||||
private const val PAIRING_SCAN = "pairing_scan"
|
||||
private const val PERMISSION = "permission"
|
||||
private const val PAIRING_PROGRESS = "pairing_progress/{$ARG_EXTENSION_ID}"
|
||||
}
|
||||
|
||||
@ -40,6 +43,7 @@ class SettingsRouterImpl(
|
||||
browserDetailsScreenFactory.create(it.arguments?.getString(ARG_EXTENSION_ID).orEmpty())
|
||||
})
|
||||
builder.composable(route = PAIRING_SCAN, content = { pairingScanScreenFactory.create() })
|
||||
builder.composable(route = PERMISSION, content = { browserExtensionPermissionScreenFactory.create() })
|
||||
builder.composable(route = PAIRING_PROGRESS, content = {
|
||||
pairingProgressScreenFactory.create(it.arguments?.getString(ARG_EXTENSION_ID).orEmpty())
|
||||
})
|
||||
@ -59,6 +63,7 @@ class SettingsRouterImpl(
|
||||
SettingsDirections.Theme -> navController.navigate(THEME)
|
||||
SettingsDirections.BrowserExtension -> navController.navigate(BROWSER_EXTENSION)
|
||||
SettingsDirections.PairingScan -> navController.navigate(PAIRING_SCAN) { popUpTo(BROWSER_EXTENSION) }
|
||||
SettingsDirections.Permission -> navController.navigate(PERMISSION) { popUpTo(BROWSER_EXTENSION) }
|
||||
|
||||
is SettingsDirections.PairingProgress -> navController.navigate(
|
||||
PAIRING_PROGRESS.replace("{$ARG_EXTENSION_ID}", direction.extensionId)
|
||||
|
@ -34,6 +34,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)
|
||||
|
@ -4,7 +4,20 @@ import com.twofasapp.browserextension.data.BrowserExtensionLocalData
|
||||
import com.twofasapp.browserextension.data.BrowserExtensionLocalDataImpl
|
||||
import com.twofasapp.browserextension.data.BrowserExtensionRemoteData
|
||||
import com.twofasapp.browserextension.data.BrowserExtensionRemoteDataImpl
|
||||
import com.twofasapp.browserextension.domain.*
|
||||
import com.twofasapp.browserextension.domain.ApproveLoginRequestCase
|
||||
import com.twofasapp.browserextension.domain.DeletePairedBrowserCase
|
||||
import com.twofasapp.browserextension.domain.DenyLoginRequestCase
|
||||
import com.twofasapp.browserextension.domain.EncryptCodeCase
|
||||
import com.twofasapp.browserextension.domain.FetchPairedBrowsersCase
|
||||
import com.twofasapp.browserextension.domain.FetchTokenRequestsCase
|
||||
import com.twofasapp.browserextension.domain.FetchTokenRequestsCaseImpl
|
||||
import com.twofasapp.browserextension.domain.ObserveMobileDeviceCase
|
||||
import com.twofasapp.browserextension.domain.ObserveMobileDeviceCaseImpl
|
||||
import com.twofasapp.browserextension.domain.ObservePairedBrowsersCase
|
||||
import com.twofasapp.browserextension.domain.ObservePairedBrowsersCaseImpl
|
||||
import com.twofasapp.browserextension.domain.PairBrowserCase
|
||||
import com.twofasapp.browserextension.domain.RegisterMobileDeviceCase
|
||||
import com.twofasapp.browserextension.domain.UpdateMobileDeviceCase
|
||||
import com.twofasapp.browserextension.domain.repository.BrowserExtensionRepository
|
||||
import com.twofasapp.browserextension.domain.repository.BrowserExtensionRepositoryImpl
|
||||
import com.twofasapp.browserextension.notification.ShowBrowserExtensionRequestNotificationCaseImpl
|
||||
@ -12,6 +25,8 @@ import com.twofasapp.browserextension.ui.browser.BrowserDetailsScreenFactory
|
||||
import com.twofasapp.browserextension.ui.browser.BrowserDetailsViewModel
|
||||
import com.twofasapp.browserextension.ui.main.BrowserExtensionScreenFactory
|
||||
import com.twofasapp.browserextension.ui.main.BrowserExtensionViewModel
|
||||
import com.twofasapp.browserextension.ui.main.permission.BrowserExtensionPermissionScreenFactory
|
||||
import com.twofasapp.browserextension.ui.main.permission.BrowserExtensionPermissionViewModel
|
||||
import com.twofasapp.browserextension.ui.pairing.progress.PairingProgressScreenFactory
|
||||
import com.twofasapp.browserextension.ui.pairing.progress.PairingProgressViewModel
|
||||
import com.twofasapp.browserextension.ui.pairing.scan.PairingScanScreenFactory
|
||||
@ -46,6 +61,7 @@ class BrowserExtensionModule : KoinModule {
|
||||
singleOf(::DeletePairedBrowserCase)
|
||||
|
||||
viewModelOf(::BrowserExtensionViewModel)
|
||||
viewModelOf(::BrowserExtensionPermissionViewModel)
|
||||
viewModelOf(::PairingScanViewModel)
|
||||
viewModelOf(::PairingProgressViewModel)
|
||||
viewModelOf(::BrowserExtensionRequestViewModel)
|
||||
@ -55,5 +71,6 @@ class BrowserExtensionModule : KoinModule {
|
||||
singleOf(::PairingProgressScreenFactory)
|
||||
singleOf(::PairingScanScreenFactory)
|
||||
singleOf(::BrowserDetailsScreenFactory)
|
||||
singleOf(::BrowserExtensionPermissionScreenFactory)
|
||||
}
|
||||
}
|
@ -1,16 +1,38 @@
|
||||
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.*
|
||||
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.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
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
|
||||
@ -22,25 +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 com.twofasapp.resources.R
|
||||
import com.twofasapp.design.compose.*
|
||||
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.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.get
|
||||
|
||||
@Composable
|
||||
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(),
|
||||
router: SettingsRouter = get()
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsState().value
|
||||
val scaffoldState = rememberScaffoldState()
|
||||
val scope = rememberCoroutineScope()
|
||||
var askForPermission by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
scaffoldState = scaffoldState,
|
||||
@ -49,17 +117,28 @@ internal fun BrowserExtensionScreen(
|
||||
if (uiState.isLoading) return@Scaffold
|
||||
|
||||
if (uiState.pairedBrowsers.isEmpty()) {
|
||||
EmptyScreen(viewModel, padding)
|
||||
EmptyScreen(router = router, padding = padding, onAddClick = { askForPermission = true })
|
||||
} else {
|
||||
ContentScreen(
|
||||
viewModel = viewModel,
|
||||
uiState = uiState,
|
||||
router = router,
|
||||
padding = padding
|
||||
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 -> {
|
||||
@ -73,32 +152,33 @@ internal fun BrowserExtensionScreen(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
internal fun ContentScreen(
|
||||
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 {
|
||||
HeaderEntry(text = stringResource(id = R.string.browser__paired_devices_browser_title))
|
||||
}
|
||||
|
||||
items(uiState.pairedBrowsers, key = { it.id }) {
|
||||
SimpleEntry(
|
||||
title = it.name,
|
||||
SimpleEntry(title = it.name,
|
||||
iconVisibleWhenNotSet = true,
|
||||
subtitle = it.formatPairedAt(),
|
||||
click = { router.navigate(SettingsDirections.BrowserDetails(extensionId = it.id)) }
|
||||
)
|
||||
click = { router.navigate(SettingsDirections.BrowserDetails(extensionId = it.id)) })
|
||||
}
|
||||
|
||||
item {
|
||||
Button(
|
||||
onClick = { viewModel.onPairBrowserClick() },
|
||||
shape = ButtonShape(),
|
||||
modifier = Modifier.padding(start = 72.dp, top = 6.dp, bottom = 2.dp)
|
||||
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())
|
||||
}
|
||||
@ -116,14 +196,30 @@ internal 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) {
|
||||
@ -140,28 +236,27 @@ internal fun ContentScreen(
|
||||
|
||||
@Composable
|
||||
internal fun EmptyScreen(
|
||||
viewModel: BrowserExtensionViewModel,
|
||||
router: SettingsRouter,
|
||||
padding: PaddingValues,
|
||||
onAddClick: () -> Unit,
|
||||
) {
|
||||
val activity = (LocalContext.current as? Activity)
|
||||
|
||||
ConstraintLayout(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)) {
|
||||
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)
|
||||
) {
|
||||
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,
|
||||
@ -184,28 +279,29 @@ internal fun EmptyScreen(
|
||||
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)
|
||||
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 = { viewModel.onPairBrowserClick() },
|
||||
shape = ButtonShape(),
|
||||
modifier = Modifier
|
||||
.height(48.dp)
|
||||
.constrainAs(pair) {
|
||||
bottom.linkTo(parent.bottom, margin = 16.dp)
|
||||
start.linkTo(parent.start)
|
||||
end.linkTo(parent.end)
|
||||
}) {
|
||||
|
||||
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 @@ internal 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,17 +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.navigation.SettingsDirections
|
||||
import com.twofasapp.navigation.SettingsRouter
|
||||
import com.twofasapp.permissions.CameraPermissionRequestFlow
|
||||
import com.twofasapp.permissions.PermissionStatus
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class BrowserExtensionViewModel(
|
||||
private val dispatchers: Dispatchers,
|
||||
private val settingsRouter: SettingsRouter,
|
||||
private val cameraPermissionRequest: CameraPermissionRequestFlow,
|
||||
private val observeMobileDeviceCase: ObserveMobileDeviceCase,
|
||||
private val observePairedBrowsersCase: ObservePairedBrowsersCase,
|
||||
private val updateMobileDeviceCase: UpdateMobileDeviceCase,
|
||||
@ -51,24 +49,6 @@ internal class BrowserExtensionViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun onPairBrowserClick() {
|
||||
cameraPermissionRequest.execute()
|
||||
.take(1)
|
||||
.onEach {
|
||||
when (it) {
|
||||
PermissionStatus.GRANTED -> settingsRouter.navigate(SettingsDirections.PairingScan)
|
||||
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,7 +1,14 @@
|
||||
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.*
|
||||
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
|
||||
@ -16,11 +23,19 @@ 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.airbnb.lottie.compose.*
|
||||
import com.twofasapp.resources.R
|
||||
import com.twofasapp.design.compose.*
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||
import com.airbnb.lottie.compose.LottieConstants
|
||||
import com.airbnb.lottie.compose.animateLottieCompositionAsState
|
||||
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||
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.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
|
||||
@ -28,6 +43,7 @@ internal fun PairingProgressScreen(
|
||||
extensionId: String,
|
||||
viewModel: PairingProgressViewModel = get(),
|
||||
router: SettingsRouter = get(),
|
||||
notificationManager: NotificationManager = get()
|
||||
) {
|
||||
val uiState = viewModel.uiState.collectAsState()
|
||||
viewModel.pairBrowser(extensionId)
|
||||
@ -42,7 +58,7 @@ internal fun PairingProgressScreen(
|
||||
AnimatedContent(
|
||||
condition = uiState.value.isPairing,
|
||||
contentWhenTrue = { ProgressContent() },
|
||||
contentWhenFalse = { ResultContent(uiState.value.isPairingSuccess, uiState.value.code, router) }
|
||||
contentWhenFalse = { ResultContent(uiState.value.isPairingSuccess, uiState.value.code, router, notificationManager) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -60,6 +76,7 @@ internal fun ResultContent(
|
||||
isSuccess: Boolean,
|
||||
code: Int? = null,
|
||||
router: SettingsRouter,
|
||||
notificationManager: NotificationManager,
|
||||
) {
|
||||
val image = if (isSuccess) R.drawable.browser_extension_success_image else R.drawable.browser_extension_error_image
|
||||
|
||||
@ -78,7 +95,15 @@ internal fun ResultContent(
|
||||
val cta = if (isSuccess) R.string.commons__continue else R.string.browser__result_error_cta
|
||||
|
||||
val ctaAction: () -> Unit = if (isSuccess) {
|
||||
{ router.navigate(SettingsDirections.GoBack) }
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (notificationManager.areNotificationsEnabled()) {
|
||||
{ router.navigate(SettingsDirections.GoBack) }
|
||||
} else {
|
||||
{ router.navigate(SettingsDirections.Permission) }
|
||||
}
|
||||
} else {
|
||||
{ router.navigate(SettingsDirections.GoBack) }
|
||||
}
|
||||
} else {
|
||||
{ router.navigate(SettingsDirections.PairingScan) }
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import com.twofasapp.base.dispatcher.Dispatchers
|
||||
import com.twofasapp.browserextension.domain.PairBrowserCase
|
||||
import com.twofasapp.browserextension.domain.RegisterMobileDeviceCase
|
||||
import com.twofasapp.network.exception.BrowserAlreadyPairedException
|
||||
import com.twofasapp.permissions.NotificationsPermissionRequestFlow
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@ -16,6 +17,7 @@ internal class PairingProgressViewModel(
|
||||
private val dispatchers: Dispatchers,
|
||||
private val registerMobileDeviceCase: RegisterMobileDeviceCase,
|
||||
private val pairBrowserCase: PairBrowserCase,
|
||||
private val notificationsPermissionRequestFlow: NotificationsPermissionRequestFlow,
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(PairingProgressUiState())
|
||||
|
@ -27,6 +27,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",
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.twofasapp.navigation
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.twofasapp.navigation.base.Directions
|
||||
|
||||
sealed interface SettingsDirections : Directions {
|
||||
@ -9,5 +11,6 @@ sealed interface SettingsDirections : Directions {
|
||||
object BrowserExtension : SettingsDirections
|
||||
class BrowserDetails(val extensionId: String) : SettingsDirections
|
||||
object PairingScan : SettingsDirections
|
||||
object Permission : SettingsDirections
|
||||
class PairingProgress(val extensionId: String) : SettingsDirections
|
||||
}
|
@ -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>
|
Loading…
Reference in New Issue
Block a user