Skip to content

Commit 5439b1d

Browse files
committed
Merge branch 'release/5.4.9' into main
2 parents 2725d5f + f42ec06 commit 5439b1d

147 files changed

Lines changed: 1610 additions & 296 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ android {
1515

1616
defaultConfig {
1717
applicationId = "com.twofasapp"
18-
versionName = "5.4.8"
19-
versionCode = 5000029
18+
versionName = "5.4.9"
19+
versionCode = 5000030
2020
}
2121

2222
applicationVariants.all {
@@ -62,6 +62,7 @@ dependencies {
6262
implementation(project(":base"))
6363
implementation(project(":prefs"))
6464
implementation(project(":truetime"))
65+
implementation(project(":secure-storage"))
6566
implementation(project(":parsers"))
6667

6768
implementation(libs.bundles.appCompat)
@@ -80,7 +81,6 @@ dependencies {
8081
implementation(libs.timber)
8182
implementation(libs.webkit)
8283
implementation(libs.securityCrypto)
83-
implementation(libs.secureStorage)
8484
implementation(libs.lottie)
8585
implementation(libs.kotlinCoroutines)
8686
implementation(libs.workManager)

app/src/debug/res/values/strings.xml

Lines changed: 0 additions & 3 deletions
This file was deleted.

app/src/main/java/com/twofasapp/ui/main/MainActivity.kt

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package com.twofasapp.ui.main
22

33
import android.content.Intent
4+
import android.content.res.Configuration
5+
import android.os.Build
46
import android.os.Bundle
7+
import androidx.activity.SystemBarStyle
58
import androidx.activity.compose.setContent
9+
import androidx.activity.enableEdgeToEdge
610
import androidx.appcompat.app.AppCompatActivity
11+
import androidx.compose.ui.graphics.Color
12+
import androidx.compose.ui.graphics.toArgb
713
import androidx.lifecycle.lifecycleScope
814
import com.google.android.material.snackbar.Snackbar
915
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
@@ -13,10 +19,12 @@ import com.google.android.play.core.install.model.InstallStatus
1319
import com.google.android.play.core.install.model.UpdateAvailability
1420
import com.twofasapp.base.lifecycle.AuthAware
1521
import com.twofasapp.base.lifecycle.AuthLifecycle
22+
import com.twofasapp.common.domain.SelectedTheme
1623
import com.twofasapp.data.services.ServicesRepository
1724
import com.twofasapp.data.session.SessionRepository
1825
import com.twofasapp.data.session.SettingsRepository
1926
import com.twofasapp.designsystem.AppThemeState
27+
import com.twofasapp.designsystem.MainAppTheme
2028
import com.twofasapp.designsystem.ktx.makeWindowSecure
2129
import com.twofasapp.designsystem.ktx.toastLong
2230
import kotlinx.coroutines.Job
@@ -45,15 +53,49 @@ class MainActivity : AppCompatActivity(), AuthAware {
4553
private var recalculateTimeJob: Job? = null
4654

4755
override fun onCreate(savedInstanceState: Bundle?) {
48-
AppThemeState.applyTheme(settingsRepository.getAppSettings().selectedTheme)
56+
val selectedTheme = settingsRepository.getAppSettings().selectedTheme
57+
AppThemeState.applyTheme(selectedTheme)
58+
enableEdgeToEdge(
59+
statusBarStyle = SystemBarStyle.auto(
60+
lightScrim = Color.Transparent.toArgb(),
61+
darkScrim = Color.Transparent.toArgb(),
62+
detectDarkMode = {
63+
when (selectedTheme) {
64+
SelectedTheme.Auto -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
65+
SelectedTheme.Light -> false
66+
SelectedTheme.Dark -> true
67+
}
68+
}
69+
),
70+
navigationBarStyle = SystemBarStyle.auto(
71+
lightScrim = Color.Transparent.toArgb(),
72+
darkScrim = Color.Transparent.toArgb(),
73+
detectDarkMode = {
74+
when (selectedTheme) {
75+
SelectedTheme.Auto -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
76+
SelectedTheme.Light -> false
77+
SelectedTheme.Dark -> true
78+
}
79+
}
80+
),
81+
)
82+
4983
super.onCreate(savedInstanceState)
5084
lifecycleScope.launch {
5185
settingsRepository.observeAppSettings().collect {
5286
makeWindowSecure(allow = it.allowScreenshots)
5387
}
5488
}
5589

56-
setContent { MainScreen() }
90+
setContent {
91+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
92+
window.isNavigationBarContrastEnforced = false
93+
}
94+
95+
MainAppTheme {
96+
MainScreen()
97+
}
98+
}
5799

58100
attachAuthLifecycleObserver()
59101
checkAppVersionUpdate()

app/src/main/java/com/twofasapp/ui/main/MainScreen.kt

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
package com.twofasapp.ui.main
22

3-
import androidx.compose.foundation.layout.fillMaxSize
43
import androidx.compose.material.ExperimentalMaterialApi
54
import androidx.compose.material.ModalBottomSheetValue
5+
import androidx.compose.material.Surface
66
import androidx.compose.material.rememberModalBottomSheetState
7-
import androidx.compose.material3.Surface
87
import androidx.compose.runtime.Composable
98
import androidx.compose.runtime.CompositionLocalProvider
109
import androidx.compose.runtime.LaunchedEffect
1110
import androidx.compose.runtime.getValue
1211
import androidx.compose.runtime.remember
13-
import androidx.compose.ui.Modifier
1412
import androidx.compose.ui.platform.LocalContext
1513
import androidx.core.app.NotificationManagerCompat
1614
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -22,7 +20,6 @@ import com.twofasapp.android.navigation.Screen
2220
import com.twofasapp.common.domain.SelectedTheme
2321
import com.twofasapp.designsystem.AppTheme
2422
import com.twofasapp.designsystem.LocalAppTheme
25-
import com.twofasapp.designsystem.MainAppTheme
2623
import com.twofasapp.designsystem.TwTheme
2724
import org.koin.androidx.compose.koinViewModel
2825
import timber.log.Timber
@@ -87,35 +84,32 @@ internal fun MainScreen(
8784
SelectedTheme.Dark -> AppTheme.Dark
8885
},
8986
) {
90-
MainAppTheme {
91-
Surface(
92-
modifier = Modifier.fillMaxSize(),
93-
color = TwTheme.color.background,
94-
) {
95-
val startDestination = when (uiState.startDestination!!) {
96-
MainUiState.StartDestination.Onboarding -> Screen.Startup.route
97-
MainUiState.StartDestination.Home -> Screen.Services.route
98-
}
87+
val startDestination = when (uiState.startDestination!!) {
88+
MainUiState.StartDestination.Onboarding -> Screen.Startup.route
89+
MainUiState.StartDestination.Home -> Screen.Services.route
90+
}
9991

100-
MainNavHost(
101-
navController = navController,
102-
bottomSheetNavigator = bottomSheetNavigator,
103-
bottomSheetState = sheetState,
104-
startDestination = startDestination,
105-
onServiceAddedSuccessfully = { viewModel.serviceAdded(it) },
106-
)
92+
Surface(
93+
color = TwTheme.color.background,
94+
) {
95+
MainNavHost(
96+
navController = navController,
97+
bottomSheetNavigator = bottomSheetNavigator,
98+
bottomSheetState = sheetState,
99+
startDestination = startDestination,
100+
onServiceAddedSuccessfully = { viewModel.serviceAdded(it) },
101+
)
102+
}
107103

108-
if (uiState.browserExtRequests.isNotEmpty()) {
109-
val browserExtRequest = uiState.browserExtRequests.first()
110-
BrowserExtRequestDialog(
111-
browserExtRequest = browserExtRequest,
112-
onRequestHandled = {
113-
viewModel.browserExtRequestHandled(browserExtRequest)
114-
NotificationManagerCompat.from(context).cancel(null, browserExtRequest.request.requestId.hashCode())
115-
}
116-
)
104+
if (uiState.browserExtRequests.isNotEmpty()) {
105+
val browserExtRequest = uiState.browserExtRequests.first()
106+
BrowserExtRequestDialog(
107+
browserExtRequest = browserExtRequest,
108+
onRequestHandled = {
109+
viewModel.browserExtRequestHandled(browserExtRequest)
110+
NotificationManagerCompat.from(context).cancel(null, browserExtRequest.request.requestId.hashCode())
117111
}
118-
}
112+
)
119113
}
120114
}
121115
}

app/src/main/java/com/twofasapp/ui/main/StartActivity.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
package com.twofasapp.ui.main
22

33
import android.content.Intent
4+
import android.content.res.Configuration
45
import android.os.Bundle
6+
import androidx.activity.ComponentActivity
7+
import androidx.activity.SystemBarStyle
8+
import androidx.activity.enableEdgeToEdge
59
import androidx.appcompat.app.AppCompatActivity
10+
import androidx.compose.ui.graphics.Color
11+
import androidx.compose.ui.graphics.toArgb
612
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
713
import com.twofasapp.android.navigation.DeeplinkHandler
814
import com.twofasapp.base.AuthTracker
915
import com.twofasapp.base.lifecycle.AuthAware
1016
import com.twofasapp.base.lifecycle.AuthLifecycle
17+
import com.twofasapp.common.domain.SelectedTheme
1118
import com.twofasapp.data.session.SettingsRepository
1219
import com.twofasapp.designsystem.AppThemeState
1320
import com.twofasapp.workmanager.OnAppStartWork
@@ -26,7 +33,32 @@ class StartActivity : AppCompatActivity(), AuthAware {
2633
private val syncTimeWorkDispatcher: SyncTimeWorkDispatcher by inject()
2734

2835
override fun onCreate(savedInstanceState: Bundle?) {
29-
AppThemeState.applyTheme(settingsRepository.getAppSettings().selectedTheme)
36+
val selectedTheme = settingsRepository.getAppSettings().selectedTheme
37+
AppThemeState.applyTheme(selectedTheme)
38+
enableEdgeToEdge(
39+
statusBarStyle = SystemBarStyle.auto(
40+
lightScrim = Color.Transparent.toArgb(),
41+
darkScrim = Color.Transparent.toArgb(),
42+
detectDarkMode = {
43+
when (selectedTheme) {
44+
SelectedTheme.Auto -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
45+
SelectedTheme.Light -> false
46+
SelectedTheme.Dark -> true
47+
}
48+
}
49+
),
50+
navigationBarStyle = SystemBarStyle.auto(
51+
lightScrim = Color.Transparent.toArgb(),
52+
darkScrim = Color.Transparent.toArgb(),
53+
detectDarkMode = {
54+
when (selectedTheme) {
55+
SelectedTheme.Auto -> (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
56+
SelectedTheme.Light -> false
57+
SelectedTheme.Dark -> true
58+
}
59+
}
60+
),
61+
)
3062
super.onCreate(savedInstanceState)
3163

3264
installSplashScreen()

app/src/main/res/values/themes.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
<item name="colorSurfaceVariant">@color/surfaceVariant</item>
1010
<item name="colorOnPrimary">@color/onSurface</item>
1111
<item name="android:windowBackground">@color/windowBackground</item>
12-
<item name="android:statusBarColor">@color/statusbar</item>
13-
<item name="android:windowLightStatusBar">@bool/isLightStatusBar</item>
1412
</style>
1513
</resources>
1614

app/src/main/res/xml/locales_config.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
<locale android:name="zh" />
1616
<locale android:name="el" />
1717
<locale android:name="ja" />
18+
<locale android:name="sv" />
1819
</locale-config>

buildlogic/src/main/java/com/twofasapp/buildlogic/version/AppConfig.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ package com.twofasapp.buildlogic.version
22

33
object AppConfig {
44
const val minSdk = 23
5-
const val targetSdk = 34
6-
const val compileSdk = 34
5+
const val targetSdk = 35
6+
const val compileSdk = 35
77
}

core/common/src/main/java/com/twofasapp/common/domain/Service.kt

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.twofasapp.common.domain
22

3+
import android.net.Uri
4+
35
data class Service(
46
val id: Long,
57
val serviceTypeId: String?,
@@ -125,4 +127,44 @@ data class Service(
125127
backupSyncStatus = BackupSyncStatus.SYNCED,
126128
)
127129
}
128-
}
130+
131+
fun toUri(): String {
132+
return Uri.Builder()
133+
.apply {
134+
135+
scheme("otpauth")
136+
137+
authority(authType.name.lowercase())
138+
139+
if (info.isNullOrBlank().not()) {
140+
appendEncodedPath("$name:$info")
141+
} else {
142+
appendEncodedPath(name)
143+
}
144+
145+
appendQueryParameter("secret", secret)
146+
147+
if (issuer.isNullOrBlank().not()) {
148+
appendQueryParameter("issuer", issuer)
149+
}
150+
151+
if (digits != null && digits != DefaultDigits) {
152+
appendQueryParameter("digits", digits.toString())
153+
}
154+
155+
if (period != null && period != DefaultPeriod) {
156+
appendQueryParameter("period", period.toString())
157+
}
158+
159+
if (hotpCounter != null && authType == AuthType.HOTP) {
160+
appendQueryParameter("counter", hotpCounter.toString())
161+
}
162+
163+
if (algorithm != null && algorithm != DefaultAlgorithm) {
164+
appendQueryParameter("algorithm", algorithm.name)
165+
}
166+
167+
}
168+
.toString()
169+
}
170+
}

core/designsystem/src/main/java/com/twofasapp/designsystem/AppTheme.kt

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.twofasapp.designsystem
22

3-
import android.app.Activity
43
import android.content.pm.ActivityInfo
54
import androidx.compose.foundation.isSystemInDarkTheme
65
import androidx.compose.material3.ColorScheme
@@ -10,14 +9,8 @@ import androidx.compose.material3.lightColorScheme
109
import androidx.compose.runtime.Composable
1110
import androidx.compose.runtime.CompositionLocalProvider
1211
import androidx.compose.runtime.DisposableEffect
13-
import androidx.compose.runtime.SideEffect
1412
import androidx.compose.runtime.staticCompositionLocalOf
15-
import androidx.compose.ui.graphics.Color
16-
import androidx.compose.ui.graphics.toArgb
1713
import androidx.compose.ui.platform.LocalContext
18-
import androidx.compose.ui.platform.LocalView
19-
import androidx.core.view.WindowCompat
20-
import com.google.accompanist.systemuicontroller.rememberSystemUiController
2114
import com.twofasapp.designsystem.internal.LocalThemeColors
2215
import com.twofasapp.designsystem.internal.ThemeColors
2316
import com.twofasapp.designsystem.internal.ThemeColorsDark
@@ -36,20 +29,6 @@ fun MainAppTheme(
3629
) {
3730
LockScreenOrientation(orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
3831

39-
val view = LocalView.current
40-
val systemUiController = rememberSystemUiController()
41-
42-
if (view.isInEditMode.not()) {
43-
SideEffect {
44-
with((view.context as Activity).window) {
45-
statusBarColor = Color.Transparent.toArgb()
46-
navigationBarColor = Color.Transparent.toArgb()
47-
48-
WindowCompat.setDecorFitsSystemWindows(this, false)
49-
}
50-
}
51-
}
52-
5332
val isInDarkTheme = when (LocalAppTheme.current) {
5433
AppTheme.Auto -> isSystemInDarkTheme()
5534
AppTheme.Light -> false
@@ -85,10 +64,6 @@ fun MainAppTheme(
8564
)
8665
}
8766

88-
SideEffect {
89-
systemUiController.setSystemBarsColor(color = colors.background)
90-
}
91-
9267
CompositionLocalProvider(
9368
LocalThemeColors provides colors,
9469
) {

0 commit comments

Comments
 (0)