From 777b419a602c1c9ae6e96886cda7860484f4e180 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Wed, 1 Jan 2025 15:17:17 +0100 Subject: [PATCH 01/15] Renamed `AccountsActivity` to `MainActivity` Signed-off-by: Arnau Mora --- app/src/main/AndroidManifest.xml | 12 ++++++------ .../kotlin/at/bitfire/davdroid/db/AppDatabase.kt | 7 ++++--- .../sync/account/AddressBookAuthenticatorService.kt | 4 ++-- .../ui/{AccountsActivity.kt => MainActivity.kt} | 2 +- .../main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt | 2 +- app/src/main/res/xml/sync_prefs.xml | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) rename app/src/main/kotlin/at/bitfire/davdroid/ui/{AccountsActivity.kt => MainActivity.kt} (97%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 173b80fc0..4e2202fb7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -62,7 +62,7 @@ @@ -73,12 +73,12 @@ + android:parentActivityName=".ui.MainActivity"/> @@ -106,7 +106,7 @@ @@ -134,7 +134,7 @@ + android:parentActivityName=".ui.MainActivity" /> ?, options: Bundle?): Bundle { - val intent = Intent(context, AccountsActivity::class.java) + val intent = Intent(context, MainActivity::class.java) intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response) return bundleOf(AccountManager.KEY_INTENT to intent) } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt similarity index 97% rename from app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt rename to app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index ad6752eb2..7a37b2fc1 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -16,7 +16,7 @@ import javax.inject.Inject @AndroidEntryPoint -class AccountsActivity: AppCompatActivity() { +class MainActivity: AppCompatActivity() { @Inject lateinit var accountsDrawerHandler: AccountsDrawerHandler diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt index 4b1038a79..72d97128a 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt @@ -86,7 +86,7 @@ object UiUtils { ShortcutInfo.Builder(context, SHORTCUT_SYNC_ALL) .setIcon(Icon.createWithResource(context, R.drawable.ic_sync_shortcut)) .setShortLabel(context.getString(R.string.accounts_sync_all)) - .setIntent(Intent(Intent.ACTION_SYNC, null, context, AccountsActivity::class.java)) + .setIntent(Intent(Intent.ACTION_SYNC, null, context, MainActivity::class.java)) .build() ) } catch(e: Exception) { diff --git a/app/src/main/res/xml/sync_prefs.xml b/app/src/main/res/xml/sync_prefs.xml index 6e693253d..d14c48a24 100644 --- a/app/src/main/res/xml/sync_prefs.xml +++ b/app/src/main/res/xml/sync_prefs.xml @@ -12,7 +12,7 @@ From ddf881a504d5193561f70b63500b4d4a8f1efbf7 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Wed, 1 Jan 2025 17:29:55 +0100 Subject: [PATCH 02/15] Added navigation Signed-off-by: Arnau Mora --- app/build.gradle.kts | 3 ++ .../at/bitfire/davdroid/ui/AccountsScreen.kt | 41 ++++++++++++++++ .../at/bitfire/davdroid/ui/MainActivity.kt | 48 ++++++++----------- .../bitfire/davdroid/ui/navigation/Routes.kt | 6 +++ gradle/libs.versions.toml | 5 ++ 5 files changed, 74 insertions(+), 29 deletions(-) create mode 100644 app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e56c50081..795cdd520 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,6 +8,7 @@ plugins { alias(libs.plugins.compose.compiler) alias(libs.plugins.hilt) alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ksp) } @@ -163,6 +164,7 @@ dependencies { implementation(platform(libs.compose.bom)) implementation(libs.compose.material3) implementation(libs.compose.materialIconsExtended) + implementation(libs.compose.navigation) implementation(libs.compose.runtime.livedata) debugImplementation(libs.compose.ui.tooling) implementation(libs.compose.ui.toolingPreview) @@ -189,6 +191,7 @@ dependencies { @Suppress("RedundantSuppression") implementation(libs.dnsjava) implementation(libs.guava) + implementation(libs.kotlinx.serialization) implementation(libs.mikepenz.aboutLibraries) implementation(libs.nsk90.kstatemachine) implementation(libs.okhttp.base) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt index 2b0e878f2..b40251586 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt @@ -2,11 +2,13 @@ package at.bitfire.davdroid.ui import android.Manifest import android.accounts.Account +import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Build import android.provider.Settings import androidx.activity.compose.BackHandler +import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -67,17 +69,56 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavBackStackEntry +import androidx.navigation.toRoute import at.bitfire.davdroid.BuildConfig import at.bitfire.davdroid.R +import at.bitfire.davdroid.ui.account.AccountActivity import at.bitfire.davdroid.ui.account.AccountProgress import at.bitfire.davdroid.ui.composable.ActionCard import at.bitfire.davdroid.ui.composable.ProgressBar +import at.bitfire.davdroid.ui.intro.IntroActivity +import at.bitfire.davdroid.ui.navigation.Routes +import at.bitfire.davdroid.ui.setup.LoginActivity import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import kotlinx.coroutines.delay import kotlinx.coroutines.launch +@Composable +fun AccountsScreen(backStackEntry: NavBackStackEntry, accountsDrawerHandler: AccountsDrawerHandler) { + val route = backStackEntry.toRoute() + val context = LocalContext.current + val activity = context as? Activity + + val introActivityLauncher = rememberLauncherForActivityResult(IntroActivity.Contract) { cancelled -> + if (cancelled) activity?.finish() + } + + AccountsScreen( + initialSyncAccounts = route.syncAccounts, + onShowAppIntro = { + introActivityLauncher.launch(null) + }, + accountsDrawerHandler = accountsDrawerHandler, + onAddAccount = { + // eventually this will become a navigation + context.startActivity(Intent(context, LoginActivity::class.java)) + }, + onShowAccount = { account -> + // eventually this will become a navigation + val intent = Intent(context, AccountActivity::class.java) + intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account) + context.startActivity(intent) + }, + onManagePermissions = { + // eventually this will become a navigation + context.startActivity(Intent(context, PermissionsActivity::class.java)) + } + ) +} + @Composable fun AccountsScreen( initialSyncAccounts: Boolean, diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index 7a37b2fc1..d82bef8c0 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -8,9 +8,10 @@ import android.content.Intent import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity -import at.bitfire.davdroid.ui.account.AccountActivity -import at.bitfire.davdroid.ui.intro.IntroActivity -import at.bitfire.davdroid.ui.setup.LoginActivity +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import at.bitfire.davdroid.ui.navigation.Routes import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -21,38 +22,27 @@ class MainActivity: AppCompatActivity() { @Inject lateinit var accountsDrawerHandler: AccountsDrawerHandler - private val introActivityLauncher = registerForActivityResult(IntroActivity.Contract) { cancelled -> - if (cancelled) - finish() - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // handle "Sync all" intent from launcher shortcut - val syncAccounts = intent.action == Intent.ACTION_SYNC - setContent { - AccountsScreen( - initialSyncAccounts = syncAccounts, - onShowAppIntro = { - introActivityLauncher.launch(null) - }, - accountsDrawerHandler = accountsDrawerHandler, - onAddAccount = { - startActivity(Intent(this, LoginActivity::class.java)) - }, - onShowAccount = { account -> - val intent = Intent(this, AccountActivity::class.java) - intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account) - startActivity(intent) - }, - onManagePermissions = { - startActivity(Intent(this, PermissionsActivity::class.java)) - } - ) + NavHost( + navController = rememberNavController(), + startDestination = accountsFromIntent() + ) { + composable { AccountsScreen(it, accountsDrawerHandler) } + } } } + /** + * Initializes the accounts route from the current intent data. + * Checks whether the action is [Intent.ACTION_SYNC]. + */ + private fun accountsFromIntent() = Routes.Accounts( + // handle "Sync all" intent from launcher shortcut + syncAccounts = intent.action == Intent.ACTION_SYNC + ) + } \ No newline at end of file diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt new file mode 100644 index 000000000..a2a0cb226 --- /dev/null +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt @@ -0,0 +1,6 @@ +package at.bitfire.davdroid.ui.navigation + +object Routes { + @Serializable + data class Accounts(val syncAccounts: Boolean) +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d271f8780..93205fd69 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,7 @@ bitfire-ical4android = "c1ed0a0570" bitfire-vcard4android = "ae5d609f92" compose-accompanist = "0.37.0" compose-bom = "2024.12.01" +compose-navigation = "2.8.5" dnsjava = "3.6.0" glance = "1.1.1" guava = "33.4.0-android" @@ -31,6 +32,7 @@ hilt = "2.54" # keep in sync with ksp version kotlin = "2.1.0" kotlinx-coroutines = "1.10.1" +kotlinx-serialization = "1.7.3" # see https://github.com/google/ksp/releases for version numbers ksp = "2.1.0-1.0.29" mikepenz-aboutLibraries = "11.2.3" @@ -72,6 +74,7 @@ compose-accompanist-permissions = { module = "com.google.accompanist:accompanist compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" } compose-material3 = { group = "androidx.compose.material3", name = "material3" } compose-materialIconsExtended = { module = "androidx.compose.material:material-icons-extended" } +compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "compose-navigation" } compose-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } compose-ui-toolingPreview = { module = "androidx.compose.ui:ui-tooling-preview" } @@ -85,6 +88,7 @@ hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", vers junit = { module = "junit:junit", version = "4.13.2" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } mikepenz-aboutLibraries = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "mikepenz-aboutLibraries" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" } mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockk" } @@ -106,5 +110,6 @@ android-application = { id = "com.android.application", version.ref = "android-a compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } mikepenz-aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "mikepenz-aboutLibraries" } From a02559ca9a05ec72b5cb3f7c19dff2a621c91052 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Wed, 1 Jan 2025 17:32:56 +0100 Subject: [PATCH 03/15] Fixed import Signed-off-by: Arnau Mora --- app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt index a2a0cb226..8c1aebec4 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt @@ -1,5 +1,7 @@ package at.bitfire.davdroid.ui.navigation +import kotlinx.serialization.Serializable + object Routes { @Serializable data class Accounts(val syncAccounts: Boolean) From a544e53267995fd132e461d5eb36c9a8f4ca6121 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Wed, 1 Jan 2025 17:33:57 +0100 Subject: [PATCH 04/15] Created `LocalNavController` Signed-off-by: Arnau Mora --- .../at/bitfire/davdroid/ui/MainActivity.kt | 16 +++++++++++----- .../davdroid/ui/composition/NavController.kt | 6 ++++++ 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index d82bef8c0..b8bce58db 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -8,9 +8,11 @@ import android.content.Intent import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity +import androidx.compose.runtime.CompositionLocalProvider import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import at.bitfire.davdroid.ui.composition.LocalNavController import at.bitfire.davdroid.ui.navigation.Routes import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -27,11 +29,15 @@ class MainActivity: AppCompatActivity() { super.onCreate(savedInstanceState) setContent { - NavHost( - navController = rememberNavController(), - startDestination = accountsFromIntent() - ) { - composable { AccountsScreen(it, accountsDrawerHandler) } + val navController = rememberNavController() + + CompositionLocalProvider(LocalNavController provides navController) { + NavHost( + navController = rememberNavController(), + startDestination = accountsFromIntent() + ) { + composable { AccountsScreen(it, accountsDrawerHandler) } + } } } } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt new file mode 100644 index 000000000..5f09fa567 --- /dev/null +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt @@ -0,0 +1,6 @@ +package at.bitfire.davdroid.ui.composition + +import androidx.compose.runtime.compositionLocalOf +import androidx.navigation.NavController + +val LocalNavController = compositionLocalOf { error("No NavController attached.") } From b8b38b600afad8c23c3fba7396c5ed53ad2b11f6 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Wed, 1 Jan 2025 17:34:19 +0100 Subject: [PATCH 05/15] Typo Signed-off-by: Arnau Mora --- app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index b8bce58db..fa3a8e549 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -33,7 +33,7 @@ class MainActivity: AppCompatActivity() { CompositionLocalProvider(LocalNavController provides navController) { NavHost( - navController = rememberNavController(), + navController = navController, startDestination = accountsFromIntent() ) { composable { AccountsScreen(it, accountsDrawerHandler) } From bdae74189b3f8d26e8e45434cdfb25e7579a4144 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Wed, 1 Jan 2025 18:23:47 +0100 Subject: [PATCH 06/15] Moved `AccountsDrawerHandler` to model Signed-off-by: Arnau Mora --- .../main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt | 3 ++- .../main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt | 6 ++---- app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt | 7 +------ app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt | 6 +++--- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt index 309a7dc78..a21f6ce12 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt @@ -50,7 +50,8 @@ class AccountsModel @AssistedInject constructor( private val db: AppDatabase, introPageFactory: IntroPageFactory, private val logger: Logger, - private val syncWorkerManager: SyncWorkerManager + private val syncWorkerManager: SyncWorkerManager, + val accountsDrawerHandler: AccountsDrawerHandler ): ViewModel() { @AssistedFactory diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt index b40251586..d49d252d0 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt @@ -87,7 +87,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Composable -fun AccountsScreen(backStackEntry: NavBackStackEntry, accountsDrawerHandler: AccountsDrawerHandler) { +fun AccountsScreen(backStackEntry: NavBackStackEntry) { val route = backStackEntry.toRoute() val context = LocalContext.current val activity = context as? Activity @@ -101,7 +101,6 @@ fun AccountsScreen(backStackEntry: NavBackStackEntry, accountsDrawerHandler: Acc onShowAppIntro = { introActivityLauncher.launch(null) }, - accountsDrawerHandler = accountsDrawerHandler, onAddAccount = { // eventually this will become a navigation context.startActivity(Intent(context, LoginActivity::class.java)) @@ -123,7 +122,6 @@ fun AccountsScreen(backStackEntry: NavBackStackEntry, accountsDrawerHandler: Acc fun AccountsScreen( initialSyncAccounts: Boolean, onShowAppIntro: () -> Unit, - accountsDrawerHandler: AccountsDrawerHandler, onAddAccount: () -> Unit, onShowAccount: (Account) -> Unit, onManagePermissions: () -> Unit, @@ -148,7 +146,7 @@ fun AccountsScreen( } AccountsScreen( - accountsDrawerHandler = accountsDrawerHandler, + accountsDrawerHandler = model.accountsDrawerHandler, accounts = accounts, showSyncAll = showSyncAll, onSyncAll = { model.syncAllAccounts() }, diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index fa3a8e549..3304bc327 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -15,16 +15,11 @@ import androidx.navigation.compose.rememberNavController import at.bitfire.davdroid.ui.composition.LocalNavController import at.bitfire.davdroid.ui.navigation.Routes import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject @AndroidEntryPoint class MainActivity: AppCompatActivity() { - @Inject - lateinit var accountsDrawerHandler: AccountsDrawerHandler - - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -36,7 +31,7 @@ class MainActivity: AppCompatActivity() { navController = navController, startDestination = accountsFromIntent() ) { - composable { AccountsScreen(it, accountsDrawerHandler) } + composable { AccountsScreen(it) } } } } diff --git a/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt b/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt index 3efcf73f0..6c20518ba 100644 --- a/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt +++ b/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt @@ -23,9 +23,6 @@ interface OseFlavorModules { @Module @InstallIn(ActivityComponent::class) interface ForActivities { - @Binds - fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler - @Binds fun loginTypesProvider(impl: StandardLoginTypesProvider): LoginTypesProvider } @@ -33,6 +30,9 @@ interface OseFlavorModules { @Module @InstallIn(ViewModelComponent::class) interface ForViewModels { + @Binds + fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler + @Binds fun appLicenseInfoProvider(impl: OpenSourceLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider From 282f1d1db6b942ae496ee335b9ad6f9bd8c18433 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Thu, 2 Jan 2025 14:52:52 +0100 Subject: [PATCH 07/15] Moved NavController Signed-off-by: Arnau Mora --- app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt | 2 +- .../davdroid/ui/{composition => navigation}/NavController.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/src/main/kotlin/at/bitfire/davdroid/ui/{composition => navigation}/NavController.kt (81%) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index 3304bc327..81581a5bf 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -12,7 +12,7 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import at.bitfire.davdroid.ui.composition.LocalNavController +import at.bitfire.davdroid.ui.navigation.LocalNavController import at.bitfire.davdroid.ui.navigation.Routes import dagger.hilt.android.AndroidEntryPoint diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt similarity index 81% rename from app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt rename to app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt index 5f09fa567..71991c542 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/composition/NavController.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt @@ -1,4 +1,4 @@ -package at.bitfire.davdroid.ui.composition +package at.bitfire.davdroid.ui.navigation import androidx.compose.runtime.compositionLocalOf import androidx.navigation.NavController From 0e59334e68944f674e24a34f776a274d06015c8c Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Sat, 11 Jan 2025 15:46:18 +0100 Subject: [PATCH 08/15] Moved `AccountsDrawerHandler` back to activity Signed-off-by: Arnau Mora --- .../main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt | 3 +-- .../main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt | 9 +++++++-- .../main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt | 6 +++++- .../ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt | 6 +++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt index cf2ef2a84..dc718ac99 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsModel.kt @@ -54,8 +54,7 @@ class AccountsModel @AssistedInject constructor( private val db: AppDatabase, introPageFactory: IntroPageFactory, private val logger: Logger, - private val syncWorkerManager: SyncWorkerManager, - val accountsDrawerHandler: AccountsDrawerHandler + private val syncWorkerManager: SyncWorkerManager ): ViewModel() { @AssistedFactory diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt index 38190a01d..e6d665875 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt @@ -91,7 +91,10 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Composable -fun AccountsScreen(backStackEntry: NavBackStackEntry) { +fun AccountsScreen( + backStackEntry: NavBackStackEntry, + accountsDrawerHandler: AccountsDrawerHandler +) { val route = backStackEntry.toRoute() val context = LocalContext.current val activity = context as? Activity @@ -101,6 +104,7 @@ fun AccountsScreen(backStackEntry: NavBackStackEntry) { } AccountsScreen( + accountsDrawerHandler = accountsDrawerHandler, initialSyncAccounts = route.syncAccounts, onShowAppIntro = { introActivityLauncher.launch(null) @@ -124,6 +128,7 @@ fun AccountsScreen(backStackEntry: NavBackStackEntry) { @Composable fun AccountsScreen( + accountsDrawerHandler: AccountsDrawerHandler, initialSyncAccounts: Boolean, onShowAppIntro: () -> Unit, onAddAccount: () -> Unit, @@ -150,7 +155,7 @@ fun AccountsScreen( } AccountsScreen( - accountsDrawerHandler = model.accountsDrawerHandler, + accountsDrawerHandler = accountsDrawerHandler, accounts = accounts, showSyncAll = showSyncAll, onSyncAll = { model.syncAllAccounts() }, diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index 81581a5bf..bf767c491 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -15,11 +15,15 @@ import androidx.navigation.compose.rememberNavController import at.bitfire.davdroid.ui.navigation.LocalNavController import at.bitfire.davdroid.ui.navigation.Routes import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @AndroidEntryPoint class MainActivity: AppCompatActivity() { + @Inject + lateinit var accountsDrawerHandler: AccountsDrawerHandler + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -31,7 +35,7 @@ class MainActivity: AppCompatActivity() { navController = navController, startDestination = accountsFromIntent() ) { - composable { AccountsScreen(it) } + composable { AccountsScreen(it, accountsDrawerHandler) } } } } diff --git a/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt b/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt index 6c20518ba..3efcf73f0 100644 --- a/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt +++ b/app/src/ose/kotlin/at/bitfire/davdroid/OseFlavorModule.kt @@ -23,6 +23,9 @@ interface OseFlavorModules { @Module @InstallIn(ActivityComponent::class) interface ForActivities { + @Binds + fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler + @Binds fun loginTypesProvider(impl: StandardLoginTypesProvider): LoginTypesProvider } @@ -30,9 +33,6 @@ interface OseFlavorModules { @Module @InstallIn(ViewModelComponent::class) interface ForViewModels { - @Binds - fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler - @Binds fun appLicenseInfoProvider(impl: OpenSourceLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider From 597a3d293ec7d543913d923811d942fb3cdc6c1e Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Sat, 11 Jan 2025 15:50:16 +0100 Subject: [PATCH 09/15] Added redirection from `AccountsActivity` to `MainActivity` Signed-off-by: Arnau Mora --- app/src/main/AndroidManifest.xml | 8 +++++++ .../bitfire/davdroid/ui/AccountsActivity.kt | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e2202fb7..9add29a5c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -70,6 +70,14 @@ + + + + Date: Mon, 13 Jan 2025 11:36:30 +0100 Subject: [PATCH 10/15] Legacy implementations Signed-off-by: Arnau Mora --- .../bitfire/davdroid/ui/AccountsActivity.kt | 11 +++-- .../at/bitfire/davdroid/ui/MainActivity.kt | 41 ++++++++++++++++++- .../kotlin/at/bitfire/davdroid/ui/UiUtils.kt | 6 ++- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt index 1f2973961..b7a4fcd2e 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt @@ -8,15 +8,14 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -@Deprecated("Automatically redirects to MainActivity. Should be removed in the future.") +// Automatically redirects to MainActivity. Should be removed in the future. +// Needed for backwards compatibility with external apps. class AccountsActivity: AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - startActivity( - Intent(this, MainActivity::class.java).apply { - action = intent.action - } - ) + MainActivity.legacyRedirect(this) { + putExtra(MainActivity.EXTRA_SYNC_ACCOUNTS, action == Intent.ACTION_SYNC) + } } } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index bf767c491..2c3c31061 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -4,9 +4,11 @@ package at.bitfire.davdroid.ui +import android.app.Activity import android.content.Intent import android.os.Bundle import androidx.activity.compose.setContent +import androidx.annotation.UiThread import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.CompositionLocalProvider import androidx.navigation.compose.NavHost @@ -47,7 +49,44 @@ class MainActivity: AppCompatActivity() { */ private fun accountsFromIntent() = Routes.Accounts( // handle "Sync all" intent from launcher shortcut - syncAccounts = intent.action == Intent.ACTION_SYNC + syncAccounts = intent.getBooleanExtra(EXTRA_SYNC_ACCOUNTS, false) ) + companion object { + /** + * Used by the "Sync all" intent from launcher shortcut. + */ + const val EXTRA_SYNC_ACCOUNTS = "sync-accounts" + + /** + * Starts [MainActivity] as a redirection of a legacy activity. + * By default, copies all the intent data from [activity]. + * This is used for migrating all multi-activity logic, to single-activity. + * + * @param activity The activity that is requesting the redirection. + * @param builder Any modifications or extras that you want to add to the intent should be + * placed here. + */ + @UiThread + fun legacyRedirect(activity: Activity, builder: Intent.() -> Unit = {}) { + val intent = activity.intent + + activity.startActivity( + Intent(activity, MainActivity::class.java).apply { + // Create a new activity, do not allow going back. + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + // Copy the action called. + action = intent.action + // Copy any intent data. + data = intent.data + // Copy all extras. + putExtras(intent) + + // Perform any extra modifications required + builder() + } + ) + } + } + } \ No newline at end of file diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt index 72d97128a..148641540 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt @@ -86,7 +86,11 @@ object UiUtils { ShortcutInfo.Builder(context, SHORTCUT_SYNC_ALL) .setIcon(Icon.createWithResource(context, R.drawable.ic_sync_shortcut)) .setShortLabel(context.getString(R.string.accounts_sync_all)) - .setIntent(Intent(Intent.ACTION_SYNC, null, context, MainActivity::class.java)) + .setIntent( + Intent(Intent.ACTION_SYNC, null, context, MainActivity::class.java).apply { + putExtra(MainActivity.EXTRA_SYNC_ACCOUNTS, true) + } + ) .build() ) } catch(e: Exception) { From 27d0a687199b2f9b2e020aa5b8b953b30c8c45a9 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Mon, 13 Jan 2025 12:43:27 +0100 Subject: [PATCH 11/15] Minor changes --- app/src/main/AndroidManifest.xml | 4 +--- .../kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt | 10 +++++++--- .../kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt | 4 ++-- .../main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt | 10 ++++++---- .../ui/navigation/{Routes.kt => Destination.kt} | 6 ++++-- .../at/bitfire/davdroid/ui/navigation/NavController.kt | 4 +++- 6 files changed, 23 insertions(+), 15 deletions(-) rename app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/{Routes.kt => Destination.kt} (86%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9add29a5c..4ee6ce89a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -71,11 +71,9 @@ - () + val route = backStackEntry.toRoute() val context = LocalContext.current val activity = context as? Activity diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt index 2c3c31061..8a32fad87 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt @@ -14,12 +14,11 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import at.bitfire.davdroid.ui.navigation.Destination import at.bitfire.davdroid.ui.navigation.LocalNavController -import at.bitfire.davdroid.ui.navigation.Routes import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject - @AndroidEntryPoint class MainActivity: AppCompatActivity() { @@ -37,7 +36,9 @@ class MainActivity: AppCompatActivity() { navController = navController, startDestination = accountsFromIntent() ) { - composable { AccountsScreen(it, accountsDrawerHandler) } + composable { + AccountsScreen(it, accountsDrawerHandler) + } } } } @@ -47,11 +48,12 @@ class MainActivity: AppCompatActivity() { * Initializes the accounts route from the current intent data. * Checks whether the action is [Intent.ACTION_SYNC]. */ - private fun accountsFromIntent() = Routes.Accounts( + private fun accountsFromIntent() = Destination.Accounts( // handle "Sync all" intent from launcher shortcut syncAccounts = intent.getBooleanExtra(EXTRA_SYNC_ACCOUNTS, false) ) + companion object { /** * Used by the "Sync all" intent from launcher shortcut. diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Destination.kt similarity index 86% rename from app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt rename to app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Destination.kt index 8c1aebec4..06745a823 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Routes.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/Destination.kt @@ -2,7 +2,9 @@ package at.bitfire.davdroid.ui.navigation import kotlinx.serialization.Serializable -object Routes { +object Destination { + @Serializable data class Accounts(val syncAccounts: Boolean) -} + +} \ No newline at end of file diff --git a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt index 71991c542..e49bda3c2 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/ui/navigation/NavController.kt @@ -3,4 +3,6 @@ package at.bitfire.davdroid.ui.navigation import androidx.compose.runtime.compositionLocalOf import androidx.navigation.NavController -val LocalNavController = compositionLocalOf { error("No NavController attached.") } +val LocalNavController = compositionLocalOf { + error("No NavController attached.") +} \ No newline at end of file From 03719abcee2f847a035d0c1aeb01c3f5ecc76603 Mon Sep 17 00:00:00 2001 From: Arnau Mora Date: Mon, 13 Jan 2025 14:57:28 +0100 Subject: [PATCH 12/15] Using deep links Signed-off-by: Arnau Mora --- app/src/main/AndroidManifest.xml | 6 ++ .../bitfire/davdroid/ui/AccountsActivity.kt | 8 ++- .../at/bitfire/davdroid/ui/MainActivity.kt | 61 ++++++++----------- .../kotlin/at/bitfire/davdroid/ui/UiUtils.kt | 9 +-- .../davdroid/ui/navigation/Destination.kt | 15 ++++- 5 files changed, 55 insertions(+), 44 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ee6ce89a..6bbd778c7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,6 +68,12 @@ + + + + + +