Skip to content
This repository was archived by the owner on Feb 13, 2024. It is now read-only.
Open
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
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ You should have received a copy of the GNU General Public License along with Sim
<service
android:name=".MarkTaskDone"
/>
<service
android:name=".NotificationService"
/>
<receiver android:name="nl.mpcjanssen.simpletask.AlarmReceiver"/>
<uses-library
android:name="com.sec.android.app.multiwindow"
Expand Down
93 changes: 93 additions & 0 deletions app/src/main/java/nl/mpcjanssen/simpletask/NotificationService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package nl.mpcjanssen.simpletask

import android.app.Activity
import android.app.PendingIntent
import android.content.Intent
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.util.Log
import nl.mpcjanssen.simpletask.task.Task
import nl.mpcjanssen.simpletask.task.TodoList
import nl.mpcjanssen.simpletask.util.Config
import nl.mpcjanssen.simpletask.util.showToastShort
import nl.mpcjanssen.simpletask.util.todayAsString
import nl.mpcjanssen.simpletask.util.broadcastTasklistChanged
import java.io.IOException
import android.app.Service
import android.app.NotificationManager
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat

class NotificationService : Service() {
public override fun onCreate() {
val builder = NotificationCompat.Builder(this, "pin-notifications")
.setSmallIcon(R.drawable.ic_done_white_24dp)
.setGroup("group")
.setGroupSummary(true)
.setOngoing(true)
startForeground(1, builder.build())
}

public override fun onStartCommand (intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
Log.d(TAG, "onStartCommand()")
val taskIds = intent.getStringArrayExtra(Constants.EXTRA_TASK_ID)
Log.d(TAG, "got taskIds from extras ${taskIds?.joinToString(",")}")
if (taskIds == null) {
Log.e(TAG, "Extra ${Constants.EXTRA_TASK_ID} not found in intent")
return START_STICKY_COMPATIBILITY
}
pinNotifications(taskIds)
return START_REDELIVER_INTENT
}

private fun pinNotifications(taskIds: Array<String>) {
for (id in taskIds) {
val task = TodoApplication.todoList.getTaskWithId(id)
if (task == null) {
Log.e(TAG, "Task with id '$id' not found in todo list")
continue
}
val taskIdHash = task.id.hashCode()
val editTaskIntent = Intent(this, AddTask::class.java).let {
it.putExtra(Constants.EXTRA_TASK_ID, task.id)
PendingIntent.getActivity(this, taskIdHash, it, PendingIntent.FLAG_IMMUTABLE)
}
val markDoneIntent = Intent(this, MarkTaskDone::class.java).let {
it.putExtra(Constants.EXTRA_TASK_ID, task.id)
PendingIntent.getService(this, taskIdHash, it, PendingIntent.FLAG_IMMUTABLE)
}
var builder = NotificationCompat.Builder(this, "pin-notifications")
.setSmallIcon(R.drawable.ic_done_white_24dp)
.setContentTitle(task.text)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(editTaskIntent)
.addAction(R.drawable.ic_done_white_24dp, getString(R.string.done), markDoneIntent)
.addExtras(Bundle().apply { putString(Constants.EXTRA_TASK_ID, task.id) })
.setGroup("group")

with(NotificationManagerCompat.from(this)) {
notify(taskIdHash, builder.build())
}
if (!TodoApplication.config.hasKeepSelection) {
TodoApplication.todoList.clearSelection()
}
}
}

public override fun onBind(intent: Intent?): IBinder? {
return null
}

companion object {
val TAG = "NotificationService"

fun removeNotifications(taskIds: List<String>) {
taskIds.forEach{
TodoApplication.notificationManager.cancel(it.hashCode())
}
}
}
}
29 changes: 4 additions & 25 deletions app/src/main/java/nl/mpcjanssen/simpletask/Simpletask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1120,31 +1120,10 @@ class Simpletask : ThemedNoActionBarActivity() {
}

