Skip to content

Commit 9435d38

Browse files
committed
Display selected notifications in homescreen widget
1 parent e364795 commit 9435d38

24 files changed

Lines changed: 603 additions & 63 deletions

File tree

app/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,15 @@ dependencies {
8484
ksp(libs.androidx.room.compiler)
8585
implementation(libs.kotlinx.serialization.json)
8686
implementation(libs.androidx.room.ktx)
87+
implementation(libs.androidx.glance.appwidget)
88+
implementation(libs.androidx.glance.material3)
8789
testImplementation(libs.junit)
8890
androidTestImplementation(libs.androidx.junit)
8991
androidTestImplementation(libs.androidx.espresso.core)
9092
androidTestImplementation(platform(libs.androidx.compose.bom))
9193
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
9294
debugImplementation(libs.androidx.compose.ui.tooling)
9395
debugImplementation(libs.androidx.compose.ui.test.manifest)
96+
debugImplementation(libs.androidx.glance.preview)
97+
debugImplementation(libs.androidx.glance.appwidget.preview)
9498
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
{
2+
"formatVersion": 1,
3+
"database": {
4+
"version": 11,
5+
"identityHash": "5a4d946a922bfa0ba8b42571ca3b51da",
6+
"entities": [
7+
{
8+
"tableName": "filters",
9+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`regexPattern` TEXT NOT NULL, `action` TEXT NOT NULL, `regexTarget` TEXT NOT NULL, `secondaryRegexPattern` TEXT, `enabled` INTEGER NOT NULL, `historyEnabled` INTEGER NOT NULL, `widgetEnabled` INTEGER NOT NULL DEFAULT 0, `hits` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `app_name` TEXT NOT NULL, `app_packageName` TEXT NOT NULL, `schedule_start` INTEGER NOT NULL, `schedule_end` INTEGER NOT NULL, `schedule_days` TEXT NOT NULL)",
10+
"fields": [
11+
{
12+
"fieldPath": "regexPattern",
13+
"columnName": "regexPattern",
14+
"affinity": "TEXT",
15+
"notNull": true
16+
},
17+
{
18+
"fieldPath": "action",
19+
"columnName": "action",
20+
"affinity": "TEXT",
21+
"notNull": true
22+
},
23+
{
24+
"fieldPath": "regexTarget",
25+
"columnName": "regexTarget",
26+
"affinity": "TEXT",
27+
"notNull": true
28+
},
29+
{
30+
"fieldPath": "secondaryRegexPattern",
31+
"columnName": "secondaryRegexPattern",
32+
"affinity": "TEXT"
33+
},
34+
{
35+
"fieldPath": "enabled",
36+
"columnName": "enabled",
37+
"affinity": "INTEGER",
38+
"notNull": true
39+
},
40+
{
41+
"fieldPath": "historyEnabled",
42+
"columnName": "historyEnabled",
43+
"affinity": "INTEGER",
44+
"notNull": true
45+
},
46+
{
47+
"fieldPath": "widgetEnabled",
48+
"columnName": "widgetEnabled",
49+
"affinity": "INTEGER",
50+
"notNull": true,
51+
"defaultValue": "0"
52+
},
53+
{
54+
"fieldPath": "hits",
55+
"columnName": "hits",
56+
"affinity": "INTEGER",
57+
"notNull": true
58+
},
59+
{
60+
"fieldPath": "id",
61+
"columnName": "id",
62+
"affinity": "INTEGER",
63+
"notNull": true
64+
},
65+
{
66+
"fieldPath": "app.name",
67+
"columnName": "app_name",
68+
"affinity": "TEXT",
69+
"notNull": true
70+
},
71+
{
72+
"fieldPath": "app.packageName",
73+
"columnName": "app_packageName",
74+
"affinity": "TEXT",
75+
"notNull": true
76+
},
77+
{
78+
"fieldPath": "schedule.start",
79+
"columnName": "schedule_start",
80+
"affinity": "INTEGER",
81+
"notNull": true
82+
},
83+
{
84+
"fieldPath": "schedule.end",
85+
"columnName": "schedule_end",
86+
"affinity": "INTEGER",
87+
"notNull": true
88+
},
89+
{
90+
"fieldPath": "schedule.days",
91+
"columnName": "schedule_days",
92+
"affinity": "TEXT",
93+
"notNull": true
94+
}
95+
],
96+
"primaryKey": {
97+
"autoGenerate": true,
98+
"columnNames": [
99+
"id"
100+
]
101+
}
102+
},
103+
{
104+
"tableName": "notifications",
105+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `content` TEXT NOT NULL, `origin` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `showInHistory` INTEGER NOT NULL DEFAULT 1, `showInWidget` INTEGER NOT NULL DEFAULT 0, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
106+
"fields": [
107+
{
108+
"fieldPath": "title",
109+
"columnName": "title",
110+
"affinity": "TEXT",
111+
"notNull": true
112+
},
113+
{
114+
"fieldPath": "content",
115+
"columnName": "content",
116+
"affinity": "TEXT",
117+
"notNull": true
118+
},
119+
{
120+
"fieldPath": "origin",
121+
"columnName": "origin",
122+
"affinity": "TEXT",
123+
"notNull": true
124+
},
125+
{
126+
"fieldPath": "timestamp",
127+
"columnName": "timestamp",
128+
"affinity": "INTEGER",
129+
"notNull": true
130+
},
131+
{
132+
"fieldPath": "showInHistory",
133+
"columnName": "showInHistory",
134+
"affinity": "INTEGER",
135+
"notNull": true,
136+
"defaultValue": "1"
137+
},
138+
{
139+
"fieldPath": "showInWidget",
140+
"columnName": "showInWidget",
141+
"affinity": "INTEGER",
142+
"notNull": true,
143+
"defaultValue": "0"
144+
},
145+
{
146+
"fieldPath": "id",
147+
"columnName": "id",
148+
"affinity": "INTEGER",
149+
"notNull": true
150+
}
151+
],
152+
"primaryKey": {
153+
"autoGenerate": true,
154+
"columnNames": [
155+
"id"
156+
]
157+
}
158+
}
159+
],
160+
"setupQueries": [
161+
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
162+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5a4d946a922bfa0ba8b42571ca3b51da')"
163+
]
164+
}
165+
}

