From 811f57bd7ef150d3b825e6133dc3aa93a1d7e495 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 16 May 2019 22:07:49 -0500 Subject: [PATCH 01/24] refactor: Removes .idea files as it's workspace specific and not recommended to version control --- .idea/assetWizardSettings.xml | 37 -------------------------- .idea/caches/build_file_checksums.ser | Bin 536 -> 0 bytes .idea/encodings.xml | 4 --- .idea/gradle.xml | 18 ------------- .idea/misc.xml | 9 ------- .idea/modules.xml | 10 ------- .idea/runConfigurations.xml | 12 --------- .idea/vcs.xml | 6 ----- 8 files changed, 96 deletions(-) delete mode 100644 .idea/assetWizardSettings.xml delete mode 100644 .idea/caches/build_file_checksums.ser delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/gradle.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/runConfigurations.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml deleted file mode 100644 index bce0e40..0000000 --- a/.idea/assetWizardSettings.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser deleted file mode 100644 index 02b69e38dc985475e7fcbcc6cc8193b8682a98e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 536 zcmZ4UmVvdnh`~NNKUXg?FQq6yGexf?KR>5fFEb@IQ7^qHF(oHeub?PDD>b=9F91S2 zm1gFoxMk*~I%lLNXBU^|7Q2L-Ts|(GuF1r}Q#7BMhIJFWRF{)3GpKa@;=as z#i=DFnR)5OFpY%_bqs7EwexN!?6bMgo~N6jCl&5=cwq?x4~h+Ng{MyW>qIR%zwPNY zW>%As9tNOua`KZCb3j2`kXlrdnOa;5SG+7$qiXTABW33~Lho;TknLQ;Ac%+v4AmR< zPS|)!@4cE~;dj&8dXHBn4C>BSF`>n&Ma40mIhBbqP*=y`G2@DC&&_^@O)M`PIA^^1 I;Z#=v0RBt89RL6T diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 15a15b2..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 7ac24c7..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 37a7509..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 2450ea5..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From ae6dd61408c4f7d2747a1cedc012476aa253ed25 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 16 May 2019 22:11:45 -0500 Subject: [PATCH 02/24] fix: Addresses gradle warning about order of enabling plugins --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 18ba831..cb553ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' apply plugin: 'io.fabric' From 1e1dbb74c5b963d98b2afc6cbb7052f8b6a51bb9 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 16 May 2019 22:14:27 -0500 Subject: [PATCH 03/24] chore: Upgrades version number of dependencies & plugins --- build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index ae9c770..f78e07a 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion" classpath 'com.android.tools.build:gradle:3.4.0' classpath 'com.google.gms:google-services:4.2.0' - classpath 'io.fabric.tools:gradle:1.27.1' + classpath 'io.fabric.tools:gradle:1.29.0' } } @@ -36,14 +36,14 @@ ext { versionName = "1.8" // App dependencies - appcompatVersion = "1.0.2" - materialVersion = "1.1.0-alpha04" + appcompatVersion = "1.1.0-alpha05" + materialVersion = "1.1.0-alpha06" androidxVersion = "1.0.0" circularAnimVersion = "0.3.4" dresscodeVersion = "1.0.0" constraintLayoutVersion = "1.1.3" - firebaseVersion = "16.0.7" - crashlyticsVersion = "2.9.9" + firebaseVersion = "16.0.9" + crashlyticsVersion = "2.10.0" kotterKnifeVersion = "0.1.0-SNAPSHOT" roomVersion = "2.1.0-alpha02" rxJavaVersion = '2.2.3' From 1c58001164715dce7796037362e40ddcc2cd1433 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 16 May 2019 22:18:13 -0500 Subject: [PATCH 04/24] feat: Adds Column to store Task Status and adds migration strategy to alter the table --- .../jizzu/simpletodo/data/database/TasksDatabase.kt | 11 +++++++++-- .../java/apps/jizzu/simpletodo/data/models/Task.kt | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt index f116bb6..9c684d5 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt @@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase import apps.jizzu.simpletodo.data.models.Task import apps.jizzu.simpletodo.utils.PreferenceHelper -@Database(entities = [Task::class], version = 3) +@Database(entities = [Task::class], version = 4) abstract class TasksDatabase : RoomDatabase() { abstract fun taskDAO(): TaskDao @@ -23,6 +23,7 @@ abstract class TasksDatabase : RoomDatabase() { private const val TEMP_TABLE = "temp_table" private const val TASK_ID_COLUMN = "_id" + private const val TASK_STATUS_COLUMN = "task_status" private const val TASK_TITLE_COLUMN = "task_title" private const val TASK_NOTE_COLUMN = "task_note" private const val TASK_DATE_COLUMN = "task_date" @@ -51,12 +52,18 @@ abstract class TasksDatabase : RoomDatabase() { } } + private val MIGRATION_3_4 = object : Migration(3, 4) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE $TASKS_TABLE ADD COLUMN $TASK_STATUS_COLUMN INTEGER NOT NULL DEFAULT 0 NOT NULL") + } + } + fun getInstance(context: Context): TasksDatabase { synchronized(TasksDatabase::class.java) { if (mInstance == null) { mInstance = Room.databaseBuilder(context, TasksDatabase::class.java, DATABASE_NAME) - .addMigrations(MIGRATION_1_2, MIGRATION_2_3) + .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4) .build() } } diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt b/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt index 34556c3..7a5c8fc 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt @@ -34,17 +34,22 @@ class Task : Serializable { @NonNull var timeStamp: Long = 0 + @ColumnInfo(name = "task_status") + @NonNull + var taskStatus: Int = 0 + @Ignore constructor() { this.timeStamp = Date().time } - constructor(id: Long, title: String, note: String, date: Long, position: Int, timeStamp: Long) { + constructor(id: Long, title: String, note: String, date: Long, position: Int, timeStamp: Long, taskStatus: Int = 0) { this.id = id this.title = title this.note = note this.date = date this.position = position this.timeStamp = timeStamp + this.taskStatus = taskStatus } } From 8eea806af782aae825d87e05ae2df961933594de Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 16 May 2019 22:19:00 -0500 Subject: [PATCH 05/24] feat: Updates Task UI to enable 'Done' using checkbox - Adds new Task Layout using constraint layout to show Tasks with checkbox - Adds event listener checkbox to 'update' task status --- .../ui/recycler/RecyclerViewAdapter.kt | 24 +++++- .../simpletodo/ui/view/AddTaskActivity.kt | 1 + .../jizzu/simpletodo/ui/view/MainActivity.kt | 9 +++ .../jizzu/simpletodo/vm/TaskListViewModel.kt | 2 + app/src/main/res/layout/task_item_view.xml | 73 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 6 files changed, 107 insertions(+), 3 deletions(-) create mode 100755 app/src/main/res/layout/task_item_view.xml diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt index 951738b..a6fcea7 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt @@ -6,8 +6,10 @@ import android.text.format.DateUtils import android.util.DisplayMetrics import android.util.Log import android.view.* +import android.widget.CompoundButton import android.widget.ImageView import android.widget.TextView +import androidx.appcompat.widget.AppCompatCheckBox import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView @@ -50,13 +52,14 @@ class RecyclerViewAdapter : RecyclerView.Adapter(R.id.cbTaskStatus) val title = v.findViewById(R.id.tvTaskTitle) val note = v.findViewById(R.id.ivTaskNote) val date = v.findViewById(R.id.tvTaskDate) mContext = parent.context - return TaskViewHolder(v, title, note, date) + return TaskViewHolder(v, status, title, note, date) } override fun onBindViewHolder(holder: TaskViewHolder, position: Int) { @@ -68,6 +71,12 @@ class RecyclerViewAdapter : RecyclerView.Adapter + if (isChecked) { + taskCompletionListener?.onTaskComplete(itemView, holder.adapterPosition) + } + } + if (task.note.isNotEmpty()) { holder.note.visible() } else holder.note.gone() @@ -133,13 +142,22 @@ class RecyclerViewAdapter : RecyclerView.Adapter + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d9e0f1f..197e446 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -162,4 +162,5 @@ ////////////////////////////// Add new task Search + Completed the task \ No newline at end of file From a85d1e10a2961d0280301f42b79fc2c50499268c Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 16 May 2019 22:22:51 -0500 Subject: [PATCH 06/24] chore: Updates git ignore to ignore workspace specific '.idea' files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7665a4a..05477b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.iml +.idea/ .gradle /local.properties /.idea/workspace.xml @@ -7,4 +8,4 @@ /build /captures .externalNativeBuild -/app/google-services.json \ No newline at end of file +/app/google-services.json From 38bec12c0af2153f6753831142a28293921f1eec Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Fri, 17 May 2019 16:48:41 -0500 Subject: [PATCH 07/24] fix: Changes the task status from integer to boolean and follow up the changes in other places --- .../main/java/apps/jizzu/simpletodo/data/models/Task.kt | 4 ++-- .../jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt | 9 ++++----- .../apps/jizzu/simpletodo/ui/view/AddTaskActivity.kt | 2 +- .../java/apps/jizzu/simpletodo/ui/view/MainActivity.kt | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt b/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt index 7a5c8fc..cf16fdd 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/models/Task.kt @@ -36,14 +36,14 @@ class Task : Serializable { @ColumnInfo(name = "task_status") @NonNull - var taskStatus: Int = 0 + var taskStatus: Boolean = false @Ignore constructor() { this.timeStamp = Date().time } - constructor(id: Long, title: String, note: String, date: Long, position: Int, timeStamp: Long, taskStatus: Int = 0) { + constructor(id: Long, title: String, note: String, date: Long, position: Int, timeStamp: Long, taskStatus: Boolean = false) { this.id = id this.title = title this.note = note diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt index a6fcea7..044b215 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/recycler/RecyclerViewAdapter.kt @@ -71,11 +71,10 @@ class RecyclerViewAdapter : RecyclerView.Adapter - if (isChecked) { - taskCompletionListener?.onTaskComplete(itemView, holder.adapterPosition) - } + holder.status.setOnClickListener { + taskCompletionListener?.onTaskStatusChanged(itemView, holder.adapterPosition) } + holder.status.isChecked = task.taskStatus if (task.note.isNotEmpty()) { holder.note.visible() @@ -151,7 +150,7 @@ class RecyclerViewAdapter : RecyclerView.Adapter Date: Wed, 29 May 2019 14:21:24 -0500 Subject: [PATCH 08/24] feat: Delete tasks on completing the task - Updates the migration strategy - Updates the Task Constructor and it's references to reflect the task status boolean flag - Adds temporary approach to delete task on completion --- .../simpletodo/data/database/TasksDatabase.kt | 19 ++++++++++++++++--- .../simpletodo/ui/view/EditTaskActivity.kt | 6 ++++-- .../jizzu/simpletodo/ui/view/MainActivity.kt | 4 ++++ .../simpletodo/ui/view/base/BaseActivity.kt | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt index 9c684d5..c9db64e 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt @@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase import apps.jizzu.simpletodo.data.models.Task import apps.jizzu.simpletodo.utils.PreferenceHelper -@Database(entities = [Task::class], version = 4) +@Database(entities = [Task::class], version = 5) abstract class TasksDatabase : RoomDatabase() { abstract fun taskDAO(): TaskDao @@ -54,7 +54,20 @@ abstract class TasksDatabase : RoomDatabase() { private val MIGRATION_3_4 = object : Migration(3, 4) { override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("ALTER TABLE $TASKS_TABLE ADD COLUMN $TASK_STATUS_COLUMN INTEGER NOT NULL DEFAULT 0 NOT NULL") + database.execSQL("ALTER TABLE $TASKS_TABLE ADD COLUMN $TASK_STATUS_COLUMN INTEGER DEFAULT 0 NOT NULL") + } + } + + private val MIGRATION_4_5 = object : Migration(4, 5) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("CREATE TABLE $TEMP_TABLE ($TASK_ID_COLUMN INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, $TASK_TITLE_COLUMN TEXT NOT NULL, " + + "$TASK_DATE_COLUMN INTEGER NOT NULL, $TASK_POSITION_COLUMN INTEGER NOT NULL, $TASK_TIME_STAMP_COLUMN INTEGER NOT NULL, " + + "$TASK_NOTE_COLUMN TEXT DEFAULT '' NOT NULL, " + + "$TASK_STATUS_COLUMN INTEGER DEFAULT 0 NOT NULL);") + database.execSQL("INSERT INTO $TEMP_TABLE ($TASK_ID_COLUMN, $TASK_TITLE_COLUMN, $TASK_DATE_COLUMN, $TASK_POSITION_COLUMN, $TASK_TIME_STAMP_COLUMN, $TASK_NOTE_COLUMN) " + + "SELECT $TASK_ID_COLUMN, $TASK_TITLE_COLUMN, $TASK_DATE_COLUMN, $TASK_POSITION_COLUMN, $TASK_TIME_STAMP_COLUMN, $TASK_NOTE_COLUMN FROM $TASKS_TABLE") + database.execSQL("DROP TABLE $TASKS_TABLE") + database.execSQL("ALTER TABLE $TEMP_TABLE RENAME TO $TASKS_TABLE;") } } @@ -63,7 +76,7 @@ abstract class TasksDatabase : RoomDatabase() { if (mInstance == null) { mInstance = Room.databaseBuilder(context, TasksDatabase::class.java, DATABASE_NAME) - .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4) + .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5) .build() } } diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/EditTaskActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/EditTaskActivity.kt index ce9c13a..ea161e1 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/EditTaskActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/EditTaskActivity.kt @@ -18,6 +18,7 @@ import kotlinx.android.synthetic.main.toolbar.* import java.util.* class EditTaskActivity : BaseTaskActivity() { + private var mTaskStatus: Boolean = false private var mId: Long = 0 private var mDate: Long = 0 private var mPosition: Int = 0 @@ -41,6 +42,7 @@ class EditTaskActivity : BaseTaskActivity() { mNote = intent.getStringExtra("note") mDate = intent.getLongExtra("date", 0) mPosition = intent.getIntExtra("position", 0) + mTaskStatus = intent.getBooleanExtra("task_status", false) mTimeStamp = intent.getLongExtra("time_stamp", 0) mTitleEditText.setText(mTitle) @@ -65,7 +67,7 @@ class EditTaskActivity : BaseTaskActivity() { mTitleEditText.length() == 0 -> tilTaskTitle.error = getString(R.string.error_text_input) mTitleEditText.text.toString().trim { it <= ' ' }.isEmpty() -> tilTaskTitle.error = getString(R.string.error_spaces) else -> { - val task = Task(mId, mTitleEditText.text.toString(), tvTaskNote.text.toString(), mDate, mPosition, mTimeStamp) + val task = Task(mId, mTitleEditText.text.toString(), tvTaskNote.text.toString(), mDate, mPosition, mTimeStamp, mTaskStatus) if (tvTaskReminder.length() != 0) { task.date = mCalendar.timeInMillis @@ -109,7 +111,7 @@ class EditTaskActivity : BaseTaskActivity() { R.id.action_delete -> { hideKeyboard(mTitleEditText) - showDeleteTaskDialog(Task(mId, mTitle, mNote, mDate, mPosition, mTimeStamp)) + showDeleteTaskDialog(Task(mId, mTitle, mNote, mDate, mPosition, mTimeStamp, mTaskStatus)) } } return super.onOptionsItemSelected(item) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt index a171e3d..66bc7cb 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt @@ -481,6 +481,10 @@ class MainActivity : BaseActivity() { val task = mAdapter.getTaskAtPosition(position) task.taskStatus = task.taskStatus.not() mViewModel.updateTask(task) + // todo: delete the task for now, find alternative approach + if (task.taskStatus) { + deleteTask(position) + } } }) } diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/base/BaseActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/base/BaseActivity.kt index 2c0edb5..b3c8c99 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/base/BaseActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/base/BaseActivity.kt @@ -90,6 +90,7 @@ abstract class BaseActivity : AppCompatActivity() { putExtra("note", task.note) putExtra("position", task.position) putExtra("time_stamp", task.timeStamp) + putExtra("task_status", task.taskStatus) if (task.date != 0L) { putExtra("date", task.date) } From c71352c75375389af2d6e48327f6c06627912d90 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Wed, 29 May 2019 15:16:08 -0500 Subject: [PATCH 09/24] feat: Adds Testcases for TaskDao - Adds Android JUnit Test Libraries - Adds Basic Unit Test cases for save & update - Removes unnecessary migration strategy --- app/build.gradle | 10 +++ .../java/apps/jizzu/simpletodo/TaskDAOTest.kt | 79 +++++++++++++++++++ .../simpletodo/data/database/TasksDatabase.kt | 8 +- 3 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt diff --git a/app/build.gradle b/app/build.gradle index cffde75..6f67b74 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,4 +70,14 @@ dependencies { // Tests testImplementation "junit:junit:$rootProject.junitVersion" + + // Core library + androidTestImplementation 'androidx.test:core:1.1.0' + + // AndroidJUnitRunner and JUnit Rules + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test:rules:1.1.1' + + // Assertions + androidTestImplementation 'androidx.test.ext:junit:1.1.0' } \ No newline at end of file diff --git a/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt b/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt new file mode 100644 index 0000000..454bbd1 --- /dev/null +++ b/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt @@ -0,0 +1,79 @@ +package apps.jizzu.simpletodo + +import android.content.Context +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import apps.jizzu.simpletodo.data.database.TaskDao +import apps.jizzu.simpletodo.data.database.TasksDatabase +import apps.jizzu.simpletodo.data.models.Task +import org.junit.After +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import java.io.IOException +import java.util.* + +@RunWith(AndroidJUnit4::class) +class TaskDAOTest { + + private lateinit var taskDao: TaskDao + private lateinit var tasksDatabase: TasksDatabase + + @Before + fun createDb() { + val context = ApplicationProvider.getApplicationContext() + tasksDatabase = Room.inMemoryDatabaseBuilder( + context, TasksDatabase::class.java + ).build() + taskDao = tasksDatabase.taskDAO() + } + + @Test + fun testSaveTask() { + var task = Task(1, "", "", Date().time, 1, Date().time) + taskDao.saveTask(task) + + var tasks = taskDao.getAllTasks() + assertEquals(1, tasks.size) + + task = Task(2, "", "", Date().time, 2, Date().time, true) + taskDao.saveTask(task) + + tasks = taskDao.getAllTasks() + assertEquals(2, tasks.size) + } + + @Test + fun testUpdateTask() { + var tasks = taskDao.getAllTasks() + assertEquals(0, tasks.size) + + val task = Task(1, "", "", Date().time, 1, Date().time) + taskDao.saveTask(task) + + tasks = taskDao.getAllTasks() + assertFalse(tasks[0].taskStatus) + + tasks[0].taskStatus = tasks[0].taskStatus.not() + taskDao.updateTask(tasks[0]) + + tasks = taskDao.getAllTasks() + assertEquals(1, tasks.size) + assertTrue(tasks[0].taskStatus) + + tasks[0].taskStatus = tasks[0].taskStatus.not() + taskDao.updateTask(tasks[0]) + + tasks = taskDao.getAllTasks() + assertEquals(1, tasks.size) + assertFalse(tasks[0].taskStatus) + } + + @After + @Throws(IOException::class) + fun closeDb() { + tasksDatabase.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt index c9db64e..9769d13 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt @@ -53,12 +53,6 @@ abstract class TasksDatabase : RoomDatabase() { } private val MIGRATION_3_4 = object : Migration(3, 4) { - override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("ALTER TABLE $TASKS_TABLE ADD COLUMN $TASK_STATUS_COLUMN INTEGER DEFAULT 0 NOT NULL") - } - } - - private val MIGRATION_4_5 = object : Migration(4, 5) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("CREATE TABLE $TEMP_TABLE ($TASK_ID_COLUMN INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, $TASK_TITLE_COLUMN TEXT NOT NULL, " + "$TASK_DATE_COLUMN INTEGER NOT NULL, $TASK_POSITION_COLUMN INTEGER NOT NULL, $TASK_TIME_STAMP_COLUMN INTEGER NOT NULL, " + @@ -76,7 +70,7 @@ abstract class TasksDatabase : RoomDatabase() { if (mInstance == null) { mInstance = Room.databaseBuilder(context, TasksDatabase::class.java, DATABASE_NAME) - .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5) + .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4) .build() } } From 4b294cc4799fb162cfa1eb5a46451ccb19715052 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Wed, 8 Jan 2020 15:56:13 -0600 Subject: [PATCH 10/24] chore: updates gradle plugin versions & libraries to the latest versions --- app/build.gradle | 2 +- build.gradle | 17 +++++++++-------- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6f67b74..da35225 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,7 +39,7 @@ dependencies { // UI implementation "androidx.appcompat:appcompat:$rootProject.appcompatVersion" implementation "com.google.android.material:material:$rootProject.materialVersion" - implementation "androidx.cardview:cardview:$rootProject.androidxVersion" + implementation "androidx.cardview:cardview:$rootProject.cardViewVersion" implementation "androidx.preference:preference:$rootProject.androidxVersion" implementation "com.github.XunMengWinter:CircularAnim:$rootProject.circularAnimVersion" implementation "com.github.Daio-io:dresscode:$rootProject.dresscodeVersion" diff --git a/build.gradle b/build.gradle index 9616142..c647339 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlinVersion = '1.3.31' + ext.kotlinVersion = '1.3.61' repositories { jcenter() @@ -10,9 +10,9 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion" - classpath 'com.android.tools.build:gradle:3.4.0' - classpath 'com.google.gms:google-services:4.2.0' - classpath 'io.fabric.tools:gradle:1.29.0' + classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.google.gms:google-services:4.3.3' + classpath 'io.fabric.tools:gradle:1.31.0' } } @@ -37,14 +37,15 @@ ext { // App dependencies appcompatVersion = "1.1.0-alpha05" - materialVersion = "1.1.0-alpha06" - androidxVersion = "1.0.0" + materialVersion = "1.2.0-alpha03" + androidxVersion = "1.1.0" + cardViewVersion = "1.0.0" circularAnimVersion = "0.3.4" dresscodeVersion = "1.0.0" materialIntroVersion = "1.6" constraintLayoutVersion = "1.1.3" - firebaseVersion = "16.0.9" - crashlyticsVersion = "2.10.0" + firebaseVersion = "17.2.1" + crashlyticsVersion = "2.10.1" kotterKnifeVersion = "0.1.0-SNAPSHOT" roomVersion = "2.1.0-alpha02" rxJavaVersion = '2.2.3' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 742fda0..90e5d7d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Apr 19 14:11:48 NOVT 2019 +#Wed Jan 08 15:45:34 CST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip From 5a8779f9176a2f1791a60e4953bc36ec7baa5ecd Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Wed, 8 Jan 2020 16:07:12 -0600 Subject: [PATCH 11/24] fix: upgrading gradle plugin breaks the build, so downgrading to 3.4.0 --- app/build.gradle | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index da35225..a64c78e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,7 +66,7 @@ dependencies { // Lifecycle components implementation "android.arch.lifecycle:extensions:$rootProject.lifecycleVersion" - annotationProcessor "android.arch.lifecycle:compiler:$rootProject.lifecycleVersion" + kapt "android.arch.lifecycle:compiler:$rootProject.lifecycleVersion" // Tests testImplementation "junit:junit:$rootProject.junitVersion" diff --git a/build.gradle b/build.gradle index c647339..f6f2cac 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion" - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:3.4.0' classpath 'com.google.gms:google-services:4.3.3' classpath 'io.fabric.tools:gradle:1.31.0' } From f0dbf8feb6ddca4a84e9a5a48f52a5a72b11aa19 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Wed, 8 Jan 2020 16:55:20 -0600 Subject: [PATCH 12/24] feat: adds translated string values for completing a task --- app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + 3 files changed, 3 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c80a55e..30ee092 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -158,4 +158,5 @@ ////////////////////////////// Ajouter une nouvelle tâche Rechercher + Terminé la tâche \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index aa0372e..95e389f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -158,4 +158,5 @@ ////////////////////////////// Добавить задачу Поиск + Выполнено задание \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 69276ea..ac0efe0 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -158,4 +158,5 @@ ////////////////////////////// Yeni görev ekle Ara + Görev tamamlandı \ No newline at end of file From 037c58ec11a167ef7f9a64616bcac90dff415e6e Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Wed, 8 Jan 2020 16:55:57 -0600 Subject: [PATCH 13/24] feat: adds method to get all open tasks - Adds a method to get all the open tasks - Adds a method to get all the open tasks live data - Updates the database query to fetch tasks that has status as '0' - Updates the test cases to verify the database operations BREAKING CHANGE: Introduces a method to get the all the open tasks. i.e., tasks that aren't completed. The app home screen shows the tasks that are open. --- .../java/apps/jizzu/simpletodo/TaskDAOTest.kt | 63 ++++++++++++++++--- .../jizzu/simpletodo/data/database/TaskDao.kt | 6 ++ .../data/database/TaskListRepository.kt | 10 ++- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt b/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt index 454bbd1..b8f094f 100644 --- a/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt +++ b/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt @@ -32,17 +32,53 @@ class TaskDAOTest { @Test fun testSaveTask() { + val task = Task(1, "", "", Date().time, 1, Date().time) + taskDao.saveTask(task) + + val tasks = taskDao.getAllTasks() + assertEquals(1, tasks.size) + } + + @Test + fun testGetAllTasks() { var task = Task(1, "", "", Date().time, 1, Date().time) taskDao.saveTask(task) var tasks = taskDao.getAllTasks() assertEquals(1, tasks.size) - task = Task(2, "", "", Date().time, 2, Date().time, true) + task = Task(2, "", "", Date().time, 2, Date().time, false) taskDao.saveTask(task) tasks = taskDao.getAllTasks() assertEquals(2, tasks.size) + + task = Task(3, "", "", Date().time, 2, Date().time, true) + taskDao.saveTask(task) + + tasks = taskDao.getAllTasks() + assertEquals(3, tasks.size) + } + + @Test + fun testGetAllOpenTasks() { + var task = Task(1, "", "", Date().time, 1, Date().time) + taskDao.saveTask(task) + + var tasks = taskDao.getAllOpenTasks() + assertEquals(1, tasks.size) + + task = Task(2, "", "", Date().time, 2, Date().time, false) + taskDao.saveTask(task) + + tasks = taskDao.getAllOpenTasks() + assertEquals(2, tasks.size) + + task = Task(3, "", "", Date().time, 2, Date().time, true) + taskDao.saveTask(task) + + tasks = taskDao.getAllOpenTasks() + assertEquals(2, tasks.size) } @Test @@ -53,22 +89,33 @@ class TaskDAOTest { val task = Task(1, "", "", Date().time, 1, Date().time) taskDao.saveTask(task) - tasks = taskDao.getAllTasks() - assertFalse(tasks[0].taskStatus) + tasks = taskDao.getAllOpenTasks() + assertEquals("", tasks[0].title) - tasks[0].taskStatus = tasks[0].taskStatus.not() + tasks[0].title = "Test" taskDao.updateTask(tasks[0]) tasks = taskDao.getAllTasks() assertEquals(1, tasks.size) - assertTrue(tasks[0].taskStatus) + assertEquals("Test", tasks[0].title) + } + + @Test + fun testUpdateStatusTask() { + var tasks = taskDao.getAllTasks() + assertEquals(0, tasks.size) + + val task = Task(1, "Test Me", "Task to Complete", Date().time, 1, Date().time) + taskDao.saveTask(task) + + tasks = taskDao.getAllOpenTasks() + assertFalse(tasks[0].taskStatus) tasks[0].taskStatus = tasks[0].taskStatus.not() taskDao.updateTask(tasks[0]) - tasks = taskDao.getAllTasks() - assertEquals(1, tasks.size) - assertFalse(tasks[0].taskStatus) + tasks = taskDao.getAllOpenTasks() + assertEquals(0, tasks.size) } @After diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt index 30a760b..43dd61b 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt @@ -21,12 +21,18 @@ interface TaskDao { @Query("DELETE FROM tasks_table") fun deleteAllTasks() + @Query("SELECT * FROM tasks_table where task_status=0 ORDER BY task_position") + fun getAllOpenTasksLiveData(): LiveData> + @Query("SELECT * FROM tasks_table ORDER BY task_position") fun getAllTasksLiveData(): LiveData> @Query("SELECT * FROM tasks_table ORDER BY task_position") fun getAllTasks(): List + @Query("SELECT * FROM tasks_table where task_status=0 ORDER BY task_position") + fun getAllOpenTasks(): List + @Query("SELECT * FROM tasks_table WHERE task_title LIKE '%' || :searchText || '%'") fun getTasksForSearch(searchText: String): LiveData> } \ No newline at end of file diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt index e3248f7..ed9d9f7 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt @@ -9,7 +9,7 @@ import io.reactivex.schedulers.Schedulers class TaskListRepository(app: Application) { private val mTaskDao = TasksDatabase.getInstance(app).taskDAO() - private val mAllTasksLiveData = mTaskDao.getAllTasksLiveData() + private val mAllTasksLiveData = mTaskDao.getAllOpenTasksLiveData() fun getAllTasksLiveData() = mAllTasksLiveData @@ -32,4 +32,12 @@ class TaskListRepository(app: Application) { .subscribeBy(onNext = { task -> taskList.add(task) }) return taskList } + + fun getAllOpenTasks(): ArrayList { + val taskList = arrayListOf() + Observable.fromCallable { mTaskDao.getAllOpenTasks() }.subscribeOn(Schedulers.io()) + .flatMap { tasks -> Observable.fromIterable(tasks) } + .subscribeBy(onNext = { task -> taskList.add(task) }) + return taskList + } } \ No newline at end of file From 20b3e554160658384319729b3edfa6a5f88ed9d2 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Wed, 8 Jan 2020 16:59:22 -0600 Subject: [PATCH 14/24] feat: adds a method to complete the task - Adds a method to complete the task instead of removing it. BREAKING CHANGE: On clicking on the checkbox, the task status is updated to '1', i.e., marked as completed instead of deleting from database. Swiping from either side will continue to delete the task. This change introduced a bug in the 'Search' screen as the 'Search' screen continue to show all the tasks (open & completed). So when a completed task shown in 'Search Results', unchecking it, may not mark it as 'Not completed'. This is still being worked on. --- .../jizzu/simpletodo/ui/view/MainActivity.kt | 52 +++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt index 5a71fca..805b590 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt @@ -171,6 +171,53 @@ class MainActivity : BaseActivity() { helper.attachToRecyclerView(mRecyclerView) } + private fun completeTask(position: Int) { + val completedTask = mAdapter.getTaskAtPosition(position) + val isCompletedTaskHasLastPosition = completedTask.position == mAdapter.itemCount - 1 + val alarmHelper = AlarmHelper.getInstance() + alarmHelper.removeAlarm(completedTask.timeStamp) + mAdapter.removeTask(position) + var isUndoClicked = false + + mSnackbar = Snackbar.make(mRecyclerView, R.string.complete_task_status, Snackbar.LENGTH_LONG) + mSnackbar?.setAction(R.string.snackbar_undo) { + mViewModel.saveTask(completedTask) + if (completedTask.date != 0L && completedTask.date > Calendar.getInstance().timeInMillis) { + alarmHelper.setAlarm(completedTask) + } + isUndoClicked = true + + Handler().postDelayed({ + val firstCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() + if (firstCompletelyVisibleItem != 0 && !RecyclerViewScrollListener.isShadowShown) { + setToolbarShadow(0f, 10f) + RecyclerViewScrollListener.isShadowShown = true + } + }, 100) + } + + mSnackbar?.view?.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(view: View) { + val firstCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() + val lastCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition() + + if (firstCompletelyVisibleItem == 0 && lastCompletelyVisibleItem == mTaskList.size - 1 && RecyclerViewScrollListener.isShadowShown) { + setToolbarShadow(10f, 0f) + RecyclerViewScrollListener.isShadowShown = false + } + } + + override fun onViewDetachedFromWindow(view: View) { + if (!isUndoClicked) { + alarmHelper.removeNotification(completedTask.timeStamp, this@MainActivity) + if (!isCompletedTaskHasLastPosition) recountTaskPositions() + } + } + }) + mSnackbar?.anchorView = mFab + mSnackbar?.show() + } + private fun deleteTask(position: Int) { val deletedTask = mAdapter.getTaskAtPosition(position) val isDeletedTaskHasLastPosition = deletedTask.position == mAdapter.itemCount - 1 @@ -484,9 +531,8 @@ class MainActivity : BaseActivity() { val task = mAdapter.getTaskAtPosition(position) task.taskStatus = task.taskStatus.not() mViewModel.updateTask(task) - // todo: delete the task for now, find alternative approach - if (task.taskStatus) { - deleteTask(position) + if (task.taskStatus) { //todo: does it require to check task status? + completeTask(position) } } }) From 5d15f3661a171e4f37ab7130ac06a910aaf35878 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 11:58:23 -0600 Subject: [PATCH 15/24] feat: adds a screen to see the completed tasks - Adds a new activity to show the completed tasks - Adds new option to allow opening the completed tasks view - Adds string resources for completed tasks labels & related translations - Fixes the warning in android manifest & adds the new activity definition - Fixes the warning in menu, i.e., uses 'IfRoom' instead of 'always' BREAKING CHANGE: This adds a new activity screen that shows the completed tasks that's launched by clicking on a button in the app bar. It only shows the completed tasks. These tasks can be moved to 'Open/Not completed' stage on clicking the checkbox. It will show up in the main tasks screen as not completed. --- app/src/main/AndroidManifest.xml | 8 +- .../jizzu/simpletodo/data/database/TaskDao.kt | 3 + .../data/database/TaskListRepository.kt | 6 +- .../ui/view/CompletedTasksActivity.kt | 143 ++++++++++++++++++ .../jizzu/simpletodo/ui/view/MainActivity.kt | 3 +- .../jizzu/simpletodo/vm/TaskListViewModel.kt | 3 +- .../res/layout/activity_completed_tasks.xml | 47 ++++++ app/src/main/res/menu/menu.xml | 9 +- app/src/main/res/values-fr/strings.xml | 2 + app/src/main/res/values-ru/strings.xml | 2 + app/src/main/res/values-tr/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 12 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt create mode 100644 app/src/main/res/layout/activity_completed_tasks.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3a1fc74..3259d23 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -12,7 +13,8 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" - android:theme="@style/AppTheme.Light"> + android:theme="@style/AppTheme.Light" + tools:ignore="AllowBackup,GoogleAppIndexingWarning"> + + diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt index 43dd61b..ff128d1 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskDao.kt @@ -24,6 +24,9 @@ interface TaskDao { @Query("SELECT * FROM tasks_table where task_status=0 ORDER BY task_position") fun getAllOpenTasksLiveData(): LiveData> + @Query("SELECT * FROM tasks_table where task_status=1 ORDER BY task_position") + fun getAllCompletedTasksLiveData(): LiveData> + @Query("SELECT * FROM tasks_table ORDER BY task_position") fun getAllTasksLiveData(): LiveData> diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt index ed9d9f7..b2fb195 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TaskListRepository.kt @@ -9,9 +9,11 @@ import io.reactivex.schedulers.Schedulers class TaskListRepository(app: Application) { private val mTaskDao = TasksDatabase.getInstance(app).taskDAO() - private val mAllTasksLiveData = mTaskDao.getAllOpenTasksLiveData() + private val mAllOpenTasksLiveData = mTaskDao.getAllOpenTasksLiveData() + private val mAllCompletedTasksLiveData = mTaskDao.getAllCompletedTasksLiveData() - fun getAllTasksLiveData() = mAllTasksLiveData + fun getAllOpenTasksLiveData() = mAllOpenTasksLiveData + fun getAllCompletedTasksLiveData() = mAllCompletedTasksLiveData fun deleteAllTasks() = Completable.fromCallable { mTaskDao.deleteAllTasks() }.subscribeOn(Schedulers.io()).subscribe()!! diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt new file mode 100644 index 0000000..dc00f05 --- /dev/null +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt @@ -0,0 +1,143 @@ +package apps.jizzu.simpletodo.ui.view + +import android.os.Bundle +import android.view.MenuItem +import android.view.View +import androidx.appcompat.content.res.AppCompatResources +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import apps.jizzu.simpletodo.R +import apps.jizzu.simpletodo.data.models.Task +import apps.jizzu.simpletodo.service.alarm.AlarmHelper +import apps.jizzu.simpletodo.ui.recycler.RecyclerViewAdapter +import apps.jizzu.simpletodo.ui.view.base.BaseActivity +import apps.jizzu.simpletodo.utils.PreferenceHelper +import apps.jizzu.simpletodo.utils.gone +import apps.jizzu.simpletodo.utils.toast +import apps.jizzu.simpletodo.utils.visible +import apps.jizzu.simpletodo.vm.TaskListViewModel +import daio.io.dresscode.matchDressCode +import kotlinx.android.synthetic.main.activity_search.* +import kotterknife.bindView + +class CompletedTasksActivity : BaseActivity() { + private val mRecyclerView: RecyclerView by bindView(R.id.rvCompletedTasksList) + private lateinit var mViewModel: TaskListViewModel + private lateinit var mAdapter: RecyclerViewAdapter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + matchDressCode() + setContentView(R.layout.activity_completed_tasks) + initToolbar(getString(R.string.completed_tasks_title)) + + if (intent.getBooleanExtra("isShortcut", false)) { + PreferenceHelper.getInstance().init(applicationContext) + AlarmHelper.getInstance().init(applicationContext) + } + + mViewModel = createViewModel() + mViewModel.completedTasksLiveData.observe(this, Observer> { response -> updateViewState(response) }) + + mRecyclerView.setHasFixedSize(true) + mRecyclerView.layoutManager = LinearLayoutManager(this) + mAdapter = RecyclerViewAdapter() + mRecyclerView.adapter = mAdapter + llEmptyView.visible() + } + + override fun onResume() { + super.onResume() + + mAdapter.setOnItemClickListener(object : RecyclerViewAdapter.ClickListener { + override fun onTaskClick(v: View, position: Int) { + showTaskDetailsActivity(mAdapter.getTaskAtPosition(position)) + } + }) + + mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener { + override fun onTaskStatusChanged(v: View, position: Int) { + toast(getString(R.string.move_task_to_open)) + val task = mAdapter.getTaskAtPosition(position) + task.taskStatus = task.taskStatus.not() + mViewModel.updateTask(task) + completeTask(position) + } + }) + } + + private fun completeTask(position: Int) { + val completedTask = mAdapter.getTaskAtPosition(position) + val isCompletedTaskHasLastPosition = completedTask.position == mAdapter.itemCount - 1 + mAdapter.removeTask(position) + val alarmHelper = AlarmHelper.getInstance() + alarmHelper.removeAlarm(completedTask.timeStamp) +// var isUndoClicked = false + + /* mSnackbar = Snackbar.make(mRecyclerView, R.string.complete_task_status, Snackbar.LENGTH_LONG) + mSnackbar?.setAction(R.string.snackbar_undo) { + mViewModel.saveTask(completedTask) + if (completedTask.date != 0L && completedTask.date > Calendar.getInstance().timeInMillis) { + alarmHelper.setAlarm(completedTask) + } + isUndoClicked = true + + Handler().postDelayed({ + val firstCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() + if (firstCompletelyVisibleItem != 0 && !RecyclerViewScrollListener.isShadowShown) { + setToolbarShadow(0f, 10f) + RecyclerViewScrollListener.isShadowShown = true + } + }, 100) + } + + mSnackbar?.view?.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(view: View) { + val firstCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() + val lastCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition() + + if (firstCompletelyVisibleItem == 0 && lastCompletelyVisibleItem == MainActivity.mTaskList.size - 1 && RecyclerViewScrollListener.isShadowShown) { + setToolbarShadow(10f, 0f) + RecyclerViewScrollListener.isShadowShown = false + } + } + + override fun onViewDetachedFromWindow(view: View) { + if (!isUndoClicked) { + alarmHelper.removeNotification(completedTask.timeStamp, this@MainActivity) + if (!isCompletedTaskHasLastPosition) recountTaskPositions() + } + } + }) + mSnackbar?.anchorView = mFab + mSnackbar?.show()*/ + } + + private fun updateViewState(tasks: List) = if (tasks.isEmpty()) showEmptyView() + else showTaskList(tasks) + + private fun showEmptyView() { + mAdapter.updateData(arrayListOf()) + llEmptyView.visible() + ivEmptyIllustration.setImageDrawable(AppCompatResources.getDrawable(this, + R.drawable.illustration_not_found)) + tvEmptyTitle.text = getString(R.string.search_view_not_found_text) + } + + private fun showTaskList(tasks: List) { + llEmptyView.gone() + mAdapter.updateData(tasks) + } + + private fun createViewModel() = ViewModelProviders.of(this).get(TaskListViewModel(application)::class.java) + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == android.R.id.home) { + onBackPressed() + return true + } + return false + } +} diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt index 805b590..03ba89c 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt @@ -79,7 +79,7 @@ class MainActivity : BaseActivity() { AlarmHelper.getInstance().init(applicationContext) mViewModel = createViewModel() - mViewModel.liveData.observe(this, Observer> { response -> updateViewState(response) }) + mViewModel.allOpenTasksLiveData.observe(this, Observer> { response -> updateViewState(response) }) PreferenceHelper.getInstance().init(applicationContext) mPreferenceHelper = PreferenceHelper.getInstance() @@ -512,6 +512,7 @@ class MainActivity : BaseActivity() { when (item.itemId) { android.R.id.home -> startActivity(Intent(this, SettingsActivity::class.java)) R.id.action_search -> startActivity(Intent(this, SearchActivity::class.java)) + R.id.action_view_completed_tasks -> startActivity(Intent(this, CompletedTasksActivity::class.java)) } return super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/apps/jizzu/simpletodo/vm/TaskListViewModel.kt b/app/src/main/java/apps/jizzu/simpletodo/vm/TaskListViewModel.kt index c5945fc..77bed8f 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/vm/TaskListViewModel.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/vm/TaskListViewModel.kt @@ -5,7 +5,8 @@ import apps.jizzu.simpletodo.data.models.Task import apps.jizzu.simpletodo.vm.base.BaseViewModel class TaskListViewModel(app: Application) : BaseViewModel(app) { - val liveData = repository.getAllTasksLiveData() + val allOpenTasksLiveData = repository.getAllOpenTasksLiveData() + val completedTasksLiveData = repository.getAllCompletedTasksLiveData() fun updateTaskOrder(tasks: List) = repository.updateTaskOrder(tasks) diff --git a/app/src/main/res/layout/activity_completed_tasks.xml b/app/src/main/res/layout/activity_completed_tasks.xml new file mode 100644 index 0000000..a650336 --- /dev/null +++ b/app/src/main/res/layout/activity_completed_tasks.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml index 0f432d7..ee936c3 100644 --- a/app/src/main/res/menu/menu.xml +++ b/app/src/main/res/menu/menu.xml @@ -6,7 +6,14 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 30ee092..0c7ab00 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,6 +1,7 @@ S I M P L E \u0020\u0020 T O D O Pas de tâches + Tâches terminées Vous pouvez créer de nouvelles tâches \n en utilisant le bouton + Rechercher des tâches particulières Aucune tâche trouvée :( @@ -159,4 +160,5 @@ Ajouter une nouvelle tâche Rechercher Terminé la tâche + Déplacement de la tâche vers l\'ouverture \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 95e389f..7f858d6 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,6 +1,7 @@ Нет задач + Завершенные задачи Создайте новые задачи \n с помощью кнопки + Введите поисковый запрос Совпадения не найдены :( @@ -159,4 +160,5 @@ Добавить задачу Поиск Выполнено задание + Переместил задачу в Открыть \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index ac0efe0..6e8faba 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,6 +1,7 @@ S I M P L E \u0020\u0020 T O D O Hiç görev yok + Tamamlanan Görevler Yeni görevleri \n + tuşunu kullanarak ekleyebilirsiniz Belirli bir görev ara Hiç görev bulunamadı :( @@ -159,4 +160,5 @@ Yeni görev ekle Ara Görev tamamlandı + Görevi Aç\'a taşıdı \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4b0cbdc..945aa89 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,6 +2,7 @@ To-Do S I M P L E \u0020\u0020 T O D O No tasks + Completed Tasks You can create new tasks \n using the + button Search to find particular tasks No tasks found :( @@ -172,4 +173,5 @@ Add new task Search Completed the task + Moved the task to Open \ No newline at end of file From eae8cc26f19f7839be9533d1c7bc297b816cb983 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 12:14:55 -0600 Subject: [PATCH 16/24] feat: updates icon for completed task --- .../drawable-hdpi/round_check_circle_black_24.png | Bin 0 -> 402 bytes .../drawable-mdpi/round_check_circle_black_24.png | Bin 0 -> 282 bytes .../round_check_circle_black_24.png | Bin 0 -> 488 bytes .../round_check_circle_black_24.png | Bin 0 -> 710 bytes .../round_check_circle_black_24.png | Bin 0 -> 919 bytes .../main/res/drawable/drawable_completed_task.xml | 4 ++++ app/src/main/res/menu/menu.xml | 2 +- 7 files changed, 5 insertions(+), 1 deletion(-) create mode 100755 app/src/main/res/drawable-hdpi/round_check_circle_black_24.png create mode 100755 app/src/main/res/drawable-mdpi/round_check_circle_black_24.png create mode 100755 app/src/main/res/drawable-xhdpi/round_check_circle_black_24.png create mode 100755 app/src/main/res/drawable-xxhdpi/round_check_circle_black_24.png create mode 100755 app/src/main/res/drawable-xxxhdpi/round_check_circle_black_24.png create mode 100644 app/src/main/res/drawable/drawable_completed_task.xml diff --git a/app/src/main/res/drawable-hdpi/round_check_circle_black_24.png b/app/src/main/res/drawable-hdpi/round_check_circle_black_24.png new file mode 100755 index 0000000000000000000000000000000000000000..1e5d330ad6590d5b2c637592c2ece7e9143762fa GIT binary patch literal 402 zcmV;D0d4+?P)obbpy zUw!hNIbBZ_)svtdfIMz?5Sw>3(zTa<8*CY%x_J*5GMMFkJ3!$wijjfxnq zUzD=dd7p&PXM_SfOJ?pEjTLEarvhCiGb6yNwBAL|yh@oldPQ=cjH6XD+1($Najj|Q zS}~KhXFM0l56)><%nSoF1~aIfD@%NC%%n3)log& wDo8|?eHWV{K+#+VcJdn$-yn?$pvXuB08LMC)ek-!FaQ7m07*qoM6N<$f&-AQ;s5{u literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/round_check_circle_black_24.png b/app/src/main/res/drawable-mdpi/round_check_circle_black_24.png new file mode 100755 index 0000000000000000000000000000000000000000..794ab708f2e64c94abbdfdeb4684be7c95c26f9f GIT binary patch literal 282 zcmV+#0p10OU>7m zfN6C0P?o8A8R#I9OO%V5Z#DmVL3tqv3+l{bc?B3C>I>z8AWVQVo9KLu@(~jAk-Sm| zsIccq70sP)&QQ({;}JYB^MQ*;qeyQDEva!Ot^ z3G5=FB@E2acgR;s0WeM{Jn1vbx8yzYFwQFyx`&1YZI3)`Mb2MHpjhzAuOm@eK#?6` zUdW=T_~ezBDDDw!uOj&kM9UqDHWD!hOmkz%Cu8zL8^t^F=`&*hq^SOw&mjiiPz>~d zaD*veK#UGhbdZRfphno|g${}a5|uSI!agrFY_92gbVM{y5s9&aB7-P52q7@#4Q5a* zB3icj$}wW$B8mi$2-<=}{)xme&vg+17_-TnpKF*kE}SEhOmJeE?=xe+GF?2xNP09& z|5v{)nscxG1+gTlIp=G9jFo{1AVhZKSBQ?ycf!Dnqz;HTeY;Tf?*tO=#wMe7V}ZP6 epy-eQqW}O-GFQ-`1n1&v0cRDb}{q-@w|r^SmKxW zpaDxnRz@7}A9ec5V`U<`=RD^-w*h#eJib9BpB?8kxXHCcWMlymY11 z9HEESCnQo*nvSy^;Uil6h+&d_j<9cf=+Gyb=NKM3wh)7)TTXI>Ewj@PHAyEKo@0Lc z0Rb{mQj)jGM621J!m3GjIYNQ4(hQB0Y;uOI5u%D1CE4T%9|*ODMA&PR0NmgWVzEsk z2qONz=6Ob7l@k!j1`^XYh^Q1xPHDO>Sp8-R1NXfLWieFrnp4DBg35GV7KR0W_`Ps$ zZk48oTMMgLSfn1`&6oIZPnAjGM22(gm~%2yev8vyjxK`vy5#UANuF;;F(>3n;@KVc s{*Q>_;1*~h!LVOyK{*%&qhJ&O04u-E?zN<5E&u=k07*qoM6N<$g4g{w4FCWD literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/round_check_circle_black_24.png b/app/src/main/res/drawable-xxxhdpi/round_check_circle_black_24.png new file mode 100755 index 0000000000000000000000000000000000000000..915a10a49294e95926d44f6e65997478f695cfa0 GIT binary patch literal 919 zcmV;I18Dq-P)lzG6`BrFNdiz!WcE)@Ph_Z z)EQ%hDu?N1DXFx8-CW=WGRGtr*-0Czv66FqK@t1Jc~;~_ALY{ieJYpL{9;*`5CgiyuV(4HR zdG0Npv}_ppk6~K02BoC6v>;CnIqMe#EMq>axr3UjQ6RDka@H(c_+t*&P*W8m$}{P3 zem8$>Z~hCL3GzhJ=WRZ~J=D}*BB^U2d5@J1}4SSpq*W&&@DADjZ z{~QYF8zn;7?tgwj+X-bTrSruQp*&6LeDM^_${y#ND`T`V#q-5Rj1HuDzBqu zQ0N9Rx|!nn;wDDph~RFsiuo+(w3qo}9HU7T*cEd8v4ii<=Zi^DmgZbhHMpb0!l<^3*=8Hj$4xyMwus2^E#Ha^h z?s(7<0_Pt?3Dk{I8w%ACpxNet`A1M9EdaA8agJbh{u4r}qLB4FoiD1%f34DQe}43@ zRZ4t|aRhtw8B0nz5=_s7xN+99twE2lJk7F`xMc>Hg?%~ t4C>zUrsudbOi|~)jpw+TOeT}b{07y@Wt_z~7`Ffb002ovPDHLkV1n^VwlV+! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/drawable_completed_task.xml b/app/src/main/res/drawable/drawable_completed_task.xml new file mode 100644 index 0000000..5c660f4 --- /dev/null +++ b/app/src/main/res/drawable/drawable_completed_task.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml index ee936c3..06bbb74 100644 --- a/app/src/main/res/menu/menu.xml +++ b/app/src/main/res/menu/menu.xml @@ -12,7 +12,7 @@ From e510040ff4527bc5329644f58d838fb05e83313e Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 14:36:14 -0600 Subject: [PATCH 17/24] fix: fixes the bug in search screen - Adds a Task Completion Listener in SearchActivity - Adds a method in SearchTaskModel to update tasks - Updates Task Completion Listener in MainActivity **Note**: The bug was introduced when checkboxes were added & SearchActivity doesn't have a Task Completion Listener. Any action performed in the Search Activity, updated the items in MainActivity since the recycler adapter used the Task Completion Listener in the MainActivity. This has been fixed by adding a separate Task Completion Listener for Search Activity. --- .../jizzu/simpletodo/ui/view/MainActivity.kt | 4 +--- .../jizzu/simpletodo/ui/view/SearchActivity.kt | 18 ++++++++++++++++-- .../simpletodo/vm/SearchTasksViewModel.kt | 2 ++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt index 03ba89c..2aaa82f 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt @@ -532,9 +532,7 @@ class MainActivity : BaseActivity() { val task = mAdapter.getTaskAtPosition(position) task.taskStatus = task.taskStatus.not() mViewModel.updateTask(task) - if (task.taskStatus) { //todo: does it require to check task status? - completeTask(position) - } + completeTask(position) } }) } diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/SearchActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/SearchActivity.kt index 68fb330..b0661f6 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/SearchActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/SearchActivity.kt @@ -20,6 +20,7 @@ import apps.jizzu.simpletodo.ui.recycler.RecyclerViewAdapter import apps.jizzu.simpletodo.ui.view.base.BaseActivity import apps.jizzu.simpletodo.utils.PreferenceHelper import apps.jizzu.simpletodo.utils.gone +import apps.jizzu.simpletodo.utils.toast import apps.jizzu.simpletodo.utils.visible import apps.jizzu.simpletodo.vm.SearchTasksViewModel import daio.io.dresscode.dressCodeStyleId @@ -58,10 +59,23 @@ class SearchActivity : BaseActivity(), SearchView.OnQueryTextListener { showTaskDetailsActivity(task) } }) + + mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener { + override fun onTaskStatusChanged(v: View, position: Int) { + val task = mAdapter.getTaskAtPosition(position) + task.taskStatus = task.taskStatus.not() + mViewModel.updateTask(task) + if (task.taskStatus) { + toast(getString(R.string.complete_task_status)) + } else { + toast(getString(R.string.move_task_to_open)) + } + } + }) } private fun updateViewState(tasks: List) = if (tasks.isEmpty()) showEmptyView(false) - else showTaskList(tasks) + else showTaskList(tasks) private fun showEmptyView(isSearchFieldEmpty: Boolean) { mAdapter.updateData(arrayListOf()) @@ -97,7 +111,7 @@ class SearchActivity : BaseActivity(), SearchView.OnQueryTextListener { searchText.setBackgroundResource(R.drawable.search_view_background) val view: View = searchView.findViewById(androidx.appcompat.R.id.search_plate) - when(dressCodeStyleId) { + when (dressCodeStyleId) { R.style.AppTheme_Light -> { searchText.setHintTextColor(ContextCompat.getColor(this, R.color.black)) view.setBackgroundColor(ContextCompat.getColor(this, R.color.white)) diff --git a/app/src/main/java/apps/jizzu/simpletodo/vm/SearchTasksViewModel.kt b/app/src/main/java/apps/jizzu/simpletodo/vm/SearchTasksViewModel.kt index 397a5c6..69bc1e7 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/vm/SearchTasksViewModel.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/vm/SearchTasksViewModel.kt @@ -16,4 +16,6 @@ class SearchTasksViewModel(app: Application) : BaseViewModel(app) { MutableLiveData() } } + + fun updateTask(task: Task) = repository.updateTask(task) } \ No newline at end of file From 7790732118a073f684a3da520730bd54b2554463 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 15:02:52 -0600 Subject: [PATCH 18/24] fix: updates the database version to the correct number (5 to 4) --- .../java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt index 9769d13..f43bbf9 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/data/database/TasksDatabase.kt @@ -9,7 +9,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase import apps.jizzu.simpletodo.data.models.Task import apps.jizzu.simpletodo.utils.PreferenceHelper -@Database(entities = [Task::class], version = 5) +@Database(entities = [Task::class], version = 4) abstract class TasksDatabase : RoomDatabase() { abstract fun taskDAO(): TaskDao From f650bd53be3afb86d24b5c2b50ae7ffb7fd6c84d Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 22:31:22 -0600 Subject: [PATCH 19/24] feat: disables editing a completed task in the edit task screen --- .../apps/jizzu/simpletodo/ui/view/task/EditTaskActivity.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/EditTaskActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/EditTaskActivity.kt index 4699d8e..654d75e 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/EditTaskActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/EditTaskActivity.kt @@ -3,6 +3,7 @@ package apps.jizzu.simpletodo.ui.view.task import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.View import androidx.lifecycle.ViewModelProviders import apps.jizzu.simpletodo.R import apps.jizzu.simpletodo.data.models.Task @@ -10,6 +11,7 @@ import apps.jizzu.simpletodo.service.alarm.AlarmHelper import apps.jizzu.simpletodo.ui.dialogs.DeleteTaskDialogFragment import apps.jizzu.simpletodo.ui.view.base.BaseTaskActivity import apps.jizzu.simpletodo.utils.DateAndTimeFormatter +import apps.jizzu.simpletodo.utils.gone import apps.jizzu.simpletodo.utils.toast import apps.jizzu.simpletodo.utils.visible import apps.jizzu.simpletodo.vm.EditTaskViewModel @@ -90,6 +92,11 @@ class EditTaskActivity : BaseTaskActivity() { } hideKeyboard(mTitleEditText) } + + mTitleEditText.isEnabled = !mTaskStatus + tvTaskNote.isEnabled = !mTaskStatus + tvTaskReminder.isEnabled = !mTaskStatus + btnTaskConfirm.visibility = if (!mTaskStatus) View.VISIBLE else View.GONE } private fun showDeleteTaskDialog(task: Task) = DeleteTaskDialogFragment(task).show(supportFragmentManager, null) From 028f7a8f867998dc49e87134d374ac7163e40484 Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 22:41:07 -0600 Subject: [PATCH 20/24] feat: updates swipe actions & fix a bug on 'undo'ing a completed task - Updates the swipe actions to 'Swipe from Left to Right: Complete the task', 'Swipe from Right to Left: Delete the task' - Fixes the bug when 'undo'ing a completed task by changing the status before saving it --- .../apps/jizzu/simpletodo/ui/view/MainActivity.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt index 2aaa82f..0feba5a 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt @@ -165,7 +165,11 @@ class MainActivity : BaseActivity() { } override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - deleteTask(viewHolder.adapterPosition) + if (direction == ItemTouchHelper.END) { + completeTask(viewHolder.adapterPosition) + } else if (direction == ItemTouchHelper.START){ + deleteTask(viewHolder.adapterPosition) + } } }) helper.attachToRecyclerView(mRecyclerView) @@ -176,11 +180,14 @@ class MainActivity : BaseActivity() { val isCompletedTaskHasLastPosition = completedTask.position == mAdapter.itemCount - 1 val alarmHelper = AlarmHelper.getInstance() alarmHelper.removeAlarm(completedTask.timeStamp) + completedTask.taskStatus = completedTask.taskStatus.not() + mViewModel.updateTask(completedTask) mAdapter.removeTask(position) var isUndoClicked = false mSnackbar = Snackbar.make(mRecyclerView, R.string.complete_task_status, Snackbar.LENGTH_LONG) mSnackbar?.setAction(R.string.snackbar_undo) { + completedTask.taskStatus = completedTask.taskStatus.not() mViewModel.saveTask(completedTask) if (completedTask.date != 0L && completedTask.date > Calendar.getInstance().timeInMillis) { alarmHelper.setAlarm(completedTask) @@ -529,9 +536,6 @@ class MainActivity : BaseActivity() { mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener { override fun onTaskStatusChanged(v: View, position: Int) { toast(getString(R.string.complete_task_status)) - val task = mAdapter.getTaskAtPosition(position) - task.taskStatus = task.taskStatus.not() - mViewModel.updateTask(task) completeTask(position) } }) From 8f0b614ab45e687ea691c89982506dbc5150277b Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 22:59:22 -0600 Subject: [PATCH 21/24] fix: updates the completed task messages to be consistent with other status messages --- app/src/main/res/values-fr/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 4 ++-- app/src/main/res/values-tr/strings.xml | 2 +- app/src/main/res/values/strings.xml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0c7ab00..eb45724 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -159,6 +159,6 @@ ////////////////////////////// Ajouter une nouvelle tâche Rechercher - Terminé la tâche - Déplacement de la tâche vers l\'ouverture + La tâche est terminée + La tâche est déplacée vers Ouvrir \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7f858d6..64007c3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -159,6 +159,6 @@ ////////////////////////////// Добавить задачу Поиск - Выполнено задание - Переместил задачу в Открыть + Задача выполнена + Задача перемещена в Открыть \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 6e8faba..8154839 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -160,5 +160,5 @@ Yeni görev ekle Ara Görev tamamlandı - Görevi Aç\'a taşıdı + Görev Açık konumuna taşındı \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 945aa89..2f624db 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -172,6 +172,6 @@ ////////////////////////////// Add new task Search - Completed the task - Moved the task to Open + Task is completed + Task is moved to Open \ No newline at end of file From c7da33f609d27f3c8bd8d3c86c773128b037324b Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 23:03:03 -0600 Subject: [PATCH 22/24] feat: adds swipe feature to completed tasks screen - Adds swipe feature to completed tasks screen - Adds the snackbar with 'undo' actions - Removes unnecessary toast BREAKING CHANGE: The swipe feature is added to completed tasks screen to help the user clean up the tasks. The swipe feauture is in consistent with the main tasks screen with one exception. Swiping from left to right moves the task from 'Completed' to 'Open' status. Swiping from 'Right' to 'Left' deletes the task as similar to Main Tasks Screen. --- .../ui/view/CompletedTasksActivity.kt | 103 ++++++++++++++++-- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt index dc00f05..67f0172 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt @@ -1,31 +1,36 @@ package apps.jizzu.simpletodo.ui.view import android.os.Bundle +import android.os.Handler import android.view.MenuItem import android.view.View import androidx.appcompat.content.res.AppCompatResources import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import apps.jizzu.simpletodo.R import apps.jizzu.simpletodo.data.models.Task import apps.jizzu.simpletodo.service.alarm.AlarmHelper import apps.jizzu.simpletodo.ui.recycler.RecyclerViewAdapter +import apps.jizzu.simpletodo.ui.recycler.RecyclerViewScrollListener import apps.jizzu.simpletodo.ui.view.base.BaseActivity import apps.jizzu.simpletodo.utils.PreferenceHelper import apps.jizzu.simpletodo.utils.gone -import apps.jizzu.simpletodo.utils.toast import apps.jizzu.simpletodo.utils.visible import apps.jizzu.simpletodo.vm.TaskListViewModel +import com.google.android.material.snackbar.Snackbar import daio.io.dresscode.matchDressCode import kotlinx.android.synthetic.main.activity_search.* import kotterknife.bindView +import java.util.* class CompletedTasksActivity : BaseActivity() { private val mRecyclerView: RecyclerView by bindView(R.id.rvCompletedTasksList) private lateinit var mViewModel: TaskListViewModel private lateinit var mAdapter: RecyclerViewAdapter + private var mSnackbar: Snackbar? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -46,6 +51,7 @@ class CompletedTasksActivity : BaseActivity() { mAdapter = RecyclerViewAdapter() mRecyclerView.adapter = mAdapter llEmptyView.visible() + createItemTouchHelper() } override fun onResume() { @@ -59,25 +65,49 @@ class CompletedTasksActivity : BaseActivity() { mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener { override fun onTaskStatusChanged(v: View, position: Int) { - toast(getString(R.string.move_task_to_open)) - val task = mAdapter.getTaskAtPosition(position) - task.taskStatus = task.taskStatus.not() - mViewModel.updateTask(task) completeTask(position) } }) } + private fun createItemTouchHelper() { + val helper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + + override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { + val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN // Flags for up and down movement + val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END // Flags for left and right movement + return ItemTouchHelper.Callback.makeMovementFlags(dragFlags, swipeFlags) + } + + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { + return true + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + if (direction == ItemTouchHelper.END) { + completeTask(viewHolder.adapterPosition) + } else if (direction == ItemTouchHelper.START){ + deleteTask(viewHolder.adapterPosition) + } + } + }) + helper.attachToRecyclerView(mRecyclerView) + } + private fun completeTask(position: Int) { val completedTask = mAdapter.getTaskAtPosition(position) val isCompletedTaskHasLastPosition = completedTask.position == mAdapter.itemCount - 1 mAdapter.removeTask(position) val alarmHelper = AlarmHelper.getInstance() alarmHelper.removeAlarm(completedTask.timeStamp) -// var isUndoClicked = false + completedTask.taskStatus = completedTask.taskStatus.not() + mViewModel.updateTask(completedTask) + + var isUndoClicked = false - /* mSnackbar = Snackbar.make(mRecyclerView, R.string.complete_task_status, Snackbar.LENGTH_LONG) + mSnackbar = Snackbar.make(mRecyclerView, R.string.complete_task_status, Snackbar.LENGTH_LONG) mSnackbar?.setAction(R.string.snackbar_undo) { + completedTask.taskStatus = completedTask.taskStatus.not() mViewModel.saveTask(completedTask) if (completedTask.date != 0L && completedTask.date > Calendar.getInstance().timeInMillis) { alarmHelper.setAlarm(completedTask) @@ -106,13 +136,66 @@ class CompletedTasksActivity : BaseActivity() { override fun onViewDetachedFromWindow(view: View) { if (!isUndoClicked) { - alarmHelper.removeNotification(completedTask.timeStamp, this@MainActivity) + alarmHelper.removeNotification(completedTask.timeStamp, this@CompletedTasksActivity) if (!isCompletedTaskHasLastPosition) recountTaskPositions() } } }) - mSnackbar?.anchorView = mFab - mSnackbar?.show()*/ + mSnackbar?.show() + } + + private fun deleteTask(position: Int) { + val deletedTask = mAdapter.getTaskAtPosition(position) + val isDeletedTaskHasLastPosition = deletedTask.position == mAdapter.itemCount - 1 + val alarmHelper = AlarmHelper.getInstance() + alarmHelper.removeAlarm(deletedTask.timeStamp) + mAdapter.removeTask(position) + mViewModel.deleteTask(deletedTask) + var isUndoClicked = false + + mSnackbar = Snackbar.make(mRecyclerView, R.string.snackbar_remove_task, Snackbar.LENGTH_LONG) + mSnackbar?.setAction(R.string.snackbar_undo) { + mViewModel.saveTask(deletedTask) + if (deletedTask.date != 0L && deletedTask.date > Calendar.getInstance().timeInMillis) { + alarmHelper.setAlarm(deletedTask) + } + isUndoClicked = true + + Handler().postDelayed({ + val firstCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() + if (firstCompletelyVisibleItem != 0 && !RecyclerViewScrollListener.isShadowShown) { + setToolbarShadow(0f, 10f) + RecyclerViewScrollListener.isShadowShown = true + } + }, 100) + } + + mSnackbar?.view?.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(view: View) { + val firstCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() + val lastCompletelyVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition() + + if (firstCompletelyVisibleItem == 0 && lastCompletelyVisibleItem == MainActivity.mTaskList.size - 1 && RecyclerViewScrollListener.isShadowShown) { + setToolbarShadow(10f, 0f) + RecyclerViewScrollListener.isShadowShown = false + } + } + + override fun onViewDetachedFromWindow(view: View) { + if (!isUndoClicked) { + alarmHelper.removeNotification(deletedTask.timeStamp, this@CompletedTasksActivity) + if (!isDeletedTaskHasLastPosition) recountTaskPositions() + } + } + }) + mSnackbar?.show() + } + + private fun recountTaskPositions() { + for ((newPosition, task) in MainActivity.mTaskList.withIndex()) { + task.position = newPosition + } + mViewModel.updateTaskOrder(MainActivity.mTaskList) } private fun updateViewState(tasks: List) = if (tasks.isEmpty()) showEmptyView() From a78f2600dad0a84670756c14fdf5db0a6d59e48e Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Thu, 9 Jan 2020 23:06:54 -0600 Subject: [PATCH 23/24] fix: removes unnecessary toasts --- app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt index 0feba5a..b60c346 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/MainActivity.kt @@ -535,7 +535,6 @@ class MainActivity : BaseActivity() { mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener { override fun onTaskStatusChanged(v: View, position: Int) { - toast(getString(R.string.complete_task_status)) completeTask(position) } }) From 24fcf38bc3e1966df5d8c09ffa25640c3c96c51e Mon Sep 17 00:00:00 2001 From: Subbramanian Lakshmanan Date: Fri, 10 Jan 2020 11:41:21 -0600 Subject: [PATCH 24/24] fix: updates the message when task is moved back to Open & renames the method for clarity --- .../jizzu/simpletodo/ui/view/CompletedTasksActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt index 67f0172..048613b 100644 --- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt +++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/CompletedTasksActivity.kt @@ -65,7 +65,7 @@ class CompletedTasksActivity : BaseActivity() { mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener { override fun onTaskStatusChanged(v: View, position: Int) { - completeTask(position) + moveTaskToOpen(position) } }) } @@ -85,7 +85,7 @@ class CompletedTasksActivity : BaseActivity() { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { if (direction == ItemTouchHelper.END) { - completeTask(viewHolder.adapterPosition) + moveTaskToOpen(viewHolder.adapterPosition) } else if (direction == ItemTouchHelper.START){ deleteTask(viewHolder.adapterPosition) } @@ -94,7 +94,7 @@ class CompletedTasksActivity : BaseActivity() { helper.attachToRecyclerView(mRecyclerView) } - private fun completeTask(position: Int) { + private fun moveTaskToOpen(position: Int) { val completedTask = mAdapter.getTaskAtPosition(position) val isCompletedTaskHasLastPosition = completedTask.position == mAdapter.itemCount - 1 mAdapter.removeTask(position) @@ -105,7 +105,7 @@ class CompletedTasksActivity : BaseActivity() { var isUndoClicked = false - mSnackbar = Snackbar.make(mRecyclerView, R.string.complete_task_status, Snackbar.LENGTH_LONG) + mSnackbar = Snackbar.make(mRecyclerView, R.string.move_task_to_open, Snackbar.LENGTH_LONG) mSnackbar?.setAction(R.string.snackbar_undo) { completedTask.taskStatus = completedTask.taskStatus.not() mViewModel.saveTask(completedTask)