Skip to content

Commit 6ffd931

Browse files
committed
Sync notes feature
Fix bug in syncing notes
1 parent 9e4f5ce commit 6ffd931

64 files changed

Lines changed: 1183 additions & 223 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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,30 @@ android {
3232
}
3333
}
3434

35+
signingConfigs {
36+
// get {
37+
// keyAlias = project.property("RELEASE_KEY_ALIAS").toString()
38+
// keyPassword = project.property("RELEASE_KEY_PASSWORD").toString()
39+
// storeFile = file(project.property("RELEASE_STORE_FILE").toString())
40+
// storePassword = project.property("RELEASE_STORE_PASSWORD").toString()
41+
// }
42+
43+
create("release") {
44+
keyAlias = project.property("RELEASE_KEY_ALIAS").toString()
45+
keyPassword = project.property("RELEASE_KEY_PASSWORD").toString()
46+
storeFile = file(project.property("RELEASE_STORE_FILE").toString())
47+
storePassword = project.property("RELEASE_STORE_PASSWORD").toString()
48+
}
49+
}
50+
3551
buildTypes {
3652
release {
3753
isMinifyEnabled = false
3854
proguardFiles(
3955
getDefaultProguardFile("proguard-android-optimize.txt"),
4056
"proguard-rules.pro"
4157
)
58+
signingConfig = signingConfigs.getByName("release")
4259
}
4360
}
4461
compileOptions {
@@ -74,6 +91,9 @@ dependencies {
7491
implementation(project(":feature:single_note:data"))
7592
implementation(project(":feature:single_note:domain"))
7693
implementation(project(":feature:single_note:presentation"))
94+
implementation(project(":feature:settings:data"))
95+
implementation(project(":feature:settings:domain"))
96+
implementation(project(":feature:settings:presentation"))
7797
implementation(libs.core.ktx)
7898
implementation(libs.lifecycle.runtime.ktx)
7999
implementation(libs.hilt)

app/src/main/java/com/viplearner/notes/MainActivity.kt

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
99
import androidx.activity.compose.setContent
1010
import androidx.activity.result.IntentSenderRequest
1111
import androidx.activity.result.contract.ActivityResultContracts
12-
import androidx.compose.material3.Text
13-
import androidx.compose.runtime.Composable
1412
import androidx.compose.runtime.DisposableEffect
15-
import androidx.compose.ui.Modifier
16-
import androidx.compose.ui.tooling.preview.Preview
1713
import androidx.lifecycle.lifecycleScope
1814
import com.example.compose.NotesTheme
1915
import com.facebook.CallbackManager
@@ -162,20 +158,4 @@ class MainActivity : ComponentActivity() {
162158
callbackManager.onActivityResult(requestCode, resultCode, data)
163159
super.onActivityResult(requestCode, resultCode, data)
164160
}
165-
}
166-
167-
@Composable
168-
fun Greeting(name: String, modifier: Modifier = Modifier) {
169-
Text(
170-
text = "Hello $name!",
171-
modifier = modifier
172-
)
173-
}
174-
175-
@Preview(showBackground = true)
176-
@Composable
177-
fun GreetingPreview() {
178-
NotesTheme {
179-
Greeting("Android")
180-
}
181161
}

common/data/local/src/main/java/com/viplearner/common/data/local/datastore/NotesDataStoreRepositoryImpl.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,29 @@ class NotesDataStoreRepositoryImpl @Inject constructor (
6969
}
7070
}
7171

72-
override suspend fun savePrivateKey(privateKey: String) {
72+
override suspend fun savePrivateKey(value: String) {
7373
prefsDataStore.edit { preferences ->
74-
preferences[NotesDataStorePreferenceKeys.PRIVATE_KEY] = privateKey
74+
preferences[NotesDataStorePreferenceKeys.PRIVATE_KEY] = value
7575
}
7676
}
7777

78+
override suspend fun getSyncState(): Flow<Boolean> {
79+
return prefsDataStore.data
80+
.catch { exception ->
81+
// dataStore.data throws an IOException when an error is encountered when reading data
82+
if (exception is IOException) {
83+
emit(emptyPreferences())
84+
} else {
85+
throw exception
86+
}
87+
}.map { preferences ->
88+
preferences[NotesDataStorePreferenceKeys.SYNC_STATE]?:false
89+
}
90+
}
91+
92+
override suspend fun setSyncState(value: Boolean) {
93+
prefsDataStore.edit { preferences ->
94+
preferences[NotesDataStorePreferenceKeys.SYNC_STATE] = value
95+
}
96+
}
7897
}

