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
diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
deleted file mode 100644
index cb4e5a8..0000000
--- a/.idea/assetWizardSettings.xml
+++ /dev/null
@@ -1,40 +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 e023764..0000000
Binary files a/.idea/caches/build_file_checksums.ser and /dev/null differ
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
diff --git a/app/build.gradle b/app/build.gradle
index 7476c84..a64c78e 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'
@@ -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"
@@ -66,8 +66,18 @@ 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"
+
+ // 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..b8f094f
--- /dev/null
+++ b/app/src/androidTest/java/apps/jizzu/simpletodo/TaskDAOTest.kt
@@ -0,0 +1,126 @@
+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() {
+ 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, 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
+ fun testUpdateTask() {
+ var tasks = taskDao.getAllTasks()
+ assertEquals(0, tasks.size)
+
+ val task = Task(1, "", "", Date().time, 1, Date().time)
+ taskDao.saveTask(task)
+
+ tasks = taskDao.getAllOpenTasks()
+ assertEquals("", tasks[0].title)
+
+ tasks[0].title = "Test"
+ taskDao.updateTask(tasks[0])
+
+ tasks = taskDao.getAllTasks()
+ assertEquals(1, tasks.size)
+ 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.getAllOpenTasks()
+ assertEquals(0, tasks.size)
+ }
+
+ @After
+ @Throws(IOException::class)
+ fun closeDb() {
+ tasksDatabase.close()
+ }
+}
\ No newline at end of file
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 30a760b..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
@@ -21,12 +21,21 @@ 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 where task_status=1 ORDER BY task_position")
+ fun getAllCompletedTasksLiveData(): 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..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.getAllTasksLiveData()
+ 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()!!
@@ -32,4 +34,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
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..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 = 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,25 @@ abstract class TasksDatabase : RoomDatabase() {
}
}
+ private val MIGRATION_3_4 = object : Migration(3, 4) {
+ 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;")
+ }
+ }
+
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..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
@@ -34,17 +34,22 @@ class Task : Serializable {
@NonNull
var timeStamp: Long = 0
+ @ColumnInfo(name = "task_status")
+ @NonNull
+ var taskStatus: Boolean = false
+
@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: Boolean = false) {
this.id = id
this.title = title
this.note = note
this.date = date
this.position = position
this.timeStamp = timeStamp
+ this.taskStatus = taskStatus
}
}
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..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
@@ -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,11 @@ class RecyclerViewAdapter : RecyclerView.Adapter> { response -> updateViewState(response) })
+
+ mRecyclerView.setHasFixedSize(true)
+ mRecyclerView.layoutManager = LinearLayoutManager(this)
+ mAdapter = RecyclerViewAdapter()
+ mRecyclerView.adapter = mAdapter
+ llEmptyView.visible()
+ createItemTouchHelper()
+ }
+
+ 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) {
+ moveTaskToOpen(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) {
+ moveTaskToOpen(viewHolder.adapterPosition)
+ } else if (direction == ItemTouchHelper.START){
+ deleteTask(viewHolder.adapterPosition)
+ }
+ }
+ })
+ helper.attachToRecyclerView(mRecyclerView)
+ }
+
+ private fun moveTaskToOpen(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)
+ completedTask.taskStatus = completedTask.taskStatus.not()
+ mViewModel.updateTask(completedTask)
+
+ var isUndoClicked = false
+
+ 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)
+ 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@CompletedTasksActivity)
+ if (!isCompletedTaskHasLastPosition) recountTaskPositions()
+ }
+ }
+ })
+ 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()
+ 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 556a58d..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
@@ -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()
@@ -165,12 +165,66 @@ 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)
}
+ 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)
+ 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)
+ }
+ 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
@@ -465,6 +519,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)
}
@@ -477,6 +532,12 @@ class MainActivity : BaseActivity() {
showTaskDetailsActivity(mAdapter.getTaskAtPosition(position))
}
})
+
+ mAdapter.setTaskCompletionListener(object : RecyclerViewAdapter.TaskCompletionListener {
+ override fun onTaskStatusChanged(v: View, position: Int) {
+ completeTask(position)
+ }
+ })
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
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/ui/view/base/BaseActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/base/BaseActivity.kt
index 49b1040..88af016 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)
}
diff --git a/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/AddTaskActivity.kt b/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/AddTaskActivity.kt
index 70403d8..c05d6be 100644
--- a/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/AddTaskActivity.kt
+++ b/app/src/main/java/apps/jizzu/simpletodo/ui/view/task/AddTaskActivity.kt
@@ -49,6 +49,7 @@ class AddTaskActivity : BaseTaskActivity() {
} else if (task.date != 0L) {
AlarmHelper.getInstance().setAlarm(task)
}
+ task.taskStatus = false
val viewModel = createViewModel()
viewModel.saveTask(task)
finish()
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 eb6d7d7..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
@@ -18,6 +20,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 +44,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 +69,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
@@ -88,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)
@@ -109,7 +118,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/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
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 993597b..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,11 +5,14 @@ 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)
fun deleteTask(task: Task) = repository.deleteTask(task)
fun saveTask(task: Task) = repository.saveTask(task)
+
+ fun updateTask(task: Task) = repository.updateTask(task)
}
\ No newline at end of file
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 0000000..1e5d330
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/round_check_circle_black_24.png differ
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 0000000..794ab70
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/round_check_circle_black_24.png differ
diff --git a/app/src/main/res/drawable-xhdpi/round_check_circle_black_24.png b/app/src/main/res/drawable-xhdpi/round_check_circle_black_24.png
new file mode 100755
index 0000000..aa9ba9c
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/round_check_circle_black_24.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/round_check_circle_black_24.png b/app/src/main/res/drawable-xxhdpi/round_check_circle_black_24.png
new file mode 100755
index 0000000..58896a0
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/round_check_circle_black_24.png differ
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 0000000..915a10a
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/round_check_circle_black_24.png differ
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/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/layout/task_item_view.xml b/app/src/main/res/layout/task_item_view.xml
new file mode 100755
index 0000000..305ca5f
--- /dev/null
+++ b/app/src/main/res/layout/task_item_view.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..06bbb74 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 c80a55e..eb45724 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 :(
@@ -158,4 +159,6 @@
//////////////////////////////
Ajouter une nouvelle tâche
Rechercher
+ 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 aa0372e..64007c3 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1,6 +1,7 @@
Нет задач
+ Завершенные задачи
Создайте новые задачи \n с помощью кнопки +
Введите поисковый запрос
Совпадения не найдены :(
@@ -158,4 +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 69276ea..8154839 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ı :(
@@ -158,4 +159,6 @@
//////////////////////////////
Yeni görev ekle
Ara
+ Görev tamamlandı
+ 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 71caf73..2f624db 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 :(
@@ -171,4 +172,6 @@
//////////////////////////////
Add new task
Search
+ Task is completed
+ Task is moved to Open
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index f29398a..f6f2cac 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlinVersion = '1.3.31'
+ ext.kotlinVersion = '1.3.61'
repositories {
jcenter()
@@ -11,8 +11,8 @@ buildscript {
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.27.1'
+ classpath 'com.google.gms:google-services:4.3.3'
+ classpath 'io.fabric.tools:gradle:1.31.0'
}
}
@@ -36,15 +36,16 @@ ext {
versionName = "1.8.7"
// App dependencies
- appcompatVersion = "1.0.2"
- materialVersion = "1.1.0-alpha04"
- androidxVersion = "1.0.0"
+ appcompatVersion = "1.1.0-alpha05"
+ 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.7"
- crashlyticsVersion = "2.9.9"
+ 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