Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/build
/release
/nightly
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ android {
applicationId = "co.adityarajput.notifilter"
minSdk = 29
targetSdk = 36
versionCode = 19
versionName = "4.2.0"
versionCode = 20
versionName = "4.3.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface FilterDao {
@Query("UPDATE filters SET hits = hits + 1 WHERE id = :id")
suspend fun registerHit(id: Int)

@Query("UPDATE filters SET historyEnabled = 1 - historyEnabled WHERE id = :id")
@Query("UPDATE filters SET historyEnabled = 1 - historyEnabled, hits = 0 WHERE id = :id")
suspend fun toggleHistory(id: Int)

@Query("UPDATE filters SET enabled = 1 - enabled WHERE id = :id")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package co.adityarajput.notifilter.data

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Query
import androidx.room.Upsert
import co.adityarajput.notifilter.data.models.Notification
Expand All @@ -17,6 +18,12 @@ interface NotificationDao {
@Query("SELECT COUNT(*) FROM notifications")
suspend fun count(): Int

@Delete
suspend fun delete(notification: Notification)

@Query("DELETE FROM notifications WHERE id IN (SELECT id FROM notifications ORDER BY timestamp ASC LIMIT :count)")
suspend fun trim(count: Int)

@Query("DELETE FROM notifications")
suspend fun deleteAll()
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,9 @@ class Repository(

suspend fun delete(filter: Filter) = filterDao.delete(filter)

suspend fun delete(notification: Notification) = notificationDao.delete(notification)

suspend fun deleteFilters() = filterDao.deleteAll()

suspend fun deleteNotifications() = notificationDao.deleteAll()
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class FiltersViewModel(private val repository: Repository) : ViewModel() {
.map { State(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), State())

var dialogState by mutableStateOf<DialogState?>(null)
var dialogState by mutableStateOf<FilterDialogState?>(null)

var selectedFilter by mutableStateOf<Filter?>(null)

Expand All @@ -47,4 +47,4 @@ class FiltersViewModel(private val repository: Repository) : ViewModel() {
}
}

enum class DialogState { TOGGLE_HISTORY, TOGGLE_FILTER, DELETE }
enum class FilterDialogState { TOGGLE_HISTORY, TOGGLE_FILTER, DELETE }
Original file line number Diff line number Diff line change
@@ -1,19 +1,44 @@
package co.adityarajput.notifilter.viewmodels

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import co.adityarajput.notifilter.data.Repository
import co.adityarajput.notifilter.data.models.Notification
import co.adityarajput.notifilter.utils.Logger
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

class NotificationsViewModel(repository: Repository) : ViewModel() {
class NotificationsViewModel(val repository: Repository) : ViewModel() {
data class State(val notifications: List<Notification>? = null)

val state: StateFlow<State> =
repository.notifications()
.map { State(it) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), State())

var selectedNotification by mutableStateOf<Notification?>(null)

var dialogState by mutableStateOf<NotificationDialogState?>(null)

fun delete(notification: Notification) {
viewModelScope.launch {
Logger.d("NotificationsViewModel", "Deleting $notification")
repository.delete(notification)
}
}

fun clearHistory() {
viewModelScope.launch {
Logger.d("NotificationsViewModel", "Deleting all notifications")
repository.deleteNotifications()
}
}
}

enum class NotificationDialogState { CLEAR_HISTORY }
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import co.adityarajput.notifilter.R
import co.adityarajput.notifilter.utils.getToggleString
import co.adityarajput.notifilter.viewmodels.DialogState
import co.adityarajput.notifilter.viewmodels.FilterDialogState
import co.adityarajput.notifilter.viewmodels.FiltersViewModel

@Composable
Expand All @@ -22,33 +22,33 @@ fun ManageFilterDialog(viewModel: FiltersViewModel) {
title = {
Text(
when (dialogState) {
DialogState.TOGGLE_HISTORY -> stringResource(
FilterDialogState.TOGGLE_HISTORY -> stringResource(
R.string.toggle_history,
filter.historyEnabled.getToggleString(),
)

DialogState.TOGGLE_FILTER -> stringResource(
FilterDialogState.TOGGLE_FILTER -> stringResource(
R.string.toggle_filter,
filter.enabled.getToggleString(),
)

DialogState.DELETE -> stringResource(R.string.delete_filter)
FilterDialogState.DELETE -> stringResource(R.string.delete_filter)
},
)
},
text = {
Text(
when (dialogState) {
DialogState.TOGGLE_HISTORY -> stringResource(
FilterDialogState.TOGGLE_HISTORY -> stringResource(
if (filter.historyEnabled) R.string.disable_history_confirmation else R.string.enable_history_confirmation,
)

DialogState.TOGGLE_FILTER -> stringResource(
FilterDialogState.TOGGLE_FILTER -> stringResource(
R.string.toggle_filter_confirmation,
filter.enabled.getToggleString(),
)

DialogState.DELETE -> stringResource(
FilterDialogState.DELETE -> stringResource(
R.string.delete_confirmation,
if (filter.enabled) stringResource(R.string.disable_suggestion) else "",
)
Expand All @@ -60,22 +60,22 @@ fun ManageFilterDialog(viewModel: FiltersViewModel) {
TextButton(
{
when (dialogState) {
DialogState.TOGGLE_HISTORY -> viewModel.toggleHistory()
DialogState.TOGGLE_FILTER -> viewModel.toggleFilter()
DialogState.DELETE -> viewModel.deleteFilter()
FilterDialogState.TOGGLE_HISTORY -> viewModel.toggleHistory()
FilterDialogState.TOGGLE_FILTER -> viewModel.toggleFilter()
FilterDialogState.DELETE -> viewModel.deleteFilter()
}
hideDialog()
},
colors = ButtonDefaults.textButtonColors(
contentColor = if (dialogState == DialogState.DELETE) MaterialTheme.colorScheme.tertiary
contentColor = if (dialogState == FilterDialogState.DELETE) MaterialTheme.colorScheme.tertiary
else Color.Unspecified,
),
) {
Text(
when (dialogState) {
DialogState.TOGGLE_HISTORY -> filter.historyEnabled.getToggleString()
DialogState.TOGGLE_FILTER -> filter.enabled.getToggleString()
DialogState.DELETE -> stringResource(R.string.delete)
FilterDialogState.TOGGLE_HISTORY -> filter.historyEnabled.getToggleString()
FilterDialogState.TOGGLE_FILTER -> filter.enabled.getToggleString()
FilterDialogState.DELETE -> stringResource(R.string.delete)
},
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package co.adityarajput.notifilter.views.components

import androidx.compose.foundation.layout.Row
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import co.adityarajput.notifilter.R
import co.adityarajput.notifilter.viewmodels.NotificationsViewModel

@Composable
fun ManageHistoryDialog(viewModel: NotificationsViewModel) {
val hideDialog = { viewModel.dialogState = null }

AlertDialog(
hideDialog,
title = { Text(stringResource(R.string.clear_history)) },
text = { Text(stringResource(R.string.clear_history_confirmation)) },
confirmButton = {
Row {
TextButton(
{ viewModel.clearHistory(); hideDialog() },
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.tertiary),
) { Text(stringResource(R.string.clear_history)) }
}
},
dismissButton = {
TextButton(hideDialog) {
Text(stringResource(R.string.cancel), fontWeight = FontWeight.Normal)
}
},
)
}
100 changes: 0 additions & 100 deletions app/src/main/java/co/adityarajput/notifilter/views/components/Tile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import co.adityarajput.notifilter.R
import co.adityarajput.notifilter.data.models.*
import co.adityarajput.notifilter.utils.getFirst
import co.adityarajput.notifilter.utils.toShortHumanReadableTime
import co.adityarajput.notifilter.views.Theme

@Composable
fun Tile(
Expand Down Expand Up @@ -92,96 +85,3 @@ fun Tile(
}
}
}

@Preview
@Composable
private fun FilterTiles() {
val filters = listOf(
Filter(
App("Clock", "com.google.android.deskclock"),
"Upcoming alarm",
Action.DISMISS,
RegexTarget.TITLE,
enabled = false,
),
Filter(
App("Software update", "com.wssyncmldm"),
"software update",
Action.TAP_BUTTON("Remind me"),
RegexTarget.CONTENT,
schedule = Schedule(days = setOf(2, 3, 4, 5, 6)),
hits = 23,
),
Filter(
App("Gmail", "com.google.android.gm"),
"[Nn]ewsletter",
Action.BATCH(3),
RegexTarget.OR,
historyEnabled = false,
),
Filter(
App("WhatsApp", "com.whatsapp"),
"Book Club",
Action.DELAY,
RegexTarget.AND,
"^Bob",
schedule = Schedule(start = 9 * 60, end = 17 * 60),
hits = 15,
),
Filter(
App("WhatsApp", "com.whatsapp"),
"Roommate",
Action.DEBOUNCE(2),
RegexTarget.TITLE,
historyEnabled = false,
),
)

Theme {
Column {
for (filter in filters)
Tile(
buildString {
append("/")
append(filter.regexPattern)
append("/")

if (filter.regexTarget == RegexTarget.AND) {
append(" && /")
append(filter.secondaryRegexPattern)
append("/")
}
},
filter.action.verb(),
filter.app.name.getFirst(30),
if (!filter.enabled) stringResource(R.string.filter_disabled)
else if (!filter.historyEnabled) stringResource(R.string.history_disabled)
else pluralStringResource(R.plurals.hit, filter.hits, filter.hits),
filter.schedule.description,
{ },
{ Text("BUTTONS") },
filter.enabled,
)
}
}
}

@Preview
@Composable
private fun NotificationTile() {
val notification = Notification(
"Notification Title",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.",
"App Name",
System.currentTimeMillis() - 12345600,
)

Theme {
Tile(
notification.title,
notification.content,
notification.origin.getFirst(30),
notification.timestamp.toShortHumanReadableTime(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import co.adityarajput.notifilter.data.models.Any
import co.adityarajput.notifilter.data.models.RegexTarget
import co.adityarajput.notifilter.utils.getFirst
import co.adityarajput.notifilter.utils.getToggleString
import co.adityarajput.notifilter.viewmodels.DialogState
import co.adityarajput.notifilter.viewmodels.FilterDialogState
import co.adityarajput.notifilter.viewmodels.FiltersViewModel
import co.adityarajput.notifilter.viewmodels.Provider
import co.adityarajput.notifilter.views.components.AppBar
Expand Down Expand Up @@ -112,7 +112,11 @@ fun FiltersScreen(
else viewModel.selectedFilter = it
},
{
IconButton({ viewModel.dialogState = DialogState.TOGGLE_HISTORY }) {
IconButton(
{
viewModel.dialogState = FilterDialogState.TOGGLE_HISTORY
},
) {
Icon(
painterResource(R.drawable.manage_history),
stringResource(
Expand All @@ -121,7 +125,11 @@ fun FiltersScreen(
),
)
}
IconButton({ viewModel.dialogState = DialogState.TOGGLE_FILTER }) {
IconButton(
{
viewModel.dialogState = FilterDialogState.TOGGLE_FILTER
},
) {
Icon(
if (it.enabled) painterResource(R.drawable.archive)
else painterResource(R.drawable.unarchive),
Expand All @@ -138,7 +146,7 @@ fun FiltersScreen(
)
}
IconButton(
{ viewModel.dialogState = DialogState.DELETE },
{ viewModel.dialogState = FilterDialogState.DELETE },
colors = IconButtonDefaults.iconButtonColors(
contentColor = MaterialTheme.colorScheme.tertiary,
),
Expand Down
Loading