Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compose Navigation: start migration with AccountsActivity #1211

Open
wants to merge 20 commits into
base: main-ose
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
20 changes: 14 additions & 6 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,31 @@

<activity android:name=".ui.intro.IntroActivity" />
<activity
android:name=".ui.AccountsActivity"
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

<!--
Left here for external apps.
Automatically redirects to MainActivity.
Should be removed in the future.
-->
<!--suppress DeprecatedClassUsageInspection -->
<activity android:name=".ui.AccountsActivity" android:exported="true" />

<activity
android:name=".ui.AboutActivity"
android:label="@string/navigation_drawer_about"
android:parentActivityName=".ui.AccountsActivity"/>
android:parentActivityName=".ui.MainActivity"/>

<activity
android:name=".ui.AppSettingsActivity"
android:label="@string/app_settings"
android:parentActivityName=".ui.AccountsActivity"
android:parentActivityName=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES"/>
Expand Down Expand Up @@ -106,7 +114,7 @@

<activity
android:name=".ui.setup.LoginActivity"
android:parentActivityName=".ui.AccountsActivity"
android:parentActivityName=".ui.MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
Expand Down Expand Up @@ -134,7 +142,7 @@

<activity
android:name=".ui.account.AccountActivity"
android:parentActivityName=".ui.AccountsActivity"
android:parentActivityName=".ui.MainActivity"
android:exported="true">
</activity>
<activity
Expand All @@ -156,7 +164,7 @@
<activity
android:name=".ui.webdav.WebdavMountsActivity"
android:exported="true"
android:parentActivityName=".ui.AccountsActivity" />
android:parentActivityName=".ui.MainActivity" />
<activity
android:name=".ui.webdav.AddWebdavMountActivity"
android:parentActivityName=".ui.webdav.WebdavMountsActivity"
Expand Down
7 changes: 4 additions & 3 deletions app/src/main/kotlin/at/bitfire/davdroid/db/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import at.bitfire.davdroid.R
import at.bitfire.davdroid.TextTable
import at.bitfire.davdroid.db.migration.*
import at.bitfire.davdroid.ui.AccountsActivity
import at.bitfire.davdroid.db.migration.AutoMigration12
import at.bitfire.davdroid.db.migration.AutoMigration16
import at.bitfire.davdroid.ui.MainActivity
import at.bitfire.davdroid.ui.NotificationRegistry
import dagger.Module
import dagger.Provides
Expand Down Expand Up @@ -74,7 +75,7 @@ abstract class AppDatabase: RoomDatabase() {
.addCallback(object: Callback() {
override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
notificationRegistry.notifyIfPossible(NotificationRegistry.NOTIFY_DATABASE_CORRUPTED) {
val launcherIntent = Intent(context, AccountsActivity::class.java)
val launcherIntent = Intent(context, MainActivity::class.java)
NotificationCompat.Builder(context, notificationRegistry.CHANNEL_GENERAL)
.setSmallIcon(R.drawable.ic_warning_notify)
.setContentTitle(context.getString(R.string.database_destructive_migration_title))
Expand Down
50 changes: 7 additions & 43 deletions app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,17 @@ package at.bitfire.davdroid.ui

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 dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject


@AndroidEntryPoint
@Deprecated("Automatically redirects to MainActivity. Should be removed in the future.")
class AccountsActivity: 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))
}
)
}
startActivity(
Intent(this, MainActivity::class.java).apply {
action = intent.action
}
)
}

}
}
46 changes: 45 additions & 1 deletion app/src/main/kotlin/at/bitfire/davdroid/ui/AccountsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,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
Expand Down Expand Up @@ -71,11 +73,17 @@ 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
Expand All @@ -84,9 +92,45 @@ import kotlinx.coroutines.launch

@Composable
fun AccountsScreen(
backStackEntry: NavBackStackEntry,
accountsDrawerHandler: AccountsDrawerHandler
) {
val route = backStackEntry.toRoute<Routes.Accounts>()
val context = LocalContext.current
val activity = context as? Activity

val introActivityLauncher = rememberLauncherForActivityResult(IntroActivity.Contract) { cancelled ->
if (cancelled) activity?.finish()
}

AccountsScreen(
accountsDrawerHandler = accountsDrawerHandler,
initialSyncAccounts = route.syncAccounts,
onShowAppIntro = {
introActivityLauncher.launch(null)
},
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(
accountsDrawerHandler: AccountsDrawerHandler,
initialSyncAccounts: Boolean,
onShowAppIntro: () -> Unit,
accountsDrawerHandler: AccountsDrawerHandler,
onAddAccount: () -> Unit,
onShowAccount: (Account) -> Unit,
onManagePermissions: () -> Unit,
Expand Down
53 changes: 53 additions & 0 deletions app/src/main/kotlin/at/bitfire/davdroid/ui/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/

package at.bitfire.davdroid.ui

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.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)

setContent {
val navController = rememberNavController()

CompositionLocalProvider(LocalNavController provides navController) {
NavHost(
navController = navController,
startDestination = accountsFromIntent()
) {
composable<Routes.Accounts> { 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
)

}
2 changes: 1 addition & 1 deletion app/src/main/kotlin/at/bitfire/davdroid/ui/UiUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package at.bitfire.davdroid.ui.navigation

import androidx.compose.runtime.compositionLocalOf
import androidx.navigation.NavController

val LocalNavController = compositionLocalOf<NavController> { error("No NavController attached.") }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package at.bitfire.davdroid.ui.navigation

import kotlinx.serialization.Serializable

object Routes {
@Serializable
data class Accounts(val syncAccounts: Boolean)
}
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ bitfire-ical4android = "12df9bfddb"
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"
hilt = "2.55"
# 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.4.0"
Expand Down Expand Up @@ -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" }
Expand All @@ -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" }
Expand All @@ -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" }
Loading