Skip to content

Commit

Permalink
Paging & DB file path snackbar (#519)
Browse files Browse the repository at this point in the history
* paging

* DB file path

---------

Co-authored-by: babichev.a <[email protected]>
  • Loading branch information
artikhon and babichev.a authored Nov 14, 2024
1 parent 45eadf2 commit 4bd2ebe
Show file tree
Hide file tree
Showing 28 changed files with 224 additions and 75 deletions.
1 change: 1 addition & 0 deletions android-compose-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ dependencies {
implementation(libs.androidx.navigation.compose)
implementation(platform(libs.koin.bom))
implementation(libs.koin.android)
implementation(libs.koin.androidx.compose)
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.analytics)
implementation(libs.firebase.crashlytics)
Expand Down
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
plugins {
alias(libs.plugins.gradle.convention) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.jvm) apply false
Expand Down
21 changes: 17 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,28 @@ kotlin = "2.0.21"
agp = "8.7.2"
gms = "4.4.2"
crashlytics = "3.0.2"
compose = "1.7.0"
compose = "1.7.1"
coroutines = "1.9.0"
sqlDelight = "2.0.2"
androidxSqlite = "2.4.0"
saferoom = "1.3.0"
androidSqlCipher = "4.5.4"
iosSqlCipher = "4.5.4"
stately = "2.0.6"
koin-bom = "4.0.0"
kotlinx-serialization = "1.7.3"
kotlinx-datetime = "0.6.1"
napier = "2.7.1"
materialThemePrefs = "0.9.0"
androidxViewModel = "2.8.3"
materialThemePrefs = "0.9.1"
androidxViewModel = "2.8.4"
androidxNavigation = "2.8.0-alpha10"
androidxActivityCompose = "1.9.3"
androidxComposeTest = "1.7.5"
androidxCoreSplashscreen = "1.0.1"
androidxTracing = "1.2.0"
androidxLifecycle = "2.8.7"
androidxArch = "2.2.0"
androidxPaging = "3.3.2"
androidxTestExt = "1.2.1"
androidxTest = "1.6.2"
androidxTestOrchestrator = "1.5.1"
Expand All @@ -36,7 +38,7 @@ junit = "4.13.2"
mockito = "5.14.1"
turbine = "1.1.0"
espresso = "3.6.1"
desugar = "2.1.2"
desugar = "2.1.3"
androidSecurityLint = "1.0.3"
appdirs = "1.2.2"

Expand All @@ -51,6 +53,11 @@ sqlDelight-android = { module = "app.cash.sqldelight:android-driver", version.re
sqlDelight-coroutinesExt = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqlDelight" }
sqlDelight-native = { module = "app.cash.sqldelight:native-driver", version.ref = "sqlDelight" }
sqlDelight-jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqlDelight" }
sqlDelight-paging = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqlDelight" }

stately-common = { module = "co.touchlab:stately-common", version.ref = "stately" } #FIXME https://github.com/cashapp/sqldelight/issues/4357
stately-isolate = { module = "co.touchlab:stately-isolate", version.ref = "stately" }
stately-iso-collections = { module = "co.touchlab:stately-iso-collections", version.ref = "stately" }

androidx-sqlite = { module = "androidx.sqlite:sqlite", version.ref = "androidxSqlite" }
androidx-sqlite-ktx = { module = "androidx.sqlite:sqlite-ktx", version.ref = "androidxSqlite" }
Expand Down Expand Up @@ -92,6 +99,12 @@ androidx-arch-core-common = { module = "androidx.arch.core:core-common", version
androidx-arch-core-runtime = { module = "androidx.arch.core:core-runtime", version.ref = "androidxArch" }
androidx-arch-core-testing = { module = "androidx.arch.core:core-testing", version.ref = "androidxArch" }

androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "androidxPaging" }
androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "androidxPaging" }
androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "androidxPaging" }

cashapp-paging-compose = { module = "app.cash.paging:paging-compose-common", version = "3.3.0-alpha02-0.5.1" }

androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidxTestExt" }
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidxTest" }
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidxTest" }
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#Tue Oct 01 17:29:23 GET 2024
#Wed Nov 13 19:15:18 GET 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
2 changes: 1 addition & 1 deletion iosApp/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 0dc93a6f6109335ea8cd3f91d2c87cc8c99f04a3