private fun pinNotification(checkedTasks: List<Task>) {
for (task in checkedTasks) {
val taskIdHash = task.id.hashCode()
val editTaskIntent = Intent(this, AddTask::class.java).let {
it.putExtra(Constants.EXTRA_TASK_ID, task.id)
PendingIntent.getActivity(this, taskIdHash, it, PendingIntent.FLAG_IMMUTABLE)
}
val markDoneIntent = Intent(this, MarkTaskDone::class.java).let {
it.putExtra(Constants.EXTRA_TASK_ID, task.id)
PendingIntent.getService(this, taskIdHash, it, PendingIntent.FLAG_IMMUTABLE)
}
var builder = NotificationCompat.Builder(this, "pin-notifications")
.setSmallIcon(R.drawable.ic_done_white_24dp)
.setContentTitle(task.text)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(editTaskIntent)
.addAction(R.drawable.ic_done_white_24dp, getString(R.string.done), markDoneIntent)
.addExtras(Bundle().apply { putString(Constants.EXTRA_TASK_ID, task.id) })

with(NotificationManagerCompat.from(this)) {
notify(taskIdHash, builder.build())
}
if (!TodoApplication.config.hasKeepSelection) {
TodoApplication.todoList.clearSelection()
}
}
val taskIds = checkedTasks.map { it.id }.toTypedArray()
val intent = Intent(this, NotificationService::class.java)
intent.putExtra(Constants.EXTRA_TASK_ID, taskIds)
startForegroundService(intent)
}