common/data/local/src/main/java/com/viplearner/common/data/local/dto/Note.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ data class Note(
1010
@PrimaryKey @ColumnInfo(name = "uuid") val uuid: String = UUID.randomUUID().toString(),
1111
@ColumnInfo(name = "title") val title: String,
1212
@ColumnInfo(name = "content") val content: String,
13-
@ColumnInfo(name = "timeLastEdited") val timeLastEdited: Long,
13+
@ColumnInfo(name = "timeLastEdited") var timeLastEdited: Long,
1414
@ColumnInfo(name = "isPinned", defaultValue = "0") var isPinned: Boolean,
1515
@ColumnInfo(name = "isDeleted", defaultValue = "false") var isDeleted: Boolean = false
1616
)

common/data/remote/src/main/java/com/viplearner/common/data/remote/fb_database_repository/DatabaseRepositoryImpl.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,7 @@ class DatabaseRepositoryImpl @Inject constructor(
5555
note.toNote()
5656
)
5757
}
58+
59+
override suspend fun observeNotes(uid: String) =
60+
databaseService.observeNotes(uid)
5861
}

common/data/remote/src/main/java/com/viplearner/common/data/remote/service/DatabaseService.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import com.google.firebase.database.ktx.database
1010
import com.google.firebase.ktx.Firebase
1111
import com.viplearner.common.data.remote.di.IoDispatcher
1212
import com.viplearner.common.data.remote.dto.Note
13+
import com.viplearner.common.data.remote.mapper.toNoteEntity
1314
import com.viplearner.common.domain.datastore.NotesDataStoreRepository
1415
import kotlinx.coroutines.CoroutineDispatcher
16+
import kotlinx.coroutines.channels.awaitClose
17+
import kotlinx.coroutines.flow.callbackFlow
18+
import kotlinx.coroutines.tasks.await
1519
import javax.inject.Inject
1620

1721
class DatabaseService @Inject constructor(
@@ -51,6 +55,27 @@ class DatabaseService @Inject constructor(
5155
return src.task
5256
}
5357

58+
fun observeNotes(uid: String) = callbackFlow{
59+
trySend(loadAllNotesTask(uid).await().children.mapNotNull {
60+
it.getValue(Note::class.java)?.toNoteEntity()
61+
})
62+
val listener = object : ValueEventListener {
63+
override fun onCancelled(error: DatabaseError) {}
64+
65+
override fun onDataChange(snapshot: DataSnapshot) {
66+
val notes = mutableListOf<Note>()
67+
snapshot.children.forEach { child ->
68+
child.getValue(Note::class.java)?.let { note ->
69+
notes.add(note)
70+
}
71+
}
72+
trySend(notes.map { note -> note.toNoteEntity() })
73+
}
74+
}
75+
refToPath("users/$uid/notes").addValueEventListener(listener)
76+
awaitClose { refToPath("users/$uid/notes").removeEventListener(listener) }
77+
}
78+
5479
fun updateNote(uid: String, note: Note) {
5580
refToPath("users/$uid/notes/${note.uuid}").setValue(note)
5681
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.viplearner.common.domain.datastore
22

3+
import androidx.datastore.preferences.core.booleanPreferencesKey
34
import androidx.datastore.preferences.core.stringPreferencesKey
45

56
object NotesDataStorePreferenceKeys {
67
const val NOTES_DATASTORE_PREFERENCES = "nomba_datastore_prefs"
78

89
val USER_DATA = stringPreferencesKey("user_data")
910
val PRIVATE_KEY = stringPreferencesKey("private_key")
11+
val SYNC_STATE = booleanPreferencesKey("sync_state")
1012
}

common/domain/src/main/java/com/viplearner/common/domain/datastore/NotesDataStoreRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ interface NotesDataStoreRepository {
1818
suspend fun clearUserData()
1919
suspend fun getPrivateKey(): Flow<String>
2020
suspend fun savePrivateKey(privateKey: String)
21+
suspend fun getSyncState(): Flow<Boolean>
22+
suspend fun setSyncState(value: Boolean)
2123
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.viplearner.common.domain.extensions
2+
3+
fun String?.isValidUrl(): Boolean {
4+
try {
5+
if (this == null) return false
6+
val url = java.net.URL(this)
7+
url.toURI()
8+
return true
9+
} catch (e: Exception) {
10+
return false
11+
}
12+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.viplearner.common.domain.firebase_database_repository
22

33
import com.viplearner.common.domain.entity.NoteEntity
4+
import kotlinx.coroutines.flow.Flow
45

56

67
interface DatabaseRepository {
78
suspend fun loadAllNotes(uid: String): List<NoteEntity>
89
suspend fun loadNote(uid: String, uuid: String): NoteEntity?
910
suspend fun saveNotes(uid: String, notes : List<NoteEntity>)
1011
suspend fun updateNote(uid: String, note: NoteEntity)
12+
suspend fun observeNotes(uid: String): Flow<List<NoteEntity>>
1113
}

0 commit comments

Comments
 (0)