COCOAPODS: 1.12.1
COCOAPODS: 1.15.2
2 changes: 1 addition & 1 deletion iosApp/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions iosApp/Pods/Pods.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions shared-compose-ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ kotlin {
implementation(libs.koin.compose.viewmodel.navigation)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.cashapp.paging.compose)
implementation(libs.stately.common)
}
androidMain.dependencies {
implementation(project.dependencies.platform(libs.koin.bom))
Expand All @@ -50,6 +52,10 @@ kotlin {
implementation(kotlin("test"))
implementation(compose.desktop.uiTestJUnit4)
}
iosMain.dependencies {
implementation(libs.stately.isolate)
implementation(libs.stately.iso.collections)
}
all {
languageSettings.optIn("kotlin.RequiresOptIn")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<string name="pref_title_enable_encryption">Включить шифрование</string>
<string name="pref_title_set_password">Установить пароль</string>
<string name="pref_title_check_cipher_version">Проверить версию SQLCipher</string>
<string name="pref_title_show_db_path">Показать путь к базе данных</string>
<string name="enter_password">Введите пароль</string>
<string name="confirm_password">Повторите пароль</string>
<string name="enter_old_password">Введите старый пароль</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<string name="pref_title_enable_encryption">Enable encryption</string>
<string name="pref_title_set_password">Set password</string>
<string name="pref_title_check_cipher_version">Check SQLCipher version</string>
<string name="pref_title_show_db_path">Show database path</string>
<string name="enter_password">Enter password</string>
<string name="confirm_password">Confirm password</string>
<string name="enter_old_password">Enter old password</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.softartdev.notedelight.ui.dialog.security.EnterPasswordDialog
import com.softartdev.theme.material3.PreferableMaterialTheme
import com.softartdev.theme.material3.ThemeDialog
import com.softartdev.theme.pref.PreferenceHelper
import org.koin.compose.KoinContext
import org.koin.compose.viewmodel.koinNavViewModel
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
Expand All @@ -39,6 +40,14 @@ import org.koin.core.parameter.parametersOf
fun App(
router: Router,
navController: NavHostController = rememberNavController()
) = KoinContext {
WrappedApp(router, navController)
}

@Composable
private fun WrappedApp(
router: Router,
navController: NavHostController = rememberNavController()
) = PreferableMaterialTheme {
DisposableEffect(key1 = router, key2 = navController) {
router.setController(navController)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.paging.PagingData
import app.cash.paging.compose.LazyPagingItems
import app.cash.paging.compose.collectAsLazyPagingItems
import com.softartdev.notedelight.shared.db.Note
import com.softartdev.notedelight.shared.db.TestSchema
import com.softartdev.notedelight.shared.presentation.main.MainViewModel
import com.softartdev.notedelight.shared.presentation.main.NoteListResult
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import notedelight.shared_compose_ui.generated.resources.Res
import notedelight.shared_compose_ui.generated.resources.app_name
import notedelight.shared_compose_ui.generated.resources.create_note
Expand All @@ -44,7 +50,7 @@ fun MainScreen(
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
) {
LaunchedEffect(mainViewModel) {
mainViewModel.updateNotes()
mainViewModel.launchNotes()
}
val noteListState: State<NoteListResult> = mainViewModel.stateFlow.collectAsState()
MainScreen(
Expand Down Expand Up @@ -77,12 +83,15 @@ fun MainScreen(
Box(modifier = Modifier.padding(paddingValues)) {
when (val noteListResult = noteListState.value) {
is NoteListResult.Loading -> Loader(modifier = Modifier.align(Alignment.Center))
is NoteListResult.Success -> when {
noteListResult.result.isNotEmpty() -> NoteList(
noteList = noteListResult.result,
onItemClicked = onItemClicked,
)
else -> Empty()
is NoteListResult.Success -> {
val pagingItems: LazyPagingItems<Note> = noteListResult.result.collectAsLazyPagingItems()
when {
pagingItems.itemCount > 0 -> NoteList(
pagingItems = pagingItems,
onItemClicked = onItemClicked,
)
else -> Empty()
}
}
is NoteListResult.Error -> Error(err = noteListResult.error ?: "Error")
}
Expand All @@ -103,8 +112,10 @@ fun MainScreen(
@Composable
fun PreviewMainScreen() {
val testNotes = listOf(TestSchema.firstNote, TestSchema.secondNote, TestSchema.thirdNote)
val pagingData: PagingData<Note> = PagingData.from(testNotes)
val pagingFlow: Flow<PagingData<Note>> = flowOf(pagingData)
val noteListState: MutableState<NoteListResult> = remember {
mutableStateOf(NoteListResult.Success(testNotes))
mutableStateOf(NoteListResult.Success(pagingFlow))
}
MainScreen(noteListState)
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
package com.softartdev.notedelight.ui

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.paging.PagingData
import app.cash.paging.compose.LazyPagingItems
import app.cash.paging.compose.collectAsLazyPagingItems
import com.softartdev.notedelight.shared.db.Note
import com.softartdev.notedelight.shared.db.TestSchema.firstNote
import com.softartdev.notedelight.shared.db.TestSchema.secondNote
import com.softartdev.notedelight.shared.db.TestSchema.thirdNote
import com.softartdev.notedelight.shared.db.Note
import kotlinx.coroutines.flow.flowOf

@Composable
fun NoteList(
noteList: List<Note>,
pagingItems: LazyPagingItems<Note>,
onItemClicked: (id: Long) -> Unit,
) {
val listState = rememberLazyListState()

LazyColumn(state = listState) {
items(items = noteList, key = Note::id) {
NoteItem(
note = it,
onItemClicked = onItemClicked,
)
LazyColumn {
items(count = pagingItems.itemCount) { index ->
when (val note: Note? = pagingItems[index]) {
null -> LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
else -> NoteItem(note = note, onItemClicked = onItemClicked)
}
HorizontalDivider()
}
}
LaunchedEffect(key1 = noteList.size, key2 = listState) {
listState.animateScrollToItem(0)
}
}

@Preview
Expand All @@ -39,6 +38,7 @@ fun PreviewNoteList() {
val lorem = StringBuilder().apply { repeat(100) { append("lorem ipsum ") } }.toString()
val longTitleNote = secondNote.copy(title = lorem)
val testNotes: List<Note> = listOf(firstNote, secondNote, thirdNote, longTitleNote)
val pagingItems = flowOf(PagingData.from(testNotes)).collectAsLazyPagingItems()
val onItemClicked: (id: Long) -> Unit = {}
NoteList(testNotes, onItemClicked)
NoteList(pagingItems, onItemClicked)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.material.icons.filled.Brightness4
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.Password
import androidx.compose.material.icons.filled.Security
import androidx.compose.material.icons.filled.Storage
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand Down Expand Up @@ -54,6 +55,7 @@ import notedelight.shared_compose_ui.generated.resources.Res
import notedelight.shared_compose_ui.generated.resources.pref_title_check_cipher_version
import notedelight.shared_compose_ui.generated.resources.pref_title_enable_encryption
import notedelight.shared_compose_ui.generated.resources.pref_title_set_password
import notedelight.shared_compose_ui.generated.resources.pref_title_show_db_path
import notedelight.shared_compose_ui.generated.resources.security
import notedelight.shared_compose_ui.generated.resources.settings
import notedelight.shared_compose_ui.generated.resources.theme
Expand Down Expand Up @@ -129,6 +131,11 @@ fun SettingsScreenBody(
vector = Icons.Filled.FileLock,
onClick = result.showCipherVersion
)
Preference(
title = stringResource(Res.string.pref_title_show_db_path),
vector = Icons.Default.Storage,
onClick = result.showDatabasePath
)
Spacer(Modifier.height(32.dp))
ListItem(
headlineContent = {},
Expand Down
1 change: 1 addition & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ kotlin {
commonMain.dependencies {
implementation(libs.coroutines.core)
implementation(libs.sqlDelight.coroutinesExt)
implementation(libs.sqlDelight.paging)
api(libs.kotlinx.datetime)
api(libs.napier)
implementation(project.dependencies.platform(libs.koin.bom))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class AndroidSafeRepo(private val context: Context) : SafeRepo() {
override val noteDAO: NoteDAO
get() = NoteDAO(buildDbIfNeed().noteQueries)

override val dbPath: String
get() = context.getDatabasePath(DB_NAME).absolutePath

override fun buildDbIfNeed(passphrase: CharSequence): DatabaseHolder = synchronized(this) {
var instance = databaseHolder
if (instance == null) {
Expand Down
Loading

0 comments on commit 4bd2ebe

Please sign in to comment.