app/src/main/AndroidManifest.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@
3232
<category android:name="android.intent.category.LAUNCHER" />
3333
</intent-filter>
3434
</activity>
35+
<receiver
36+
android:name=".WidgetReceiver"
37+
android:exported="true">
38+
<intent-filter>
39+
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
40+
</intent-filter>
41+
<meta-data
42+
android:name="android.appwidget.provider"
43+
android:resource="@xml/widget_info" />
44+
</receiver>
45+
3546

3647
<service
3748
android:name=".services.NotificationListener"

app/src/main/java/co/adityarajput/notifilter/MainActivity.kt

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ import androidx.activity.enableEdgeToEdge
2525
import androidx.compose.foundation.layout.fillMaxSize
2626
import androidx.compose.material3.MaterialTheme
2727
import androidx.compose.material3.Surface
28-
import androidx.compose.runtime.Composable
2928
import androidx.compose.ui.Modifier
30-
import androidx.compose.ui.tooling.preview.Preview
3129
import androidx.lifecycle.lifecycleScope
32-
import androidx.navigation.NavHostController
3330
import androidx.navigation.compose.rememberNavController
3431
import co.adityarajput.notifilter.data.Cache
3532
import co.adityarajput.notifilter.views.Navigator
@@ -54,16 +51,8 @@ class MainActivity : ComponentActivity() {
5451
Surface(
5552
Modifier.fillMaxSize(),
5653
color = MaterialTheme.colorScheme.background,
57-
) {
58-
NotiFilter()
59-
}
54+
) { Navigator(rememberNavController()) }
6055
}
6156
}
6257
}
6358
}
64-
65-
@Preview
66-
@Composable
67-
fun NotiFilter(navController: NavHostController = rememberNavController()) {
68-
Navigator(navController)
69-
}

