From 03c92c8bee7fef598b444052a5788c1b9ababbe3 Mon Sep 17 00:00:00 2001 From: Brendan Gregos Date: Fri, 24 Mar 2023 21:45:41 -0400 Subject: [PATCH 1/2] add basic skeleton for implementation of task file based storage --- .../foreground/data/tasks/TaskFileStorage.kt | 15 +++++++++ .../foreground/data/tasks/TaskRepository.kt | 6 ++-- .../me/bgregos/foreground/di/TaskModule.kt | 32 +++++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/me/bgregos/foreground/data/tasks/TaskFileStorage.kt diff --git a/app/src/main/java/me/bgregos/foreground/data/tasks/TaskFileStorage.kt b/app/src/main/java/me/bgregos/foreground/data/tasks/TaskFileStorage.kt new file mode 100644 index 0000000..52d7ce9 --- /dev/null +++ b/app/src/main/java/me/bgregos/foreground/data/tasks/TaskFileStorage.kt @@ -0,0 +1,15 @@ +package me.bgregos.foreground.data.tasks + +import java.io.File +import javax.inject.Inject +import javax.inject.Named + +class TaskFileStorage @Inject constructor( + @Named("InternalFiles") val internalFileDir: File, + @Named("ExternalFiles") val eternalFileDir: File? +) { + /* + Implement save and load functions for each of internal files and external files, then have + TaskRepository call the functions as appropriate based on user preference. + */ +} \ No newline at end of file diff --git a/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt b/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt index c2bf232..1ad9af9 100644 --- a/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt +++ b/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt @@ -23,8 +23,10 @@ import kotlin.collections.ArrayList @Singleton class TaskRepository @Inject constructor( - private val prefs: SharedPreferences, - private val remoteTaskSource: RemoteTaskSource) { + private val prefs: SharedPreferences, + private val remoteTaskSource: RemoteTaskSource, + private val taskFileStorage: TaskFileStorage +) { var tasks: MutableStateFlow> = MutableStateFlow(listOf()) val localChanges: MutableStateFlow> = MutableStateFlow(listOf()) diff --git a/app/src/main/java/me/bgregos/foreground/di/TaskModule.kt b/app/src/main/java/me/bgregos/foreground/di/TaskModule.kt index 09c7530..92ae33a 100644 --- a/app/src/main/java/me/bgregos/foreground/di/TaskModule.kt +++ b/app/src/main/java/me/bgregos/foreground/di/TaskModule.kt @@ -6,10 +6,13 @@ import android.content.SharedPreferences import dagger.Module import dagger.Provides import me.bgregos.foreground.data.taskfilter.TaskFilterRepository +import me.bgregos.foreground.data.tasks.TaskFileStorage import me.bgregos.foreground.network.RemoteTaskSource import me.bgregos.foreground.network.RemoteTaskSourceImpl import me.bgregos.foreground.data.tasks.TaskRepository import me.bgregos.foreground.util.NotificationRepository +import java.io.File +import javax.inject.Named import javax.inject.Singleton @Module @@ -24,8 +27,12 @@ abstract class TaskModule { @Singleton @Provides - fun provideTaskRepository(sharedPreferences: SharedPreferences, remoteTaskSource: RemoteTaskSource): TaskRepository { - return TaskRepository(sharedPreferences, remoteTaskSource) + fun provideTaskRepository( + sharedPreferences: SharedPreferences, + remoteTaskSource: RemoteTaskSource, + taskFileStorage: TaskFileStorage + ): TaskRepository { + return TaskRepository(sharedPreferences, remoteTaskSource, taskFileStorage) } @Singleton @@ -39,5 +46,26 @@ abstract class TaskModule { fun provideRemoteTaskSource(context: Context, sharedPreferences: SharedPreferences): RemoteTaskSource { return RemoteTaskSourceImpl(context.filesDir, sharedPreferences) } + + @Singleton + @Provides + fun provideTaskFileStorage( + @Named("InternalFiles") internalFiles: File, + @Named("ExternalFiles") externalFiles: File? + ): TaskFileStorage { + return TaskFileStorage(internalFiles, externalFiles) + } + + @Singleton + @Provides + @Named("InternalFiles") + fun provideInternalFileDir(context: Context): File = + context.filesDir + + @Singleton + @Provides + @Named("ExternalFiles") + fun provideExternalFilesDir(context: Context): File? = + context.getExternalFilesDir(null) } } \ No newline at end of file From 59a71dd0e8aa2adf9b17f72ec23fa561243a3ddf Mon Sep 17 00:00:00 2001 From: Brendan Gregos Date: Fri, 24 Mar 2023 21:47:44 -0400 Subject: [PATCH 2/2] fix formatting --- .../foreground/data/tasks/TaskRepository.kt | 87 +++++++++++-------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt b/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt index 1ad9af9..a860f49 100644 --- a/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt +++ b/app/src/main/java/me/bgregos/foreground/data/tasks/TaskRepository.kt @@ -45,7 +45,7 @@ class TaskRepository @Inject constructor( return remoteTaskSource.taskwarriorInitSync() } - suspend fun resetSync(){ + suspend fun resetSync() { localChanges.value = listOf() remoteTaskSource.resetSync() save() @@ -56,7 +56,7 @@ class TaskRepository @Inject constructor( } fun addToLocalChanges(updated: Task) { - if(localChanges.value.firstOrNull{ it.uuid == updated.uuid } == null){ + if (localChanges.value.firstOrNull { it.uuid == updated.uuid } == null) { localChanges.value = localChanges.value.plus(updated) } else { localChanges.value = localChanges.value.replace(updated) { it.uuid == updated.uuid } @@ -100,8 +100,9 @@ class TaskRepository @Inject constructor( remoteTaskSource.load() val taskType = object : TypeToken>() {}.type tasks.value = Gson().fromJson(prefs.getString("LocalTasks", ""), taskType) - ?: tasks.value - localChanges.value = Gson().fromJson(prefs.getString("LocalTasks.localChanges", ""), taskType) + ?: tasks.value + localChanges.value = + Gson().fromJson(prefs.getString("LocalTasks.localChanges", ""), taskType) ?: localChanges.value val lastSeenVersion = prefs.getInt("lastSeenVersion", 6) runMigrationsIfRequired(lastSeenVersion) @@ -110,12 +111,11 @@ class TaskRepository @Inject constructor( } @SuppressLint("SimpleDateFormat") - @Synchronized - suspend fun runMigrationsIfRequired(lastSeenVersion: Int){ + suspend fun runMigrationsIfRequired(lastSeenVersion: Int) { //migration - breaking changes are versioned here var itemsModified = false var taskList = tasks - if (lastSeenVersion<2){ + if (lastSeenVersion < 2) { val editor = prefs.edit() itemsModified = true val dfLocal = SimpleDateFormat() @@ -127,57 +127,60 @@ class TaskRepository @Inject constructor( val entryDate = dfUtc.parse(dfLocal.format(task.createdDate)) var modifiedDate: Date? = null var dueDate: Date? = null - if (task.modifiedDate != null){ - modifiedDate=dfUtc.parse(dfLocal.format(task.modifiedDate)) + if (task.modifiedDate != null) { + modifiedDate = dfUtc.parse(dfLocal.format(task.modifiedDate)) } - if (task.dueDate != null){ - dueDate=dfUtc.parse(dfLocal.format(task.dueDate)) + if (task.dueDate != null) { + dueDate = dfUtc.parse(dfLocal.format(task.dueDate)) } val newTask = task.copy( - modifiedDate = modifiedDate, - dueDate = dueDate, - createdDate = entryDate!! + modifiedDate = modifiedDate, + dueDate = dueDate, + createdDate = entryDate!! ) - taskList.value = taskList.value.replace(newTask) {it === task} + taskList.value = taskList.value.replace(newTask) { it === task } } editor.putInt("lastSeenVersion", 2) editor.apply() } - if (lastSeenVersion<3){ + if (lastSeenVersion < 3) { val editor = prefs.edit() itemsModified = true for (task in taskList.value) { //convert all Dates from local time to GMT var newTask: Task = task if (task.others["wait"] != null) { - newTask = newTask.copy(waitDate = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'").parse(task.others["wait"]), others = newTask.others.minus("wait")) + newTask = newTask.copy( + waitDate = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'").parse(task.others["wait"]), + others = newTask.others.minus("wait") + ) } val waitdate = task.waitDate - if(waitdate != null && waitdate.after(Date())) { + if (waitdate != null && waitdate.after(Date())) { newTask = newTask.copy(status = "waiting") } - if (newTask !== task){ - taskList.value = taskList.value.replace(newTask) {it === task} + if (newTask !== task) { + taskList.value = taskList.value.replace(newTask) { it === task } } } editor.putInt("lastSeenVersion", 3) editor.apply() } - if(lastSeenVersion<4){ + if (lastSeenVersion < 4) { //normalize tags val editor = prefs.edit() itemsModified = true - taskList.value.forEach{ + taskList.value.forEach { var tags = it.tags.filter { tag -> tag.isBlank() } - tags = tags.map{ tag -> tag.trim() } + tags = tags.map { tag -> tag.trim() } val newTask = it.copy(tags = tags) - taskList.value = taskList.value.replace(newTask) { foundTask -> foundTask === it} + taskList.value = taskList.value.replace(newTask) { foundTask -> foundTask === it } } editor.putInt("lastSeenVersion", 4) editor.apply() } - if(lastSeenVersion<5){ + if (lastSeenVersion < 5) { //time normalization val editor = prefs.edit() itemsModified = true @@ -186,28 +189,30 @@ class TaskRepository @Inject constructor( val waitDate = it.waitDate?.toLocal() val dueDate = it.dueDate?.toLocal() val modifiedDate = now - val newTask = it.copy(waitDate = waitDate, dueDate = dueDate, modifiedDate = modifiedDate) - taskList.value = taskList.value.replace(newTask) {foundTask -> foundTask === it} + val newTask = + it.copy(waitDate = waitDate, dueDate = dueDate, modifiedDate = modifiedDate) + taskList.value = taskList.value.replace(newTask) { foundTask -> foundTask === it } } editor.putInt("lastSeenVersion", 5) editor.apply() } - if(lastSeenVersion<6){ + if (lastSeenVersion < 6) { val timeFormatter = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'") timeFormatter.timeZone = TimeZone.getTimeZone("UTC") //annotations broken out into different field val editor = prefs.edit() itemsModified = true taskList.value.forEach { - if(it.annotations == null){ + if (it.annotations == null) { val newTask = it.copy(annotations = listOf()) - taskList.value = taskList.value.replace(newTask) {foundTask -> foundTask === it} + taskList.value = + taskList.value.replace(newTask) { foundTask -> foundTask === it } } } taskList.value.forEach { task -> val annotations = arrayListOf() val othersEntry = task.others.get("annotations") - if(!othersEntry.isNullOrBlank()){ + if (!othersEntry.isNullOrBlank()) { val jsonannotations = JSONArray(othersEntry) for (j in 0 until jsonannotations.length()) { @@ -215,10 +220,18 @@ class TaskRepository @Inject constructor( val entry = obj.getString("entry") val parsedEntry = timeFormatter.parse(entry) val description = obj.getString("description") - annotations.add(me.bgregos.foreground.model.Annotation(description, parsedEntry)) + annotations.add( + me.bgregos.foreground.model.Annotation( + description, + parsedEntry + ) + ) } - val newTask = task.copy(annotations = listOf(), others = task.others.filterKeys { it != "annotations" }) - taskList.value = taskList.value.replace(newTask) {foundTask -> foundTask === task} + val newTask = task.copy( + annotations = listOf(), + others = task.others.filterKeys { it != "annotations" }) + taskList.value = + taskList.value.replace(newTask) { foundTask -> foundTask === task } } } editor.putInt("lastSeenVersion", 6) @@ -230,10 +243,10 @@ class TaskRepository @Inject constructor( } } - fun getTaskByUUID(uuid: UUID): Task?{ + fun getTaskByUUID(uuid: UUID): Task? { val tasklist = tasks - for(task in tasklist.value){ - if(task.uuid == uuid){ + for (task in tasklist.value) { + if (task.uuid == uuid) { return task } }