Skip to content

Commit 13a5af2

Browse files
phpbgsamuelchemla
andauthored
Show notification on error (#34)
* Add error table, fill it and show notification * Add error activity * Warning instead of error on sync error * Use lazy column --------- Co-authored-by: Samuel CHEMLA <[email protected]>
1 parent dbde987 commit 13a5af2

27 files changed

+515
-89
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
{
2+
"formatVersion": 1,
3+
"database": {
4+
"version": 2,
5+
"identityHash": "555c0e853832f7aa52c9b3bf77b55a87",
6+
"entities": [
7+
{
8+
"tableName": "File",
9+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`pathname` TEXT NOT NULL, `local_pathname` TEXT NOT NULL, `id` INTEGER NOT NULL, `remote_date_changed` INTEGER, `local_date_changed` INTEGER, `etag` TEXT, `is_collection` INTEGER NOT NULL, PRIMARY KEY(`pathname`))",
10+
"fields": [
11+
{
12+
"fieldPath": "pathname",
13+
"columnName": "pathname",
14+
"affinity": "TEXT",
15+
"notNull": true
16+
},
17+
{
18+
"fieldPath": "localPathname",
19+
"columnName": "local_pathname",
20+
"affinity": "TEXT",
21+
"notNull": true
22+
},
23+
{
24+
"fieldPath": "id",
25+
"columnName": "id",
26+
"affinity": "INTEGER",
27+
"notNull": true
28+
},
29+
{
30+
"fieldPath": "remoteDateChanged",
31+
"columnName": "remote_date_changed",
32+
"affinity": "INTEGER",
33+
"notNull": false
34+
},
35+
{
36+
"fieldPath": "localDateChanged",
37+
"columnName": "local_date_changed",
38+
"affinity": "INTEGER",
39+
"notNull": false
40+
},
41+
{
42+
"fieldPath": "etag",
43+
"columnName": "etag",
44+
"affinity": "TEXT",
45+
"notNull": false
46+
},
47+
{
48+
"fieldPath": "isCollection",
49+
"columnName": "is_collection",
50+
"affinity": "INTEGER",
51+
"notNull": true
52+
}
53+
],
54+
"primaryKey": {
55+
"autoGenerate": false,
56+
"columnNames": [
57+
"pathname"
58+
]
59+
},
60+
"indices": [
61+
{
62+
"name": "index_File_id",
63+
"unique": true,
64+
"columnNames": [
65+
"id"
66+
],
67+
"orders": [],
68+
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_File_id` ON `${TABLE_NAME}` (`id`)"
69+
}
70+
],
71+
"foreignKeys": []
72+
},
73+
{
74+
"tableName": "Error",
75+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `created_date` INTEGER, `path` TEXT NOT NULL, `message` TEXT NOT NULL)",
76+
"fields": [
77+
{
78+
"fieldPath": "id",
79+
"columnName": "id",
80+
"affinity": "INTEGER",
81+
"notNull": true
82+
},
83+
{
84+
"fieldPath": "createdDate",
85+
"columnName": "created_date",
86+
"affinity": "INTEGER",
87+
"notNull": false
88+
},
89+
{
90+
"fieldPath": "path",
91+
"columnName": "path",
92+
"affinity": "TEXT",
93+
"notNull": true
94+
},
95+
{
96+
"fieldPath": "message",
97+
"columnName": "message",
98+
"affinity": "TEXT",
99+
"notNull": true
100+
}
101+
],
102+
"primaryKey": {
103+
"autoGenerate": true,
104+
"columnNames": [
105+
"id"
106+
]
107+
},
108+
"indices": [],
109+
"foreignKeys": []
110+
}
111+
],
112+
"views": [],
113+
"setupQueries": [
114+
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
115+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '555c0e853832f7aa52c9b3bf77b55a87')"
116+
]
117+
}
118+
}

app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@
2323
android:label="@string/flavored_app_name"
2424
android:localeConfig="@xml/locales_config"
2525
android:networkSecurityConfig="@xml/network_security_config"
26+
android:requestLegacyExternalStorage="true"
2627
android:roundIcon="@mipmap/ic_launcher_round"
2728
android:supportsRtl="true"
28-
android:requestLegacyExternalStorage="true"
2929
android:theme="@style/Theme.MyApplication"
3030
tools:targetApi="31">
31+
<activity
32+
android:name=".ui.SyncErrorsActivity"
33+
android:exported="false"
34+
android:label="@string/sync_errors_activity_title"
35+
android:launchMode="singleTop" />
3136
<activity
3237
android:name=".ui.PermissionsActivity"
3338
android:exported="false"
@@ -46,7 +51,7 @@
4651
<activity
4752
android:name=".ui.MainActivity"
4853
android:exported="true"
49-
android:launchMode="singleTop" >
54+
android:launchMode="singleTop">
5055
<intent-filter>
5156
<action android:name="android.intent.action.MAIN" />
5257

app/src/main/java/com/phpbg/easysync/Notifications.kt

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,38 @@
2424

2525
package com.phpbg.easysync
2626

27+
import android.app.Notification
28+
import android.app.NotificationChannel
29+
import android.app.NotificationManager
30+
import android.app.PendingIntent
31+
import android.content.Context
32+
import android.content.Intent
33+
import com.phpbg.easysync.ui.MainActivity
34+
2735
enum class Notifications(val id: Int) {
28-
MISSING_PERMISSIONS(1),
29-
TRIAL_EXPIRED(2)
36+
MISSING_PERMISSIONS(1), TRIAL_EXPIRED(2)
37+
}
38+
39+
fun showNotification(
40+
context: Context, title: String, text: String, notificationId: Notifications
41+
) {
42+
val notificationManager =
43+
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
44+
45+
val intent = Intent(context, MainActivity::class.java).apply {
46+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
47+
}
48+
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
49+
50+
val id = context.getString(R.string.notification_channel_id)
51+
val channel = NotificationChannel(
52+
id, "Synchronization status", NotificationManager.IMPORTANCE_LOW
53+
)
54+
notificationManager.createNotificationChannel(channel)
55+
56+
val notification = Notification.Builder(context, id).setContentTitle(title).setContentText(text)
57+
.setTicker(title).setSmallIcon(R.drawable.ic_launcher_background).setOnlyAlertOnce(true)
58+
.setAutoCancel(true).setContentIntent(pendingIntent).build()
59+
60+
notificationManager.notify(notificationId.id, notification)
3061
}

app/src/main/java/com/phpbg/easysync/db/AppDatabase.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@
2424

2525
package com.phpbg.easysync.db
2626

27+
import androidx.room.AutoMigration
2728
import androidx.room.Database
2829
import androidx.room.RoomDatabase
2930
import androidx.room.TypeConverters
3031

3132
@Database(
32-
entities = [File::class], version = 1, autoMigrations = [
33-
]
33+
entities = [File::class, Error::class],
34+
version = 2,
35+
autoMigrations = [AutoMigration(from = 1, to = 2)],
3436
)
3537
@TypeConverters(Converters::class)
3638
abstract class AppDatabase : RoomDatabase() {
3739
abstract fun fileDao(): FileDao
40+
41+
abstract fun errorDao(): ErrorDao
3842
}

app/src/main/java/com/phpbg/easysync/db/AppDatabaseFactory.kt

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,13 @@ package com.phpbg.easysync.db
2626

2727
import android.content.Context
2828
import androidx.room.Room
29-
import androidx.room.migration.Migration
30-
import androidx.sqlite.db.SupportSQLiteDatabase
31-
32-
val MIGRATION_1_2 = object : Migration(1, 2) {
33-
override fun migrate(db: SupportSQLiteDatabase) {
34-
db.execSQL("ALTER TABLE File ADD COLUMN is_collection INTEGER NOT NULL DEFAULT(0)")
35-
}
36-
}
37-
3829

3930
object AppDatabaseFactory {
4031
fun create(context: Context): AppDatabase {
4132
return Room.databaseBuilder(
4233
context,
4334
AppDatabase::class.java, "appdatabase"
4435
)
45-
.addMigrations(MIGRATION_1_2)
4636
.enableMultiInstanceInvalidation()
4737
.build()
4838
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2024 Samuel CHEMLA
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.phpbg.easysync.db
26+
27+
import androidx.room.ColumnInfo
28+
import androidx.room.Entity
29+
import androidx.room.PrimaryKey
30+
import java.time.Instant
31+
32+
@Entity
33+
data class Error(
34+
@PrimaryKey(autoGenerate = true) val id: Long = 0,
35+
36+
@ColumnInfo(name = "created_date") val createdDate: Instant?,
37+
38+
val path: String,
39+
40+
val message: String,
41+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2024 Samuel CHEMLA
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package com.phpbg.easysync.db
26+
27+
import androidx.lifecycle.LiveData
28+
import androidx.room.Dao
29+
import androidx.room.Insert
30+
import androidx.room.Query
31+
32+
@Dao
33+
interface ErrorDao {
34+
@Query("SELECT * FROM error")
35+
fun getAll(): LiveData<List<Error>>
36+
37+
@Query("SELECT COUNT(id) FROM error")
38+
fun count(): LiveData<Int>
39+
40+
@Query("DELETE FROM error")
41+
suspend fun deleteAll(): Int
42+
43+
@Insert
44+
suspend fun insertAll(vararg errors: Error)
45+
}

app/src/main/java/com/phpbg/easysync/ui/DavSettingsActivity.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ import androidx.compose.ui.unit.dp
6767
import com.phpbg.easysync.R
6868
import com.phpbg.easysync.settings.Settings
6969
import com.phpbg.easysync.ui.components.Title
70-
import com.phpbg.easysync.ui.theme.MyApplicationTheme
70+
import com.phpbg.easysync.ui.theme.EasySyncTheme
7171

7272
class DavSettingsActivity : ComponentActivity() {
7373

@@ -78,7 +78,7 @@ class DavSettingsActivity : ComponentActivity() {
7878
viewModel.load()
7979

8080
setContent {
81-
MyApplicationTheme {
81+
EasySyncTheme {
8282
// A surface container using the 'background' color from the theme
8383
Surface(
8484
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background
@@ -203,15 +203,15 @@ private fun Preferences(
203203
@Preview(name = "FR", showBackground = true, locale = "fr")
204204
@Composable
205205
private fun PreferencesPreview() {
206-
MyApplicationTheme {
206+
EasySyncTheme {
207207
Preferences(uiState = DavSettingsUiState(), stateChangeHandler = { }, saveHandler = { })
208208
}
209209
}
210210

211211
@Preview(name = "Light Mode", showBackground = true)
212212
@Composable
213213
private fun PreferencesPreviewWithCircularIndicator() {
214-
MyApplicationTheme {
214+
EasySyncTheme {
215215
Preferences(uiState = DavSettingsUiState(ongoingIO = true), stateChangeHandler = { }, saveHandler = { })
216216
}
217217
}

0 commit comments

Comments
 (0)