diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 45b5654..88ea3aa 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,8 +1,5 @@ - - diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 169fd0d..5cd135a 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,8 +1,10 @@ + diff --git a/app/build.gradle b/app/build.gradle index b71f897..a67b989 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,44 +3,46 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' - android { compileSdkVersion 29 - buildToolsVersion "29.0.2" + buildToolsVersion "29.0.3" + defaultConfig { - applicationId "com.codingblocks.todo" + applicationId "com.example.todoapp" minSdkVersion 23 targetSdkVersion 29 versionCode 1 versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } -} -ext { - ankoVersion = '0.10.6' - room_version = "2.2.1" } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.core:core-ktx:1.1.0' + implementation 'androidx.core:core-ktx:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.recyclerview:recyclerview:1.0.0' - implementation 'com.google.android.material:material:1.0.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + + implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'com.google.android.material:material:1.1.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3' //database - implementation "androidx.room:room-runtime:$room_version" - implementation "androidx.room:room-ktx:$room_version" - kapt "androidx.room:room-compiler:$room_version" + implementation "androidx.room:room-runtime:2.2.3" + implementation "androidx.room:room-ktx:2.2.3" + kapt "androidx.room:room-compiler:2.2.3" } diff --git a/app/src/androidTest/java/com/codingblocks/todo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/todoapp/ExampleInstrumentedTest.kt similarity index 85% rename from app/src/androidTest/java/com/codingblocks/todo/ExampleInstrumentedTest.kt rename to app/src/androidTest/java/com/example/todoapp/ExampleInstrumentedTest.kt index 0e11e5c..5d6b24c 100644 --- a/app/src/androidTest/java/com/codingblocks/todo/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/example/todoapp/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.codingblocks.todo +package com.example.todoapp import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.codingblocks.todo", appContext.packageName) + assertEquals("com.example.todoapp", appContext.packageName) } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e6a72b6..131ed5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="com.example.todoapp"> - + @@ -21,10 +18,6 @@ - - \ No newline at end of file diff --git a/app/src/main/java/com/codingblocks/todo/AlarmReceiver.kt b/app/src/main/java/com/codingblocks/todo/AlarmReceiver.kt deleted file mode 100644 index 4309b97..0000000 --- a/app/src/main/java/com/codingblocks/todo/AlarmReceiver.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.codingblocks.todo - -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.graphics.BitmapFactory -import android.graphics.Color -import android.media.RingtoneManager -import android.os.Build -import androidx.core.app.NotificationCompat - -class AlarmReceiver : BroadcastReceiver() { - - override fun onReceive(context: Context, intent: Intent) { - - val mNotificationManager = - context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - mNotificationManager.createNotificationChannel( - NotificationChannel( - "default", - "Todo", - NotificationManager.IMPORTANCE_DEFAULT - ) - ) - } - - val taskRowId = intent.extras?.getString(TASK_ID) - val taskTitle = intent.extras?.getString(TASK_TITLE) - val taskTask = intent.extras?.getString(TASK_TASK) - - //To Open the app on clicking notification - val notificationIntent = Intent(context, MainActivity::class.java) - val pendingIntent = PendingIntent.getActivity( - context, - 0, - notificationIntent, - PendingIntent.FLAG_UPDATE_CURRENT - ) - - val notificationFinishIntent = Intent(context, MainActivity::class.java) - notificationFinishIntent.putExtra(TASK_ID, taskRowId) - notificationFinishIntent.action = "FINISH" - val pendingFinishIntent = PendingIntent.getActivity( - context, - 0, - notificationFinishIntent, - PendingIntent.FLAG_UPDATE_CURRENT - ) - - val title = taskTitle//taskTitle//task title - val message = taskTask//taskTask//task - val icon = R.mipmap.ic_launcher - val time = System.currentTimeMillis() - - val notification = NotificationCompat.Builder(context, "default") - .setContentTitle(title) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher)) - .setContentText(message) - .setContentIntent(pendingIntent) - .setColor(Color.argb(225, 225, 87, 34)) - .setSmallIcon(icon) - .setWhen(time) - .addAction(R.drawable.ic_check_black_24dp, "Finish", pendingFinishIntent) - .setAutoCancel(true) - .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) - .build() - mNotificationManager.notify(Integer.parseInt(taskRowId?:""/*rowId*/), notification) - - - - } -} diff --git a/app/src/main/java/com/codingblocks/todo/AppDatabase.kt b/app/src/main/java/com/codingblocks/todo/AppDatabase.kt deleted file mode 100644 index 411a9ac..0000000 --- a/app/src/main/java/com/codingblocks/todo/AppDatabase.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.codingblocks.todo - -import androidx.room.Database -import androidx.room.RoomDatabase - -@Database(entities = [TaskModel::class],version = 1) -abstract class AppDatabase : RoomDatabase() { - abstract fun taskDao(): TaskDao -} \ No newline at end of file diff --git a/app/src/main/java/com/codingblocks/todo/Constants.kt b/app/src/main/java/com/codingblocks/todo/Constants.kt deleted file mode 100644 index 23d5541..0000000 --- a/app/src/main/java/com/codingblocks/todo/Constants.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.codingblocks.todo - -/***************** Task *****************/ - -const val TABLE_TASK = "TASK" -const val TASK_TITLE = "title" -const val TASK_TASK = "task" -const val TASK_CATEGORY = "category" -const val TASK_DATE = "date" -const val TASK_TIME = "time" -const val TASK_FINISH = "finish" -const val TASK_ID = "task_id" - - -const val TASK_IS_FINISH = 1 -const val TASK_IS_NOT_FINISH = 0 diff --git a/app/src/main/java/com/codingblocks/todo/HistoryActivity.kt b/app/src/main/java/com/codingblocks/todo/HistoryActivity.kt deleted file mode 100644 index c25c77e..0000000 --- a/app/src/main/java/com/codingblocks/todo/HistoryActivity.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.codingblocks.todo - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import androidx.core.view.isVisible -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.room.Room -import kotlinx.android.synthetic.main.activity_history.* - -class HistoryActivity : AppCompatActivity() { - var mArrayList: ArrayList = ArrayList() - lateinit var taskAdapter: TaskAdapter - - val db: AppDatabase by lazy { - Room.databaseBuilder( - this, - AppDatabase::class.java, - "todo.db" - ).fallbackToDestructiveMigration() - .build() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_history) - - recyclerViewTask.setHasFixedSize(true) - recyclerViewTask.layoutManager = LinearLayoutManager(this) - taskAdapter = TaskAdapter(mArrayList) - recyclerViewTask.adapter = taskAdapter - - db.taskDao().getTask(TASK_IS_FINISH).observe(this, Observer { - if (it.isNotEmpty()) { - mArrayList = it as ArrayList - taskAdapter.setList(mArrayList) - } else { - mArrayList = it as ArrayList - taskAdapter.setList(mArrayList) - } - txtNoTask.isVisible = it.isEmpty() - }) - } -} diff --git a/app/src/main/java/com/codingblocks/todo/MainActivity.kt b/app/src/main/java/com/codingblocks/todo/MainActivity.kt deleted file mode 100644 index 34bc72f..0000000 --- a/app/src/main/java/com/codingblocks/todo/MainActivity.kt +++ /dev/null @@ -1,236 +0,0 @@ -package com.codingblocks.todo - -import android.app.NotificationManager -import android.content.Context -import android.content.Intent -import android.graphics.* -import android.os.Bundle -import android.util.DisplayMetrics -import android.view.Menu -import android.view.MenuItem -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.SearchView -import androidx.core.view.isVisible -import androidx.lifecycle.Observer -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.room.Room -import kotlinx.android.synthetic.main.activity_main.* - -class MainActivity : AppCompatActivity() { - - var mArrayList: ArrayList = ArrayList() - lateinit var taskAdapter: TaskAdapter - - val mNotificationManager by lazy { - getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - } - - val db: AppDatabase by lazy { - Room.databaseBuilder( - this, - AppDatabase::class.java, - "todo.db" - ).fallbackToDestructiveMigration() - .build() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - setSupportActionBar(toolbarAddTask) - - - recyclerViewTask.setHasFixedSize(true) - recyclerViewTask.layoutManager = LinearLayoutManager(this) - taskAdapter = TaskAdapter(mArrayList) - recyclerViewTask.adapter = taskAdapter - - initSwipe() - - fabAddTask.setOnClickListener { - startActivity(Intent(this, NewTaskActivity::class.java)) - } - displayTasks() - - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.main_menu, menu) - val item = menu.findItem(R.id.search) - val searchView = item.actionView as SearchView - item.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionExpand(p0: MenuItem?): Boolean { - displayTasks() - return true - - } - - override fun onMenuItemActionCollapse(p0: MenuItem?): Boolean { - displayTasks() - return true - - } - - }) - searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String): Boolean { - return false - } - - override fun onQueryTextChange(newText: String): Boolean { - if (newText.isNotEmpty()) - displayTasks(newText) - return true - } - }) - return true - } - - private fun displayTasks(searchQuery: String = "") { - db.taskDao().getTask(TASK_IS_NOT_FINISH).observe(this, Observer { - if (!it.isEmpty()) { - taskAdapter.setList(it.filter { c -> - c.title.contains(searchQuery, true) || - c.task.contains(searchQuery, true) - } as ArrayList) - } else { - taskAdapter.setList(arrayListOf()) - } - txtNoTask.isVisible = it.isEmpty() - }) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { - R.id.history -> { - startActivity(Intent(this, HistoryActivity::class.java)) - true - } - else -> super.onOptionsItemSelected(item) - } - - override fun onStart() { - super.onStart() - - if (intent.action == "FINISH") { - val id = intent.getStringExtra(TASK_ID) - id?.let { - db.taskDao().finishTask(id.toLong()) - mNotificationManager.cancel(id.toInt()) - } - } - - } - - //Dont Explain this code - private fun initSwipe() { - - val simpleItemTouchCallback = object : - ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { - - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return false - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - val position = viewHolder.adapterPosition - - if (direction == ItemTouchHelper.LEFT) { - db.taskDao().deleleTask(taskAdapter.getItemId(position)) - } else { - db.taskDao().finishTask(taskAdapter.getItemId(position)) - } - } - - override fun onChildDraw( - canvas: Canvas, - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - dX: Float, - dY: Float, - actionState: Int, - isCurrentlyActive: Boolean - ) { - - if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { - - val itemView = viewHolder.itemView - - val paint = Paint() - val iconBitmap: Bitmap - - if (dX > 0) { - - iconBitmap = - BitmapFactory.decodeResource(resources, R.mipmap.ic_check_white_png) - - paint.color = Color.parseColor(getString(R.color.green)) - - canvas.drawRect( - itemView.left.toFloat(), itemView.top.toFloat(), - itemView.left.toFloat() + dX, itemView.bottom.toFloat(), paint - ) - - // Set the image icon for Right side swipe - canvas.drawBitmap( - iconBitmap, - itemView.left.toFloat() + convertDpToPx(16), - itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - iconBitmap.height.toFloat()) / 2, - paint - ) - } else { - - iconBitmap = - BitmapFactory.decodeResource(resources, R.mipmap.ic_delete_white_png) - - paint.color = Color.parseColor(getString(R.color.red)) - - canvas.drawRect( - itemView.right.toFloat() + dX, itemView.top.toFloat(), - itemView.right.toFloat(), itemView.bottom.toFloat(), paint - ) - - //Set the image icon for Left side swipe - canvas.drawBitmap( - iconBitmap, - itemView.right.toFloat() - convertDpToPx(16) - iconBitmap.width, - itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - iconBitmap.height.toFloat()) / 2, - paint - ) - } - - val ALPHA_FULL: Float = 1.0f - - // Fade out the view as it is swiped out of the parent's bounds - val alpha: Float = - ALPHA_FULL - Math.abs(dX) / viewHolder.itemView.width.toFloat() - viewHolder.itemView.alpha = alpha - viewHolder.itemView.translationX = dX - - } else { - super.onChildDraw( - canvas, - recyclerView, - viewHolder, - dX, - dY, - actionState, - isCurrentlyActive - ) - } - } - } - val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback) - itemTouchHelper.attachToRecyclerView(recyclerViewTask) - } - - - private fun convertDpToPx(dp: Int): Int { - return Math.round(dp * (resources.displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)) - } -} diff --git a/app/src/main/java/com/codingblocks/todo/NewTaskActivity.kt b/app/src/main/java/com/codingblocks/todo/NewTaskActivity.kt deleted file mode 100644 index 79a837b..0000000 --- a/app/src/main/java/com/codingblocks/todo/NewTaskActivity.kt +++ /dev/null @@ -1,231 +0,0 @@ -package com.codingblocks.todo - -import android.app.AlarmManager -import android.app.DatePickerDialog -import android.app.PendingIntent -import android.app.TimePickerDialog -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.view.View -import android.widget.ArrayAdapter -import androidx.appcompat.app.AppCompatActivity -import androidx.room.Room -import kotlinx.android.synthetic.main.activity_new_task.* -import java.text.SimpleDateFormat -import java.util.* - - -class NewTaskActivity : AppCompatActivity(), View.OnClickListener { - - lateinit var myCalendar: Calendar - - lateinit var dateSetListener: DatePickerDialog.OnDateSetListener - lateinit var timeSetListener: TimePickerDialog.OnTimeSetListener - - //Final variable to save in database - private var finalDate = "" - private var finalTime = "" - private var finalTitle = "" - private var finalTask = "" - private var finalCategoryName = "Default" - - private val labels: ArrayList = - arrayListOf("Personal", "Business", "Insurance", "Shopping", "Banking") - - - val db: AppDatabase by lazy { - Room.databaseBuilder( - this, - AppDatabase::class.java, - "todo.db" - ).fallbackToDestructiveMigration() - .allowMainThreadQueries() - .build() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_new_task) - - setSupportActionBar(toolbarAddTask) - supportActionBar?.apply { - setDisplayHomeAsUpEnabled(true) - setDisplayShowHomeEnabled(true) - } - - saveBtn.setOnClickListener(this) - dateEdt.setOnClickListener(this) - timeEdt.setOnClickListener(this) - - loadDataInSpinner() - } - - private fun loadDataInSpinner() { - val dataAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, labels) - - dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - - labels.sort() - - spinnerCategory.adapter = dataAdapter - } - - override fun onClick(view: View) { - when (view.id) { - R.id.dateEdt -> { - dateAndTime() - setDate() - } - R.id.timeEdt -> { - dateAndTime() - setTime() - } - R.id.saveBtn -> { - finalCategoryName = spinnerCategory.selectedItem.toString() - saveTask() - } - } - } - - - private fun saveTask() { - finalTitle = titleInpLay.editText?.text.toString().trim() - finalTask = taskInpLay.editText?.text.toString().trim() - - if (finalTitle != "") { - if (finalTask != "") { - if (finalCategoryName != "") { - if (finalDate != "") { - if (finalTime != "") { - val id = db.taskDao().insertTask( - TaskModel( - finalTitle, - finalTask, - finalCategoryName, - finalDate, - finalTime - ) - ) - myCalendar.set(Calendar.SECOND, 0) - setNotification(myCalendar, id) // Set notification - } else { - - } - } else { - - } - } else { - //show toast - } - } else { - //show toast - } - } else { - //show toast - } - } - - private fun setNotification(myCalendar: Calendar, id: Long) { - - val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager - - val intent = Intent(this, AlarmReceiver::class.java) - intent.putExtra(TASK_ID, id.toString()) - intent.putExtra(TASK_TITLE, finalTitle) - intent.putExtra(TASK_TASK, finalTask) - - val pendingIntent = - PendingIntent.getBroadcast(this, 0/*taskRowId*/, intent, PendingIntent.FLAG_ONE_SHOT) - alarmManager.setExactAndAllowWhileIdle( - AlarmManager.RTC_WAKEUP, - myCalendar.timeInMillis, - pendingIntent - ) - finish() - } - - /** - * current Date and Time initialize - * */ - private fun dateAndTime() { - - myCalendar = Calendar.getInstance() - - dateSetListener = - DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth -> - myCalendar.set(Calendar.YEAR, year) - myCalendar.set(Calendar.MONTH, monthOfYear) - myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth) - updateLabelDate() - } - - timeSetListener = TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute -> - myCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay) - myCalendar.set(Calendar.MINUTE, minute) - updateLabelTime() - } - - } - - /** - * @DatePickerDialog for selecting date - * */ - private fun setDate() { - - val datePickerDialog = DatePickerDialog( - this, dateSetListener, myCalendar.get(Calendar.YEAR), - myCalendar.get(Calendar.MONTH), myCalendar.get(Calendar.DAY_OF_MONTH) - ) - datePickerDialog.datePicker.minDate = System.currentTimeMillis() - 1000 - datePickerDialog.show() - - } - - - /** - * @TimePickerDialog for selecting time - * */ - private fun setTime() { - val timePickerDialog = TimePickerDialog( - this, timeSetListener, myCalendar.get(Calendar.HOUR_OF_DAY), - myCalendar.get(Calendar.MINUTE), false - ) - timePickerDialog.show() - } - - /** - * UI Update of time - * */ - private fun updateLabelTime() { - - val myFormat = "HH:mm" // HH:mm:ss - val sdf = SimpleDateFormat(myFormat, Locale.US) - - finalTime = sdf.format(myCalendar.time) - - - val myFormat2 = "h:mm a" - val sdf2 = SimpleDateFormat(myFormat2, Locale.US) - timeEdt.setText(sdf2.format(myCalendar.time)) - } - - - /** - * UI Update of Date - * */ - private fun updateLabelDate() { - - val myFormat = "yyyy-MM-dd" - val sdf = SimpleDateFormat(myFormat, Locale.US) - - finalDate = sdf.format(myCalendar.time) - - - val myFormat2 = "EEE, d MMM yyyy" - val sdf2 = SimpleDateFormat(myFormat2, Locale.US) - dateEdt.setText(sdf2.format(myCalendar.time)) - - timeInptLay.visibility = View.VISIBLE - } -} diff --git a/app/src/main/java/com/codingblocks/todo/TaskAdapter.kt b/app/src/main/java/com/codingblocks/todo/TaskAdapter.kt deleted file mode 100644 index 59d2ca9..0000000 --- a/app/src/main/java/com/codingblocks/todo/TaskAdapter.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.codingblocks.todo - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.synthetic.main.row_task.view.* -import java.util.* - -class TaskAdapter(var mArrayList: ArrayList) : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskViewHolder { - val mView = LayoutInflater.from(parent.context).inflate(R.layout.row_task, parent, false) - return TaskViewHolder(mView) - } - - override fun getItemCount(): Int = mArrayList.size - - override fun onBindViewHolder(holder: TaskViewHolder, position: Int) { - holder.bind(mArrayList[position]) - } - - override fun getItemId(position: Int): Long { - return mArrayList[position].id - } - - /** - * Set new data list - * */ - fun setList(mArrayList: ArrayList) { - this.mArrayList.clear() - this.mArrayList = mArrayList - notifyDataSetChanged() - } - - -} - -class TaskViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - fun bind(taskModel: TaskModel) { - with(itemView) { - val androidColors = resources.getIntArray(R.array.random_color) - val randomAndroidColor = androidColors[Random().nextInt(androidColors.size)] - viewColorTag.setBackgroundColor(randomAndroidColor) - txtShowTitle.text = taskModel.title - txtShowTask.text = taskModel.task - txtShowCategory.text = taskModel.category - } - } - -} - diff --git a/app/src/main/java/com/codingblocks/todo/TaskDao.kt b/app/src/main/java/com/codingblocks/todo/TaskDao.kt deleted file mode 100644 index 960a6c6..0000000 --- a/app/src/main/java/com/codingblocks/todo/TaskDao.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.codingblocks.todo - -import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.Query - -@Dao -interface TaskDao { - @Insert() - fun insertTask(task: TaskModel): Long - - @Query("UPDATE Task SET finish = 1 WHERE id = :tid") - fun finishTask(tid: Long) - - @Query("DELETE FROM Task WHERE id = :tid") - fun deleleTask(tid: Long) - - @Query("Select * FROM TASK WHERE finish = :finish") - fun getTask(finish: Int): LiveData> - - -} \ No newline at end of file diff --git a/app/src/main/java/com/codingblocks/todo/TaskModel.kt b/app/src/main/java/com/codingblocks/todo/TaskModel.kt deleted file mode 100644 index 3c7aceb..0000000 --- a/app/src/main/java/com/codingblocks/todo/TaskModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codingblocks.todo - -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "Task") -class TaskModel( - var title: String, - var task: String, - var category: String, - var date: String? = null, - var time: String? = null, - var finish: Int = TASK_IS_NOT_FINISH, - @PrimaryKey(autoGenerate = true) - var id: Long = 0 - -) \ No newline at end of file diff --git a/app/src/main/java/com/example/todoapp/AppDatabase.kt b/app/src/main/java/com/example/todoapp/AppDatabase.kt new file mode 100644 index 0000000..574b168 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/AppDatabase.kt @@ -0,0 +1,36 @@ +package com.example.todoapp + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + + +@Database(entities = [TodoModel::class], version = 1) +abstract class AppDatabase : RoomDatabase() { + abstract fun todoDao(): TodoDao + + + companion object { + // Singleton prevents multiple instances of database opening at the + // same time. + @Volatile + private var INSTANCE: AppDatabase? = null + + fun getDatabase(context: Context): AppDatabase { + val tempInstance = INSTANCE + if (tempInstance != null) { + return tempInstance + } + synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + DB_NAME + ).build() + INSTANCE = instance + return instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/todoapp/HistoryActivity.kt b/app/src/main/java/com/example/todoapp/HistoryActivity.kt new file mode 100644 index 0000000..4c31fa5 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/HistoryActivity.kt @@ -0,0 +1,12 @@ +package com.example.todoapp + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle + +class HistoryActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_history) + } +} diff --git a/app/src/main/java/com/example/todoapp/MainActivity.kt b/app/src/main/java/com/example/todoapp/MainActivity.kt new file mode 100644 index 0000000..19ace7e --- /dev/null +++ b/app/src/main/java/com/example/todoapp/MainActivity.kt @@ -0,0 +1,212 @@ +package com.example.todoapp + +import android.content.Intent +import android.graphics.* +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.SearchView +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + +class MainActivity : AppCompatActivity() { + + val list = arrayListOf() + var adapter = TodoAdapter(list) + + val db by lazy { + AppDatabase.getDatabase(this) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + setSupportActionBar(toolbar) + todoRv.apply { + layoutManager = LinearLayoutManager(this@MainActivity) + adapter = this@MainActivity.adapter + } + + initSwipe() + + db.todoDao().getTask().observe(this, Observer { + if (!it.isNullOrEmpty()) { + list.clear() + list.addAll(it) + adapter.notifyDataSetChanged() + }else{ + list.clear() + adapter.notifyDataSetChanged() + } + }) + + + } + + fun initSwipe() { + val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback( + 0, + ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT + ) { + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean = false + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val position = viewHolder.adapterPosition + + if (direction == ItemTouchHelper.LEFT) { + GlobalScope.launch(Dispatchers.IO) { + db.todoDao().deleteTask(adapter.getItemId(position)) + } + } else if (direction == ItemTouchHelper.RIGHT) { + GlobalScope.launch(Dispatchers.IO) { + db.todoDao().finishTask(adapter.getItemId(position)) + } + } + } + + override fun onChildDraw( + canvas: Canvas, + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + dX: Float, + dY: Float, + actionState: Int, + isCurrentlyActive: Boolean + ) { + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + val itemView = viewHolder.itemView + + val paint = Paint() + val icon: Bitmap + + if (dX > 0) { + + icon = BitmapFactory.decodeResource(resources, R.mipmap.ic_check_white_png) + + paint.color = Color.parseColor("#388E3C") + + canvas.drawRect( + itemView.left.toFloat(), itemView.top.toFloat(), + itemView.left.toFloat() + dX, itemView.bottom.toFloat(), paint + ) + + canvas.drawBitmap( + icon, + itemView.left.toFloat(), + itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - icon.height.toFloat()) / 2, + paint + ) + + + } else { + icon = BitmapFactory.decodeResource(resources, R.mipmap.ic_delete_white_png) + + paint.color = Color.parseColor("#D32F2F") + + canvas.drawRect( + itemView.right.toFloat() + dX, itemView.top.toFloat(), + itemView.right.toFloat(), itemView.bottom.toFloat(), paint + ) + + canvas.drawBitmap( + icon, + itemView.right.toFloat() - icon.width, + itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - icon.height.toFloat()) / 2, + paint + ) + } + viewHolder.itemView.translationX = dX + + + } else { + super.onChildDraw( + canvas, + recyclerView, + viewHolder, + dX, + dY, + actionState, + isCurrentlyActive + ) + } + } + + + } + + val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback) + itemTouchHelper.attachToRecyclerView(todoRv) + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.main_menu, menu) + val item = menu.findItem(R.id.search) + val searchView = item.actionView as SearchView + item.setOnActionExpandListener(object :MenuItem.OnActionExpandListener{ + override fun onMenuItemActionExpand(item: MenuItem?): Boolean { + displayTodo() + return true + } + + override fun onMenuItemActionCollapse(item: MenuItem?): Boolean { + displayTodo() + return true + } + + }) + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{ + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + if(!newText.isNullOrEmpty()){ + displayTodo(newText) + } + return true + } + + }) + + return super.onCreateOptionsMenu(menu) + } + + fun displayTodo(newText: String = "") { + db.todoDao().getTask().observe(this, Observer { + if(it.isNotEmpty()){ + list.clear() + list.addAll( + it.filter { todo -> + todo.title.contains(newText,true) + } + ) + adapter.notifyDataSetChanged() + } + }) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.history -> { + startActivity(Intent(this, HistoryActivity::class.java)) + } + } + return super.onOptionsItemSelected(item) + } + + fun openNewTask(view: View) { + startActivity(Intent(this, TaskActivity::class.java)) + } +} diff --git a/app/src/main/java/com/example/todoapp/TaskActivity.kt b/app/src/main/java/com/example/todoapp/TaskActivity.kt new file mode 100644 index 0000000..1286958 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/TaskActivity.kt @@ -0,0 +1,155 @@ +package com.example.todoapp + +import android.app.DatePickerDialog +import android.app.TimePickerDialog +import android.os.Bundle +import android.view.View +import android.widget.ArrayAdapter +import android.widget.DatePicker +import android.widget.TimePicker +import androidx.appcompat.app.AppCompatActivity +import androidx.room.Room +import kotlinx.android.synthetic.main.activity_task.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.text.SimpleDateFormat +import java.util.* + +const val DB_NAME = "todo.db" + +class TaskActivity : AppCompatActivity(), View.OnClickListener { + + lateinit var myCalendar: Calendar + + lateinit var dateSetListener: DatePickerDialog.OnDateSetListener + lateinit var timeSetListener: TimePickerDialog.OnTimeSetListener + + var finalDate = 0L + var finalTime = 0L + + + private val labels = arrayListOf("Personal", "Business", "Insurance", "Shopping", "Banking") + + + val db by lazy { + AppDatabase.getDatabase(this) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_task) + + dateEdt.setOnClickListener(this) + timeEdt.setOnClickListener(this) + saveBtn.setOnClickListener(this) + + + setUpSpinner() + } + + private fun setUpSpinner() { + val adapter = + ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, labels) + + labels.sort() + + spinnerCategory.adapter = adapter + } + + override fun onClick(v: View) { + when (v.id) { + R.id.dateEdt -> { + setListener() + } + R.id.timeEdt -> { + setTimeListener() + } + R.id.saveBtn -> { + saveTodo() + } + } + + } + + private fun saveTodo() { + val category = spinnerCategory.selectedItem.toString() + val title = titleInpLay.editText?.text.toString() + val description = taskInpLay.editText?.text.toString() + + GlobalScope.launch(Dispatchers.Main) { + val id = withContext(Dispatchers.IO) { + return@withContext db.todoDao().insertTask( + TodoModel( + title, + description, + category, + finalDate, + finalTime + ) + ) + } + finish() + } + + } + + private fun setTimeListener() { + myCalendar = Calendar.getInstance() + + timeSetListener = + TimePickerDialog.OnTimeSetListener() { _: TimePicker, hourOfDay: Int, min: Int -> + myCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay) + myCalendar.set(Calendar.MINUTE, min) + updateTime() + } + + val timePickerDialog = TimePickerDialog( + this, timeSetListener, myCalendar.get(Calendar.HOUR_OF_DAY), + myCalendar.get(Calendar.MINUTE), false + ) + timePickerDialog.show() + } + + private fun updateTime() { + //Mon, 5 Jan 2020 + val myformat = "h:mm a" + val sdf = SimpleDateFormat(myformat) + finalTime = myCalendar.time.time + timeEdt.setText(sdf.format(myCalendar.time)) + + } + + private fun setListener() { + myCalendar = Calendar.getInstance() + + dateSetListener = + DatePickerDialog.OnDateSetListener { _: DatePicker, year: Int, month: Int, dayOfMonth: Int -> + myCalendar.set(Calendar.YEAR, year) + myCalendar.set(Calendar.MONTH, month) + myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth) + updateDate() + + } + + val datePickerDialog = DatePickerDialog( + this, dateSetListener, myCalendar.get(Calendar.YEAR), + myCalendar.get(Calendar.MONTH), myCalendar.get(Calendar.DAY_OF_MONTH) + ) + datePickerDialog.datePicker.minDate = System.currentTimeMillis() + datePickerDialog.show() + } + + private fun updateDate() { + //Mon, 5 Jan 2020 + val myformat = "EEE, d MMM yyyy" + val sdf = SimpleDateFormat(myformat) + finalDate = myCalendar.time.time + dateEdt.setText(sdf.format(myCalendar.time)) + + timeInptLay.visibility = View.VISIBLE + + } + +} diff --git a/app/src/main/java/com/example/todoapp/TodoAdapter.kt b/app/src/main/java/com/example/todoapp/TodoAdapter.kt new file mode 100644 index 0000000..d69c739 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/TodoAdapter.kt @@ -0,0 +1,65 @@ +package com.example.todoapp + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.activity_task.* +import kotlinx.android.synthetic.main.item_todo.view.* +import java.text.SimpleDateFormat +import java.util.* + +class TodoAdapter(val list: List) : RecyclerView.Adapter() { + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder { + return TodoViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_todo, parent, false) + ) + } + + override fun getItemCount() = list.size + + override fun onBindViewHolder(holder: TodoViewHolder, position: Int) { + holder.bind(list[position]) + } + + override fun getItemId(position: Int): Long { + return list[position].id + } + + class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + fun bind(todoModel: TodoModel) { + with(itemView) { + val colors = resources.getIntArray(R.array.random_color) + val randomColor = colors[Random().nextInt(colors.size)] + viewColorTag.setBackgroundColor(randomColor) + txtShowTitle.text = todoModel.title + txtShowTask.text = todoModel.description + txtShowCategory.text = todoModel.category + updateTime(todoModel.time) + updateDate(todoModel.date) + + } + } + private fun updateTime(time: Long) { + //Mon, 5 Jan 2020 + val myformat = "h:mm a" + val sdf = SimpleDateFormat(myformat) + itemView.txtShowTime.text = sdf.format(Date(time)) + + } + + private fun updateDate(time: Long) { + //Mon, 5 Jan 2020 + val myformat = "EEE, d MMM yyyy" + val sdf = SimpleDateFormat(myformat) + itemView.txtShowDate.text = sdf.format(Date(time)) + + } + } + +} + + diff --git a/app/src/main/java/com/example/todoapp/TodoDao.kt b/app/src/main/java/com/example/todoapp/TodoDao.kt new file mode 100644 index 0000000..2478406 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/TodoDao.kt @@ -0,0 +1,22 @@ +package com.example.todoapp + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query + +@Dao +interface TodoDao { + + @Insert() + suspend fun insertTask(todoModel: TodoModel):Long + + @Query("Select * from TodoModel where isFinished == 0") + fun getTask():LiveData> + + @Query("Update TodoModel Set isFinished = 1 where id=:uid") + fun finishTask(uid:Long) + + @Query("Delete from TodoModel where id=:uid") + fun deleteTask(uid:Long) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/todoapp/TodoModel.kt b/app/src/main/java/com/example/todoapp/TodoModel.kt new file mode 100644 index 0000000..486d7e2 --- /dev/null +++ b/app/src/main/java/com/example/todoapp/TodoModel.kt @@ -0,0 +1,16 @@ +package com.example.todoapp + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class TodoModel( + var title:String, + var description:String, + var category: String, + var date:Long, + var time:Long, + var isFinished : Int = 0, + @PrimaryKey(autoGenerate = true) + var id:Long = 0 +) \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml index 7f5ee5b..1fd6752 100644 --- a/app/src/main/res/layout/activity_history.xml +++ b/app/src/main/res/layout/activity_history.xml @@ -4,59 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#f2f2f2"> - - - - - - - - - - - + tools:context=".HistoryActivity"> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 34e5581..f20e335 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,71 +1,36 @@ - + tools:context=".MainActivity"> - - - - - - - + + android:layout_below="@+id/toolbar" + android:id="@+id/todoRv" + tools:itemCount="3" + android:padding="8dp" + tools:listitem="@layout/item_todo" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + android:layout_height="wrap_content"/> + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_new_task.xml b/app/src/main/res/layout/activity_task.xml similarity index 92% rename from app/src/main/res/layout/activity_new_task.xml rename to app/src/main/res/layout/activity_task.xml index b8edfd3..3748fc1 100644 --- a/app/src/main/res/layout/activity_new_task.xml +++ b/app/src/main/res/layout/activity_task.xml @@ -5,15 +5,13 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".NewTaskActivity"> + tools:context=".TaskActivity"> + android:theme="@style/AppTheme.AppBarOverlay"> @@ -66,6 +66,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="16dp" + app:hintTextColor="@color/colorAccent" + app:boxStrokeColor="@color/colorAccent" android:layout_marginEnd="16dp" android:id="@+id/taskInpLay" android:layout_marginBottom="16dp"> @@ -94,6 +96,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="16dp" + app:hintTextColor="@color/colorAccent" + app:boxStrokeColor="@color/colorAccent" android:layout_marginEnd="16dp" android:layout_marginBottom="16dp"> @@ -118,6 +122,8 @@ android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" + app:hintTextColor="@color/colorAccent" + app:boxStrokeColor="@color/colorAccent" android:visibility="gone" android:id="@+id/timeInptLay" android:layout_marginBottom="16dp"> @@ -166,6 +172,7 @@ + android:textSize="12sp" + android:visibility="visible" /> + android:visibility="visible" /> + android:textSize="12sp" + android:visibility="visible" /> + android:visibility="visible" /> diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index e7dbdec..c27637f 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -2,16 +2,13 @@ - + app:showAsAction="never"/> - + app:showAsAction="ifRoom|collapseActionView"/> \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 3b973b1..2e30014 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,6 +7,7 @@ #388E3C #D32F2F + #e84e40 #ec407a diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml deleted file mode 100644 index 92be463..0000000 --- a/app/src/main/res/values/dimens.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 16dp - \ 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 715802e..53db4d4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,3 @@ - Todo - No task to show + TodoApp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 323c3e7..b11ee25 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -5,12 +5,11 @@ @color/colorPrimary @color/colorPrimaryDark - @color/colorAccent + @color/colorAccent @style/Widget.MaterialComponents.TextInputLayout.OutlinedBox