private inner class UiHandler () {
Expand Down
20 changes: 9 additions & 11 deletions app/src/main/java/nl/mpcjanssen/simpletask/TodoApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class TodoApplication : Application() {
db = Room.databaseBuilder(this,
AppDatabase::class.java, DB_FILE).fallbackToDestructiveMigration()
.build()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (config.forceEnglish) {
val conf = resources.configuration
conf.locale = Locale.ENGLISH
Expand Down Expand Up @@ -220,15 +221,13 @@ class TodoApplication : Application() {

fun updatePinnedNotifications() {
Log.i(TAG, "Updating pinned notifications")
val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.getActiveNotifications().forEach {
val taskId = it.notification.extras.getString(Constants.EXTRA_TASK_ID)
if (taskId != null) {
val taskText = TodoApplication.todoList.getTaskWithId(taskId)?.text
val notification = NotificationCompat.Builder(this, it.notification).setContentTitle(taskText).build()
notificationManager.notify(it.id, notification)
}
}
val taskIds = notificationManager.getActiveNotifications().map { it.notification.extras.getString(Constants.EXTRA_TASK_ID) }.filterNotNull().toTypedArray()
val (completedIds, incompleteIds) = taskIds.partition { todoList.getTaskWithId(it)?.isCompleted() ?: false }
NotificationService.removeNotifications(completedIds)
Log.i(TAG, "taskIds: $taskIds")
val intent = Intent(this, NotificationService::class.java)
intent.putExtra(Constants.EXTRA_TASK_ID, incompleteIds.toTypedArray())
startForegroundService(intent)
}

fun clearTodoFile() {
Expand Down Expand Up @@ -268,8 +267,6 @@ class TodoApplication : Application() {
description = descriptionText
}
// Register the channel with the system
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
Expand All @@ -282,6 +279,7 @@ class TodoApplication : Application() {
lateinit var config : Config
lateinit var todoList: TodoList
lateinit var db : AppDatabase
lateinit var notificationManager: NotificationManager
}
var today: String = todayAsString
}
Expand Down
36 changes: 36 additions & 0 deletions app/src/main/java/nl/mpcjanssen/simpletask/dao/TaskIdDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package nl.mpcjanssen.simpletask.dao

import nl.mpcjanssen.simpletask.TodoApplication
import nl.mpcjanssen.simpletask.task.Task
import android.content.Context.MODE_PRIVATE

object TaskIdDao {
val sharedPrefs = TodoApplication.app.getSharedPreferences("todolist", MODE_PRIVATE)
val editor = sharedPrefs.edit()

fun get(taskText: String): String? {
return sharedPrefs.getString(taskText, null)
}

fun add(tasks: List<Task>) {
tasks.forEach {
editor.putString(it.text, it.id)
}
editor.apply()
}

fun add(task: Task) {
add(listOf(task))
}

fun remove(tasks: List<Task>) {
tasks.forEach {
editor.remove(it.text)
}
editor.apply()
}

fun remove(task: Task) {
remove(listOf(task))
}
}
8 changes: 5 additions & 3 deletions app/src/main/java/nl/mpcjanssen/simpletask/task/Task.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import nl.mpcjanssen.simpletask.util.addInterval
import java.util.*
import java.util.regex.Pattern

class Task(text: String, defaultPrependedDate: String? = null) {
class Task(text: String, defaultPrependedDate: String? = null, val id: String = UUID.randomUUID().toString()) {

var tokens: ArrayList<TToken>

Expand All @@ -23,6 +23,10 @@ class Task(text: String, defaultPrependedDate: String? = null) {
tokens = parse(rawText)
}

fun withId(id: String): Task {
return Task(text, id = id)
}

private inline fun <reified T> getFirstToken(): T? {
tokens.filterIsInstance<T>().forEach {
return it
Expand All @@ -42,8 +46,6 @@ class Task(text: String, defaultPrependedDate: String? = null) {

}

var id: String = UUID.randomUUID().toString()

val text: String
get() {
return tokens.joinToString(" ") { it.text }
Expand Down
22 changes: 17 additions & 5 deletions app/src/main/java/nl/mpcjanssen/simpletask/task/TodoList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import nl.mpcjanssen.simpletask.remote.FileStore

import nl.mpcjanssen.simpletask.remote.IFileStore
import nl.mpcjanssen.simpletask.util.*
import nl.mpcjanssen.simpletask.dao.TaskIdDao
import java.io.File
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
Expand Down Expand Up @@ -45,7 +46,7 @@ class TodoList(val config: Config) {
} else {
todoItems.addAll(0, updatedItems)
}

TaskIdDao.add(items)
}

fun add(t: Task, atEnd: Boolean) {
Expand All @@ -57,7 +58,7 @@ class TodoList(val config: Config) {
Log.d(tag, "Remove")
pendingEdits.removeAll(tasks)
todoItems.removeAll(tasks)

TaskIdDao.remove(tasks)
}


Expand Down Expand Up @@ -160,10 +161,13 @@ class TodoList(val config: Config) {
val smallestSize = org.zip(updated) { orgTask, updatedTask ->
val idx = todoItems.indexOf(orgTask)
if (idx != -1) {
updatedTask.id = orgTask.id
todoItems[idx] = updatedTask
val newTask = updatedTask.withId(orgTask.id)
todoItems[idx] = newTask
TaskIdDao.remove(orgTask)
TaskIdDao.add(newTask)
} else {
todoItems.add(updatedTask)
TaskIdDao.add(updatedTask)
}
1
}.size
Expand Down Expand Up @@ -263,7 +267,15 @@ class TodoList(val config: Config) {
try {
val items = FileStore.loadTasksFromFile(file)

val newTodoItems = items.map { Task(it) }.toMutableList()
val newTodoItems = items.map {
val taskId = TaskIdDao.get(it)
if (taskId == null) {
val task = Task(it)
TaskIdDao.add(task)
task
}
else Task(it, id = taskId)
}.toMutableList()
synchronized(todoItems) {
Log.d(tag, "Fill todolist with ${items.size} items")
todoItems = newTodoItems
Expand Down
14 changes: 13 additions & 1 deletion app/src/main/java/nl/mpcjanssen/simpletask/util/Config.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package nl.mpcjanssen.simpletask.util

import android.content.Context.MODE_PRIVATE
import android.os.Build
import android.os.Environment
import android.preference.PreferenceManager
import android.util.Log
import androidx.annotation.RequiresApi
import me.smichel.android.KPreferences.Preferences
import nl.mpcjanssen.simpletask.*
import nl.mpcjanssen.simpletask.remote.FileStore
import nl.mpcjanssen.simpletask.task.Task
import nl.mpcjanssen.simpletask.dao.TaskIdDao
import org.json.JSONObject
import java.io.File
import java.util.*
Expand Down Expand Up @@ -229,7 +232,16 @@ class Config(app: TodoApplication) : Preferences(app) {
val lines = it.lines()
Log.i(TAG, "Getting ${lines.size} items todoList from cache")
ArrayList<Task>().apply {
addAll(lines.map { line -> Task(line) })
addAll(lines.map { line ->
val taskId = TaskIdDao.get(line)
if (taskId == null) {
val task = Task(line)
TaskIdDao.add(task)
task
} else {
Task(line, id = taskId)
}
})
}
}
set(items) {
Expand Down