app/src/main/java/co/adityarajput/notifilter/NotiFilterApplication.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ package co.adityarajput.notifilter
33
import android.app.Application
44
import android.content.pm.ApplicationInfo
55
import co.adityarajput.notifilter.data.AppContainer
6+
import co.adityarajput.notifilter.utils.pushWidgetPreview
7+
import co.adityarajput.notifilter.utils.subscribeWidgetToFlow
8+
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.SupervisorJob
11+
import kotlinx.coroutines.launch
612

713
class NotiFilterApplication : Application() {
814
lateinit var container: AppContainer
@@ -16,5 +22,10 @@ class NotiFilterApplication : Application() {
1622
// INFO: While debugging, populate database with demo data for screenshots
1723
container.seedDemoData()
1824
}
25+
26+
CoroutineScope(SupervisorJob() + Dispatchers.IO).launch {
27+
this@NotiFilterApplication.pushWidgetPreview()
28+
subscribeWidgetToFlow(this@NotiFilterApplication, container.repository.log())
29+
}
1930
}
2031
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package co.adityarajput.notifilter
2+
3+
import androidx.glance.appwidget.GlanceAppWidgetReceiver
4+
import co.adityarajput.notifilter.views.Widget
5+
6+
class WidgetReceiver : GlanceAppWidgetReceiver() {
7+
override val glanceAppWidget = Widget()
8+
}

app/src/main/java/co/adityarajput/notifilter/data/AppContainer.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class AppContainer(private val context: Context) {
5656
"[Nn]ewsletter",
5757
Action.BATCH(3),
5858
RegexTarget.OR,
59-
historyEnabled = false,
59+
widgetEnabled = true,
60+
hits = 1,
6061
),
6162
Filter(
6263
App("WhatsApp", "com.whatsapp"),
@@ -121,6 +122,7 @@ class AppContainer(private val context: Context) {
121122
"The week: a microphone, a ropeway, and something very sour.\nHello!\nOver the last few days...",
122123
"Gmail",
123124
System.currentTimeMillis() - 3 * 60 * 60 * 1000,
125+
showInWidget = true,
124126
),
125127
Notification(
126128
"Book Club",

app/src/main/java/co/adityarajput/notifilter/data/Database.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import co.adityarajput.notifilter.data.models.Notification
1010

1111
@Database(
1212
entities = [Filter::class, Notification::class],
13-
version = 10,
13+
version = 11,
1414
autoMigrations = [
1515
AutoMigration(1, 2), AutoMigration(2, 3), AutoMigration(3, 4),
1616
AutoMigration(4, 5), AutoMigration(5, 6),
1717
AutoMigration(6, 7, NotiFilterDatabase.DeleteTableAN::class),
18-
AutoMigration(7, 8), AutoMigration(8, 9),
18+
AutoMigration(7, 8), AutoMigration(8, 9), AutoMigration(10, 11),
1919
],
2020
)
2121
@TypeConverters(Converters::class)

app/src/main/java/co/adityarajput/notifilter/data/NotificationDao.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ interface NotificationDao {
1515
@Query("SELECT * FROM notifications ORDER BY id DESC")
1616
fun list(): Flow<List<Notification>>
1717

18+
@Query("SELECT * FROM notifications WHERE showInHistory = 1 ORDER BY id DESC")
19+
fun history(): Flow<List<Notification>>
20+
21+
@Query("SELECT * FROM notifications WHERE showInWidget = 1 ORDER BY id DESC")
22+
fun widget(): Flow<List<Notification>>
23+
1824
@Query("SELECT COUNT(*) FROM notifications")
1925
suspend fun count(): Int
2026

app/src/main/java/co/adityarajput/notifilter/data/Repository.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class Repository(
1616

1717
fun notifications() = notificationDao.list()
1818

19+
fun history() = notificationDao.history()
20+
21+
fun log() = notificationDao.widget()
22+
1923
suspend fun registerHit(filter: Filter, notification: Notification) {
2024
filterDao.registerHit(filter.id)
2125
notificationDao.upsert(notification)

0 commit comments

Comments
 (0)