From 20f39d2501155027c827bc32ccd11514c1610010 Mon Sep 17 00:00:00 2001 From: Insaf Date: Thu, 16 Dec 2021 16:59:38 +0300 Subject: [PATCH 1/2] template --- app/build.gradle | 18 +++++++++- app/src/main/AndroidManifest.xml | 2 +- .../java/com/itis/androidlabproject/App.kt | 33 +++++++++++++++++ .../androidlabproject/adapter/TodoAdapter.kt | 20 +++++++++++ .../androidlabproject/adapter/TodoHolder.kt | 35 +++++++++++++++++++ .../androidlabproject/data/AppDatabase.kt | 15 ++++++++ .../androidlabproject/data/dao/TodoDao.kt | 34 ++++++++++++++++++ .../extentions/ActivityExt.kt | 9 +++++ .../fragments/TodoDetailsFragment.kt | 31 ++++++++++++++++ .../fragments/TodoListFragment.kt | 26 ++++++++++++++ .../com/itis/androidlabproject/models/Todo.kt | 20 +++++++++++ .../{ => view}/MainActivity.kt | 7 ++-- .../androidlabproject/view/MainViewModel.kt | 14 ++++++++ app/src/main/res/drawable-v24/done.xml | 9 +++++ app/src/main/res/layout/activity_main.xml | 2 +- .../main/res/layout/fragment_details_todo.xml | 14 ++++++++ .../main/res/layout/fragment_todo_list.xml | 14 ++++++++ app/src/main/res/layout/todo_list_item.xml | 7 ++++ app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 4 ++- build.gradle | 4 +-- 21 files changed, 310 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/itis/androidlabproject/App.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/extentions/ActivityExt.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/models/Todo.kt rename app/src/main/java/com/itis/androidlabproject/{ => view}/MainActivity.kt (77%) create mode 100644 app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt create mode 100644 app/src/main/res/drawable-v24/done.xml create mode 100644 app/src/main/res/layout/fragment_details_todo.xml create mode 100644 app/src/main/res/layout/fragment_todo_list.xml create mode 100644 app/src/main/res/layout/todo_list_item.xml diff --git a/app/build.gradle b/app/build.gradle index 53c125c..af718c9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-parcelize' + id 'kotlin-kapt' } android { @@ -37,6 +38,21 @@ android { } dependencies { + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + def room_version = "2.4.0" + + implementation "androidx.room:room-runtime:$room_version" + kapt "androidx.room:room-compiler:$room_version" + + // optional - Kotlin Extensions and Coroutines support for Room + implementation "androidx.room:room-ktx:$room_version" + + def lifecycle_version = "2.4.0" + + // LiveData + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + // Annotation processor + kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.0' @@ -44,7 +60,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.2' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' - implementation "androidx.media:media:1.2.0" + implementation "androidx.media:media:1.4.3" testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 69ebd0a..87de077 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ android:supportsRtl="true" android:theme="@style/Theme.AndroidLabProject"> diff --git a/app/src/main/java/com/itis/androidlabproject/App.kt b/app/src/main/java/com/itis/androidlabproject/App.kt new file mode 100644 index 0000000..3fa12ea --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/App.kt @@ -0,0 +1,33 @@ +package com.itis.androidlabproject + +import android.app.Application +import androidx.room.Room +import com.itis.androidlabproject.data.AppDatabase +import com.itis.androidlabproject.data.dao.TodoDao + +class App : Application() { + lateinit var database: AppDatabase + lateinit var todoDao: TodoDao + + companion object { + private lateinit var instance: App + + fun getInstance(): App { + return instance + } + } + + override fun onCreate() { + super.onCreate() + instance = this + database = Room.databaseBuilder( + applicationContext, + AppDatabase::class.java, + "app-db" + ).run { + allowMainThreadQueries() + build() + } + todoDao = database.todoDao() + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt b/app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt new file mode 100644 index 0000000..336b70a --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt @@ -0,0 +1,20 @@ +package com.itis.androidlabproject.adapter + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.itis.androidlabproject.models.Todo + +class TodoAdapter( + private val itemList: List, + private val itemClick: (Int) -> (Unit) +) : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoHolder { + return TodoHolder.create(parent, itemClick) + } + + override fun onBindViewHolder(holder: TodoHolder, position: Int) { + holder.bind(itemList[position]) + } + + override fun getItemCount(): Int = itemList.size +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt b/app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt new file mode 100644 index 0000000..c297dc3 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt @@ -0,0 +1,35 @@ +package com.itis.androidlabproject.adapter + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.itis.androidlabproject.databinding.TodoListItemBinding +import com.itis.androidlabproject.models.Todo + +class TodoHolder( + private val binding: TodoListItemBinding, + private val itemClick: (Int) -> (Unit) +) : RecyclerView.ViewHolder(binding.root) { + private var itemToShow: Todo? = null + + fun bind(todo: Todo) { + itemToShow = todo + with(binding) { + + } + } + + companion object { + fun create( + parent: ViewGroup, + itemClick: (Int) -> Unit + ) = TodoHolder( + TodoListItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + itemClick + ) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt b/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt new file mode 100644 index 0000000..b03c0e1 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt @@ -0,0 +1,15 @@ +package com.itis.androidlabproject.data + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.itis.androidlabproject.data.dao.TodoDao +import com.itis.androidlabproject.models.Todo + +@Database( + entities = arrayOf(Todo::class), + version = 1, + exportSchema = false +) +abstract class AppDatabase : RoomDatabase() { + abstract fun todoDao(): TodoDao +} diff --git a/app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt b/app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt new file mode 100644 index 0000000..640065b --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt @@ -0,0 +1,34 @@ +package com.itis.androidlabproject.data.dao + +import androidx.lifecycle.LiveData +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.itis.androidlabproject.models.Todo + +interface TodoDao { + @Query("SELECT * FROM Todo") + fun getAll(): List + + @Query("SELECT * FROM Todo") + fun getAllLiveData(): LiveData> + + @Query("SELECT * FROM Todo WHERE id IN (:todoIds)") + fun loadAllByIds(todoIds: IntArray): List + + @Query("SELECT * FROM Todo WHERE title = :title LIMIT 1") + fun findByName(title: String): Todo + + @Query("SELECT * FROM Todo WHERE id = :id LIMIT 1") + fun findById(id: Int): Todo + + @Insert + fun insert(todo: Todo) + + @Update + fun update(todo: Todo) + + @Delete + fun delete(todo: Todo) +} diff --git a/app/src/main/java/com/itis/androidlabproject/extentions/ActivityExt.kt b/app/src/main/java/com/itis/androidlabproject/extentions/ActivityExt.kt new file mode 100644 index 0000000..86b200e --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/extentions/ActivityExt.kt @@ -0,0 +1,9 @@ +package com.itis.androidlabproject.extentions + +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.NavController +import androidx.navigation.fragment.NavHostFragment + +fun AppCompatActivity.findController (id: Int) : NavController { + return (supportFragmentManager.findFragmentById(id) as NavHostFragment).navController +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt new file mode 100644 index 0000000..a6d0226 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt @@ -0,0 +1,31 @@ +package com.itis.androidlabproject.fragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.itis.androidlabproject.R +import com.itis.androidlabproject.databinding.FragmentDetailsTodoBinding + +class TodoDetailsFragment : Fragment() { + private var binding: FragmentDetailsTodoBinding? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentDetailsTodoBinding.inflate(inflater, container, false) + return binding?.root + } + + override fun onDestroy() { + super.onDestroy() + binding = null + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt new file mode 100644 index 0000000..ec0c059 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt @@ -0,0 +1,26 @@ +package com.itis.androidlabproject.fragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.itis.androidlabproject.R +import com.itis.androidlabproject.databinding.FragmentTodoListBinding + +class TodoListFragment : Fragment() { + private var binding: FragmentTodoListBinding? = null + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentTodoListBinding.bind(view) + } + + override fun onDestroy() { + super.onDestroy() + binding = null + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/models/Todo.kt b/app/src/main/java/com/itis/androidlabproject/models/Todo.kt new file mode 100644 index 0000000..5354a17 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/models/Todo.kt @@ -0,0 +1,20 @@ +package com.itis.androidlabproject.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +class Todo( + @PrimaryKey(autoGenerate = true) + var id: Int?, + + @ColumnInfo(name = "title") + var title: String?, + + @ColumnInfo(name = "description") + var description: String?, + + @ColumnInfo(name = "timestamp") + var timestamp: Long? +) diff --git a/app/src/main/java/com/itis/androidlabproject/MainActivity.kt b/app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt similarity index 77% rename from app/src/main/java/com/itis/androidlabproject/MainActivity.kt rename to app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt index d85e6eb..63b41fa 100644 --- a/app/src/main/java/com/itis/androidlabproject/MainActivity.kt +++ b/app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt @@ -1,11 +1,12 @@ -package com.itis.androidlabproject +package com.itis.androidlabproject.view -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.itis.androidlabproject.R class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt b/app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt new file mode 100644 index 0000000..89b2de6 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt @@ -0,0 +1,14 @@ +package com.itis.androidlabproject.view + +import androidx.lifecycle.LiveData +import androidx.lifecycle.ViewModel +import com.itis.androidlabproject.App +import com.itis.androidlabproject.models.Todo + +class MainViewModel : ViewModel() { + val liveData: LiveData> + + init { + liveData = App.getInstance().todoDao.getAllLiveData() + } +} diff --git a/app/src/main/res/drawable-v24/done.xml b/app/src/main/res/drawable-v24/done.xml new file mode 100644 index 0000000..f5c43ba --- /dev/null +++ b/app/src/main/res/drawable-v24/done.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4fa45b0..a70bdb9 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".view.MainActivity"> + + + + + + diff --git a/app/src/main/res/layout/fragment_todo_list.xml b/app/src/main/res/layout/fragment_todo_list.xml new file mode 100644 index 0000000..37c43c0 --- /dev/null +++ b/app/src/main/res/layout/fragment_todo_list.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/todo_list_item.xml b/app/src/main/res/layout/todo_list_item.xml new file mode 100644 index 0000000..1d67208 --- /dev/null +++ b/app/src/main/res/layout/todo_list_item.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index ca1931b..3e48526 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #FF018786 #FF000000 #FFFFFFFF + #838383 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f931ae8..0d94b3b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ AndroidLabProject - \ No newline at end of file + + Hello blank fragment + diff --git a/build.gradle b/build.gradle index 12f1d4c..00c138b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.0.2" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.30" + classpath 'com.android.tools.build:gradle:7.0.4' + classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From a2be5dc3afacd990bea0eb42e3081e68b5c6bbc6 Mon Sep 17 00:00:00 2001 From: Insaf Date: Tue, 28 Dec 2021 14:12:12 +0300 Subject: [PATCH 2/2] hw-9-todo without coroutines --- app/build.gradle | 25 +- app/src/main/AndroidManifest.xml | 1 + .../java/com/itis/androidlabproject/App.kt | 6 +- .../androidlabproject/adapter/TaskAdapter.kt | 46 +++ .../androidlabproject/adapter/TaskHolder.kt | 67 +++++ .../androidlabproject/adapter/TodoAdapter.kt | 20 -- .../androidlabproject/adapter/TodoHolder.kt | 35 --- .../callbacks/TaskDiffItemCallback.kt | 57 ++++ .../androidlabproject/data/AppDatabase.kt | 37 ++- .../androidlabproject/data/dao/TaskDao.kt | 40 +++ .../androidlabproject/data/dao/TodoDao.kt | 34 --- .../fragments/TaskDetailsFragment.kt | 274 ++++++++++++++++++ .../fragments/TaskListFragment.kt | 125 ++++++++ .../fragments/TodoDetailsFragment.kt | 31 -- .../fragments/TodoListFragment.kt | 26 -- .../date_picker/DatePickerFragment.kt | 35 +++ .../item_decorator/SpaceItemDecorator.kt | 51 ++++ .../androidlabproject/models/DateConverter.kt | 18 ++ .../models/DateToStringConverter.kt | 14 + .../models/{Todo.kt => Task.kt} | 15 +- .../androidlabproject/view/MainActivity.kt | 22 +- .../androidlabproject/view/MainViewModel.kt | 14 - app/src/main/res/anim/enter_from_left.xml | 8 + app/src/main/res/anim/enter_from_right.xml | 8 + app/src/main/res/anim/exit_to_left.xml | 8 + app/src/main/res/anim/exit_to_right.xml | 8 + app/src/main/res/drawable/delete.xml | 10 + .../drawable/ic_baseline_arrow_back_24.xml | 11 + app/src/main/res/layout/activity_main.xml | 18 +- .../main/res/layout/fragment_details_task.xml | 118 ++++++++ .../main/res/layout/fragment_details_todo.xml | 14 - .../main/res/layout/fragment_task_list.xml | 59 ++++ .../main/res/layout/fragment_todo_list.xml | 14 - app/src/main/res/layout/task_list_item.xml | 43 +++ app/src/main/res/layout/todo_list_item.xml | 7 - app/src/main/res/menu/menu_main.xml | 9 + app/src/main/res/menu/menu_task.xml | 9 + app/src/main/res/navigation/nav_graph.xml | 26 ++ app/src/main/res/values/strings.xml | 10 + 39 files changed, 1142 insertions(+), 231 deletions(-) create mode 100644 app/src/main/java/com/itis/androidlabproject/adapter/TaskAdapter.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/adapter/TaskHolder.kt delete mode 100644 app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt delete mode 100644 app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/callbacks/TaskDiffItemCallback.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/data/dao/TaskDao.kt delete mode 100644 app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/TaskDetailsFragment.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/TaskListFragment.kt delete mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt delete mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/fragments/date_picker/DatePickerFragment.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/item_decorator/SpaceItemDecorator.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/models/DateConverter.kt create mode 100644 app/src/main/java/com/itis/androidlabproject/models/DateToStringConverter.kt rename app/src/main/java/com/itis/androidlabproject/models/{Todo.kt => Task.kt} (57%) delete mode 100644 app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt create mode 100644 app/src/main/res/anim/enter_from_left.xml create mode 100644 app/src/main/res/anim/enter_from_right.xml create mode 100644 app/src/main/res/anim/exit_to_left.xml create mode 100644 app/src/main/res/anim/exit_to_right.xml create mode 100644 app/src/main/res/drawable/delete.xml create mode 100644 app/src/main/res/drawable/ic_baseline_arrow_back_24.xml create mode 100644 app/src/main/res/layout/fragment_details_task.xml delete mode 100644 app/src/main/res/layout/fragment_details_todo.xml create mode 100644 app/src/main/res/layout/fragment_task_list.xml delete mode 100644 app/src/main/res/layout/fragment_todo_list.xml create mode 100644 app/src/main/res/layout/task_list_item.xml delete mode 100644 app/src/main/res/layout/todo_list_item.xml create mode 100644 app/src/main/res/menu/menu_main.xml create mode 100644 app/src/main/res/menu/menu_task.xml create mode 100644 app/src/main/res/navigation/nav_graph.xml diff --git a/app/build.gradle b/app/build.gradle index af718c9..5928442 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,30 +38,23 @@ android { } dependencies { - implementation 'androidx.legacy:legacy-support-v4:1.0.0' def room_version = "2.4.0" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" - // optional - Kotlin Extensions and Coroutines support for Room - implementation "androidx.room:room-ktx:$room_version" - - def lifecycle_version = "2.4.0" - - // LiveData - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" - // Annotation processor - kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" - - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.2' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' - implementation "androidx.media:media:1.4.3" - testImplementation 'junit:junit:4.+' + + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + implementation('androidx.fragment:fragment-ktx:1.4.0-alpha02') + implementation 'com.google.android.gms:play-services-location:18.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 87de077..1718214 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + (Unit), + private val actionDelete: (Int) -> (Unit) +) : ListAdapter(TaskDiffItemCallback()) { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): TaskHolder = TaskHolder.create(parent, actionChoose, actionDelete) + + override fun onBindViewHolder( + holder: TaskHolder, + position: Int) = holder.bind(getItem(position)) + + override fun onBindViewHolder( + holder: TaskHolder, + position: Int, + payloads: MutableList + ) { + if (payloads.isEmpty()) { + super.onBindViewHolder(holder, position, payloads) + } else { + payloads.last().takeIf { + it is Bundle + }?.let { + holder.updateFields(it as Bundle) + } + } + } + + override fun submitList(list: MutableList?) { + super.submitList( + if (list == null) null + else ArrayList(list) + ) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/TaskHolder.kt b/app/src/main/java/com/itis/androidlabproject/adapter/TaskHolder.kt new file mode 100644 index 0000000..b5af9f2 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/adapter/TaskHolder.kt @@ -0,0 +1,67 @@ +package com.itis.androidlabproject.adapter + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.itis.androidlabproject.databinding.TaskListItemBinding +import com.itis.androidlabproject.models.DateToStringConverter.convertDateToString +import com.itis.androidlabproject.models.Task + +class TaskHolder( + private val binding: TaskListItemBinding, + private val actionChoose: (Int) -> (Unit), + private val actionDelete: (Int) -> (Unit) +) : RecyclerView.ViewHolder(binding.root) { + private var task: Task? = null + + fun bind(item: Task) { + this.task = item + with(binding) { + tvTaskTitle.text = item.title + tvTaskDate.text = convertDateToString(item.date) + + itemView.setOnClickListener { + actionChoose(item.id) + } + ivDelete.setOnClickListener { + actionDelete(item.id) + } + } + } + + fun updateFields(bundle: Bundle?) { + bundle?.run { + getString("TITLE")?.also { + updateTitle(it) + } + getString("DATE")?.also { + updateDate(it) + } + } + } + + private fun updateTitle(title: String) { + binding.tvTaskTitle.text = title + } + + private fun updateDate(date: String) { + binding.tvTaskDate.text = date + } + + companion object { + fun create( + parent: ViewGroup, + actionChoose: (Int) -> Unit, + actionDelete: (Int) -> Unit + ) = TaskHolder( + TaskListItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + actionChoose, + actionDelete + ) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt b/app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt deleted file mode 100644 index 336b70a..0000000 --- a/app/src/main/java/com/itis/androidlabproject/adapter/TodoAdapter.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.itis.androidlabproject.adapter - -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import com.itis.androidlabproject.models.Todo - -class TodoAdapter( - private val itemList: List, - private val itemClick: (Int) -> (Unit) -) : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoHolder { - return TodoHolder.create(parent, itemClick) - } - - override fun onBindViewHolder(holder: TodoHolder, position: Int) { - holder.bind(itemList[position]) - } - - override fun getItemCount(): Int = itemList.size -} diff --git a/app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt b/app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt deleted file mode 100644 index c297dc3..0000000 --- a/app/src/main/java/com/itis/androidlabproject/adapter/TodoHolder.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.itis.androidlabproject.adapter - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import com.itis.androidlabproject.databinding.TodoListItemBinding -import com.itis.androidlabproject.models.Todo - -class TodoHolder( - private val binding: TodoListItemBinding, - private val itemClick: (Int) -> (Unit) -) : RecyclerView.ViewHolder(binding.root) { - private var itemToShow: Todo? = null - - fun bind(todo: Todo) { - itemToShow = todo - with(binding) { - - } - } - - companion object { - fun create( - parent: ViewGroup, - itemClick: (Int) -> Unit - ) = TodoHolder( - TodoListItemBinding.inflate( - LayoutInflater.from(parent.context), - parent, - false - ), - itemClick - ) - } -} diff --git a/app/src/main/java/com/itis/androidlabproject/callbacks/TaskDiffItemCallback.kt b/app/src/main/java/com/itis/androidlabproject/callbacks/TaskDiffItemCallback.kt new file mode 100644 index 0000000..87a20f5 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/callbacks/TaskDiffItemCallback.kt @@ -0,0 +1,57 @@ +package com.itis.androidlabproject.callbacks + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.core.os.bundleOf +import androidx.recyclerview.widget.DiffUtil +import com.itis.androidlabproject.models.DateToStringConverter +import com.itis.androidlabproject.models.Task + +class TaskDiffItemCallback : DiffUtil.ItemCallback(){ + override fun areItemsTheSame( + oldItem: Task, + newItem: Task + ): Boolean = oldItem.id == newItem.id + + override fun areContentsTheSame( + oldItem: Task, + newItem: Task + ): Boolean { + return oldItem.equals(newItem) + } + + override fun getChangePayload( + oldItem: Task, + newItem: Task + ): Any? { + val bundle = Bundle().apply { + if (oldItem.title != newItem.title) { + putString("TITLE", newItem.title) + } + + if (oldItem.description != newItem.description) { + putString("DESCRIPTION", newItem.description) + } + + if (oldItem.date != newItem.date) { + putString("DATE", DateToStringConverter.convertDateToString(newItem.date)) + } + + if (oldItem.latitude != newItem.latitude) { + newItem.latitude?.let { + putDouble("LATITUDE", it) + } + } + + if (oldItem.longitude != newItem.longitude) { + newItem.longitude?.let { + putDouble("LONGITUDE", it) + } + } + } + + + if (bundle.isEmpty) return null + return bundle + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt b/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt index b03c0e1..add815f 100644 --- a/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt +++ b/app/src/main/java/com/itis/androidlabproject/data/AppDatabase.kt @@ -1,15 +1,44 @@ package com.itis.androidlabproject.data +import android.content.Context import androidx.room.Database +import androidx.room.Room import androidx.room.RoomDatabase -import com.itis.androidlabproject.data.dao.TodoDao -import com.itis.androidlabproject.models.Todo +import androidx.room.TypeConverters +import com.itis.androidlabproject.data.dao.TaskDao +import com.itis.androidlabproject.models.DateConverter +import com.itis.androidlabproject.models.Task @Database( - entities = arrayOf(Todo::class), + entities = [Task::class], version = 1, exportSchema = false ) +@TypeConverters(DateConverter::class) abstract class AppDatabase : RoomDatabase() { - abstract fun todoDao(): TodoDao + abstract fun taskDao(): TaskDao + + companion object { + private const val DB_NAME = "task.db" + + @Volatile + private var instance: AppDatabase? = null + private val LOCK = Any() + + operator fun invoke(context: Context?) = Companion.instance ?: synchronized(LOCK) { + buildDatabase(context) + } + + private fun buildDatabase(context: Context) { + instance = Room.databaseBuilder( + context, + AppDatabase::class.java, + DB_NAME + ).run { + allowMainThreadQueries() + fallbackToDestructiveMigration() + build() + } + } + } } diff --git a/app/src/main/java/com/itis/androidlabproject/data/dao/TaskDao.kt b/app/src/main/java/com/itis/androidlabproject/data/dao/TaskDao.kt new file mode 100644 index 0000000..3c1934a --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/data/dao/TaskDao.kt @@ -0,0 +1,40 @@ +package com.itis.androidlabproject.data.dao + +import androidx.lifecycle.LiveData +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.itis.androidlabproject.models.Task + +interface TaskDao { + @Query("SELECT * FROM Task") + fun getAll(): List + + @Query("SELECT * FROM Task") + fun getAllLiveData(): LiveData> + + @Query("SELECT * FROM Task WHERE id IN (:todoIds)") + fun loadAllByIds(todoIds: IntArray): List + + @Query("SELECT * FROM Task WHERE title = :title LIMIT 1") + fun findByName(title: String): Task + + @Query("SELECT * FROM Task WHERE id = :id LIMIT 1") + fun findById(id: Int): Task + + @Insert + fun insert(task: Task) + + @Update + fun update(task: Task) + + @Delete + fun delete(task: Task) + + @Query("DELETE FROM Task") + fun deleteAllTasks() + + @Query("DELETE FROM task WHERE id=:id") + fun deleteTaskById(id: Int) +} diff --git a/app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt b/app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt deleted file mode 100644 index 640065b..0000000 --- a/app/src/main/java/com/itis/androidlabproject/data/dao/TodoDao.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.itis.androidlabproject.data.dao - -import androidx.lifecycle.LiveData -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.Query -import androidx.room.Update -import com.itis.androidlabproject.models.Todo - -interface TodoDao { - @Query("SELECT * FROM Todo") - fun getAll(): List - - @Query("SELECT * FROM Todo") - fun getAllLiveData(): LiveData> - - @Query("SELECT * FROM Todo WHERE id IN (:todoIds)") - fun loadAllByIds(todoIds: IntArray): List - - @Query("SELECT * FROM Todo WHERE title = :title LIMIT 1") - fun findByName(title: String): Todo - - @Query("SELECT * FROM Todo WHERE id = :id LIMIT 1") - fun findById(id: Int): Todo - - @Insert - fun insert(todo: Todo) - - @Update - fun update(todo: Todo) - - @Delete - fun delete(todo: Todo) -} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/TaskDetailsFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/TaskDetailsFragment.kt new file mode 100644 index 0000000..9beaec5 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragments/TaskDetailsFragment.kt @@ -0,0 +1,274 @@ +package com.itis.androidlabproject.fragments + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.location.LocationManager +import android.os.Bundle +import android.provider.Settings +import android.view.MenuItem +import android.view.View +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.google.android.gms.location.FusedLocationProviderClient +import com.google.android.gms.location.LocationServices +import com.google.android.material.snackbar.Snackbar +import com.itis.androidlabproject.R +import com.itis.androidlabproject.data.AppDatabase +import com.itis.androidlabproject.databinding.FragmentDetailsTaskBinding +import com.itis.androidlabproject.fragments.date_picker.DatePickerFragment +import com.itis.androidlabproject.models.DateToStringConverter +import com.itis.androidlabproject.models.Task +import com.itis.androidlabproject.view.MainActivity +import java.util.* + +class TaskDetailsFragment : Fragment(R.layout.fragment_details_task) { + private var binding: FragmentDetailsTaskBinding? = null + private var database: AppDatabase? = null + private var client: FusedLocationProviderClient? = null + private var calendar: Calendar? = null + private var currentTaskId: Int? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + client = LocationServices.getFusedLocationProviderClient(activity) + } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + binding = FragmentDetailsTaskBinding.bind(view) + database = AppDatabase.invoke(context) as AppDatabase + + binding?.apply { + toolBar.apply { + setNavigationIcon(R.drawable.ic_baseline_arrow_back_24) + setNavigationOnClickListener { + (activity as? MainActivity)?.onBackPressed() + } + setOnMenuItemClickListener { onOptionsItemSelected(it) } + } + + btnChooseDate.setOnClickListener { + showDatePicker() + } + } + + checkIfTaskExists() + setLocation() + } + + private fun setLocation() { + if (checkPermissions() == true) { + getCurrentLocation() + } else { + requestPermissions( + arrayOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + ), REQUEST_CODE + ) + } + } + + private fun checkPermissions(): Boolean? { + activity?.apply { + return (ContextCompat.checkSelfPermission( + this, + Manifest.permission.ACCESS_FINE_LOCATION + ) + == PackageManager.PERMISSION_GRANTED && + ContextCompat.checkSelfPermission( + this, + Manifest.permission.ACCESS_COARSE_LOCATION + ) + == PackageManager.PERMISSION_GRANTED) + } + return null + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + if (requestCode == REQUEST_CODE && grantResults.isNotEmpty() && + grantResults[0] == PackageManager.PERMISSION_GRANTED + ) { + getCurrentLocation() + } else { + returnToTaskListFragment() + } + } + + @SuppressLint("MissingPermission") + private fun getCurrentLocation() { + val locationManager = + activity?.getSystemService(Context.LOCATION_SERVICE) as LocationManager + if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) or + locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) + ) { + if (checkPermissions() == true) { + client?.lastLocation?.addOnCompleteListener { + val location = it.result + if (location != null) { + binding?.etLongitude?.setText(location.longitude.toString()) + binding?.etLatitude?.setText(location.latitude.toString()) + } + } + } + } else { + startActivity( + Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + ) + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.icon_save -> { + saveTask() + true + } + else -> super.onOptionsItemSelected(item) + } + } + + private fun checkIfTaskExists() { + arguments?.getInt("ARG_TASK_ID")?.let { + currentTaskId = it + setTaskEditingView(it) + } + } + + private fun setTaskEditingView(id: Int) { + val task = database?.taskDao()?.findById(id) + binding?.apply { + etTitle.setText(task?.title) + etDesc.setText(task?.description) + task?.date?.let { + calendar = Calendar.getInstance() + calendar?.time = it + tvDate.text = DateToStringConverter.convertDateToString(it) + tvDate.visibility = View.VISIBLE + } + } + } + + private fun showDatePicker() { + calendar = Calendar.getInstance() + val datePickerFragment = DatePickerFragment() + val supportFragmentManager = requireActivity().supportFragmentManager + + supportFragmentManager.setFragmentResultListener( + "REQUEST_KEY", + viewLifecycleOwner + ) { resultKey, bundle -> + if (resultKey == "REQUEST_KEY") { + calendar?.timeInMillis = bundle.getLong("SELECTED_DATE") + setDate(calendar) + } + } + datePickerFragment.show(supportFragmentManager, "DatePickerDialog") + } + + private fun setDate(calendar: Calendar?) { + binding?.apply { + tvDate.text = DateToStringConverter.convertDateToString(calendar?.time) + tvDate.visibility = View.VISIBLE + } + } + + private fun saveTask() { + if (currentTaskId == null && isTaskCorrect()) { + addTask() + } else { + currentTaskId?.let { + updateTask(it) + } + } + returnToTaskListFragment() + } + + private fun addTask() { + binding?.apply { + database?.taskDao()?.insert( + Task( + null, + etTitle.text.toString(), + etDesc.text.toString(), + calendar?.time, + etLongitude.text as? Double, + etLatitude.text as? Double + ) + ) + } + showMessage("Задача сохранена") + returnToTaskListFragment() + } + + private fun updateTask(id: Int) { + val task = database?.taskDao()?.findById(id) + binding?.apply { + if (isTaskCorrect()) { + binding?.run { + task?.let { task -> + task.title = etTitle.text.toString() + task.description = etDesc.text.toString() + calendar?.also { + task.date = it.time + } + database?.taskDao()?.update(task) + showMessage("Задача обновлена") + returnToTaskListFragment() + } + } + } + } + returnToTaskListFragment() + } + + private fun isTaskCorrect(): Boolean { + binding?.run { + if (etTitle.text.toString().isEmpty()) { + showMessage("Нет названия") + return false + } + if (etDesc.text.toString().isEmpty()) { + showMessage("Нет описания") + return false + } + } + return true + } + + + private fun showMessage(message: String) { + Snackbar.make( + requireActivity().findViewById(R.id.container), + message, + Snackbar.LENGTH_LONG + ).show() + } + + private fun returnToTaskListFragment() { + (activity as? MainActivity)?.onBackPressed() + } + + override fun onDestroy() { + super.onDestroy() + binding = null + database = null + + } + + companion object { + private const val REQUEST_CODE = 1 + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/TaskListFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/TaskListFragment.kt new file mode 100644 index 0000000..a18146b --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragments/TaskListFragment.kt @@ -0,0 +1,125 @@ +package com.itis.androidlabproject.fragments + +import android.os.Bundle +import android.view.MenuItem +import android.view.View +import androidx.fragment.app.Fragment +import androidx.navigation.NavOptions +import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.snackbar.Snackbar +import com.itis.androidlabproject.R +import com.itis.androidlabproject.adapter.TaskAdapter +import com.itis.androidlabproject.data.AppDatabase +import com.itis.androidlabproject.databinding.FragmentTaskListBinding +import com.itis.androidlabproject.item_decorator.SpaceItemDecorator +import com.itis.androidlabproject.models.Task + +class TaskListFragment : Fragment(R.layout.fragment_task_list) { + private var binding: FragmentTaskListBinding? = null + private var database: AppDatabase? = null + private var taskAdapter: TaskAdapter? = null + private var tasks: List? = null + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + super.onViewCreated(view, savedInstanceState) + binding = FragmentTaskListBinding.bind(view) + database = AppDatabase.invoke(context) as AppDatabase + taskAdapter = TaskAdapter({showTaskFragment(it)}, {deleteTask(it)}) + + binding?.apply { + toolBar.setOnMenuItemClickListener { + onOptionsItemSelected(it) + } + fabAdd.setOnClickListener { + showTaskFragment(null) + } + rvTasks.run { + adapter = taskAdapter + addItemDecoration( + DividerItemDecoration(context, RecyclerView.VERTICAL) + ) + addItemDecoration( + SpaceItemDecorator(context) + ) + } + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.icon_delete_all -> { + deleteAllTasks() + true + } + else ->super.onOptionsItemSelected(item) + } + } + + private fun deleteAllTasks() { + database?.taskDao()?.deleteAllTasks() + updateTasks() + showMessage("Задачи удалены") + } + + private fun deleteTask(id: Int) { + database?.taskDao()?.deleteTaskById(id) + updateTasks() + showMessage("Задача удалена") + } + + private fun updateTasks() { + tasks = database?.taskDao()?.getAll() + binding?.apply { + if (tasks.isNullOrEmpty()) { + rvTasks.visibility = View.GONE + noTasksAdded.visibility = View.VISIBLE + } else { + rvTasks.visibility = View.VISIBLE + noTasksAdded.visibility = View.GONE + } + } + taskAdapter?.submitList(ArrayList(tasks)) + } + + private fun showTaskFragment(id: Int?) { + var bundle: Bundle? = null + id?.also { + bundle = Bundle().apply { + putInt("ARG_TASK_ID", id) + } + } + val options = NavOptions.Builder() + .setLaunchSingleTop(true) + .setEnterAnim(R.anim.enter_from_right) + .setExitAnim(R.anim.exit_to_left) + .setPopEnterAnim(R.anim.enter_from_left) + .setPopExitAnim(R.anim.exit_to_right) + .build() + + findNavController().navigate( + R.id.action_taskListFragment_to_taskDetailsFragment, + bundle, + options + ) + } + + private fun showMessage(message: String) { + Snackbar.make( + requireActivity().findViewById(R.id.container), + message, + Snackbar.LENGTH_LONG + ).show() + } + + override fun onDestroy() { + super.onDestroy() + binding = null + database = null + taskAdapter = null + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt deleted file mode 100644 index a6d0226..0000000 --- a/app/src/main/java/com/itis/androidlabproject/fragments/TodoDetailsFragment.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.itis.androidlabproject.fragments - -import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.itis.androidlabproject.R -import com.itis.androidlabproject.databinding.FragmentDetailsTodoBinding - -class TodoDetailsFragment : Fragment() { - private var binding: FragmentDetailsTodoBinding? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - binding = FragmentDetailsTodoBinding.inflate(inflater, container, false) - return binding?.root - } - - override fun onDestroy() { - super.onDestroy() - binding = null - } -} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt deleted file mode 100644 index ec0c059..0000000 --- a/app/src/main/java/com/itis/androidlabproject/fragments/TodoListFragment.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.itis.androidlabproject.fragments - -import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.itis.androidlabproject.R -import com.itis.androidlabproject.databinding.FragmentTodoListBinding - -class TodoListFragment : Fragment() { - private var binding: FragmentTodoListBinding? = null - - override fun onViewCreated( - view: View, - savedInstanceState: Bundle? - ) { - super.onViewCreated(view, savedInstanceState) - binding = FragmentTodoListBinding.bind(view) - } - - override fun onDestroy() { - super.onDestroy() - binding = null - } -} diff --git a/app/src/main/java/com/itis/androidlabproject/fragments/date_picker/DatePickerFragment.kt b/app/src/main/java/com/itis/androidlabproject/fragments/date_picker/DatePickerFragment.kt new file mode 100644 index 0000000..d96b647 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/fragments/date_picker/DatePickerFragment.kt @@ -0,0 +1,35 @@ +package com.itis.androidlabproject.fragments.date_picker + +import android.app.DatePickerDialog +import android.app.Dialog +import android.os.Bundle +import android.widget.DatePicker +import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.setFragmentResult +import androidx.fragment.app.Fragment +import java.util.* + +class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener { + private val calendar = Calendar.getInstance() + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + var year = calendar.get(Calendar.YEAR) + var month = calendar.get(Calendar.MONTH) + var dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH) + + return DatePickerDialog(requireActivity(), this, year, month, dayOfMonth) + } + + override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) { + calendar.set(Calendar.YEAR, year) + calendar.set(Calendar.MONTH, month) + calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth) + + val bundle = bundleOf( + "SELECTED_DATE" to calendar.timeInMillis + ) + + this.setFragmentResult("REQUEST_KEY", bundle) + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/item_decorator/SpaceItemDecorator.kt b/app/src/main/java/com/itis/androidlabproject/item_decorator/SpaceItemDecorator.kt new file mode 100644 index 0000000..aeae2a9 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/item_decorator/SpaceItemDecorator.kt @@ -0,0 +1,51 @@ +package com.itis.androidlabproject.item_decorator + +import android.content.Context +import android.graphics.Rect +import android.util.TypedValue +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class SpaceItemDecorator( + context: Context, + spacing: Float = 16f +) : RecyclerView.ItemDecoration() { + + private val spacingPx: Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + spacing, + context.resources.displayMetrics + ).toInt() + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + val spacingMiddle = (spacingPx * 0.25).toInt() + val spacingTopBottom = (spacingPx * 0.5).toInt() + val viewHolder = parent.getChildViewHolder(view) + + val currentPosition = parent.getChildAdapterPosition(view).takeIf { + it != RecyclerView.NO_POSITION + } ?: viewHolder.oldPosition + + when (currentPosition) { + 0 -> { + outRect.top = spacingTopBottom + outRect.bottom = spacingMiddle + } + state.itemCount - 1 -> { + outRect.top = spacingMiddle + outRect.bottom = spacingTopBottom + } + else -> { + outRect.top = spacingMiddle + outRect.bottom = spacingMiddle + } + } + outRect.left = spacingPx + outRect.right = spacingPx + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/models/DateConverter.kt b/app/src/main/java/com/itis/androidlabproject/models/DateConverter.kt new file mode 100644 index 0000000..f6f6441 --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/models/DateConverter.kt @@ -0,0 +1,18 @@ +package com.itis.androidlabproject.models + +import androidx.room.TypeConverter +import java.util.* + +class DateConverter { + @TypeConverter + fun dateToTimestamp(date: Date?): Long? { + return date?.time?.toLong() + } + + @TypeConverter + fun timestampToDate(timestamp: Long?): Date? { + return timestamp?.let { + Date(it) + } + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/models/DateToStringConverter.kt b/app/src/main/java/com/itis/androidlabproject/models/DateToStringConverter.kt new file mode 100644 index 0000000..7270d9a --- /dev/null +++ b/app/src/main/java/com/itis/androidlabproject/models/DateToStringConverter.kt @@ -0,0 +1,14 @@ +package com.itis.androidlabproject.models + +import java.text.SimpleDateFormat +import java.util.* + +object DateToStringConverter { + + fun convertDateToString(date: Date?): String{ + val dateFormat = SimpleDateFormat("EEE, MMM d, yyyy", Locale.getDefault()) + return date.let { + dateFormat.format(it) + } ?: "Дата не выбрана" + } +} diff --git a/app/src/main/java/com/itis/androidlabproject/models/Todo.kt b/app/src/main/java/com/itis/androidlabproject/models/Task.kt similarity index 57% rename from app/src/main/java/com/itis/androidlabproject/models/Todo.kt rename to app/src/main/java/com/itis/androidlabproject/models/Task.kt index 5354a17..432dffe 100644 --- a/app/src/main/java/com/itis/androidlabproject/models/Todo.kt +++ b/app/src/main/java/com/itis/androidlabproject/models/Task.kt @@ -3,9 +3,10 @@ package com.itis.androidlabproject.models import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey +import java.util.* -@Entity -class Todo( +@Entity(tableName = "task") +class Task( @PrimaryKey(autoGenerate = true) var id: Int?, @@ -15,6 +16,12 @@ class Todo( @ColumnInfo(name = "description") var description: String?, - @ColumnInfo(name = "timestamp") - var timestamp: Long? + @ColumnInfo(name = "date") + var date: Date?, + + @ColumnInfo(name = "longitude") + var longitude: Double?, + + @ColumnInfo(name = "latitude") + var latitude: Double? ) diff --git a/app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt b/app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt index 63b41fa..757a7ae 100644 --- a/app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt +++ b/app/src/main/java/com/itis/androidlabproject/view/MainActivity.kt @@ -2,11 +2,29 @@ package com.itis.androidlabproject.view import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import com.itis.androidlabproject.R +import androidx.navigation.NavController +import androidx.navigation.findNavController +import com.itis.androidlabproject.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { + private var controller: NavController? = null + private var binding: ActivityMainBinding? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater).also { + setContentView(binding?.root) + } + controller = binding?.container?.id?.let { findNavController(it) } + } + + override fun onBackPressed() { + supportFragmentManager.run { + if (backStackEntryCount == 0) { + super.onBackPressed() + } else { + popBackStack() + } + } } } diff --git a/app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt b/app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt deleted file mode 100644 index 89b2de6..0000000 --- a/app/src/main/java/com/itis/androidlabproject/view/MainViewModel.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.itis.androidlabproject.view - -import androidx.lifecycle.LiveData -import androidx.lifecycle.ViewModel -import com.itis.androidlabproject.App -import com.itis.androidlabproject.models.Todo - -class MainViewModel : ViewModel() { - val liveData: LiveData> - - init { - liveData = App.getInstance().todoDao.getAllLiveData() - } -} diff --git a/app/src/main/res/anim/enter_from_left.xml b/app/src/main/res/anim/enter_from_left.xml new file mode 100644 index 0000000..0826b75 --- /dev/null +++ b/app/src/main/res/anim/enter_from_left.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/anim/enter_from_right.xml b/app/src/main/res/anim/enter_from_right.xml new file mode 100644 index 0000000..d424f42 --- /dev/null +++ b/app/src/main/res/anim/enter_from_right.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/anim/exit_to_left.xml b/app/src/main/res/anim/exit_to_left.xml new file mode 100644 index 0000000..9c2ad05 --- /dev/null +++ b/app/src/main/res/anim/exit_to_left.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/anim/exit_to_right.xml b/app/src/main/res/anim/exit_to_right.xml new file mode 100644 index 0000000..7becffd --- /dev/null +++ b/app/src/main/res/anim/exit_to_right.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/drawable/delete.xml b/app/src/main/res/drawable/delete.xml new file mode 100644 index 0000000..3c4030b --- /dev/null +++ b/app/src/main/res/drawable/delete.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml new file mode 100644 index 0000000..2a31b2e --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a70bdb9..eae5a44 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,15 +4,19 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:orientation="vertical" tools:context=".view.MainActivity"> - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:navGraph="@navigation/nav_graph" /> diff --git a/app/src/main/res/layout/fragment_details_task.xml b/app/src/main/res/layout/fragment_details_task.xml new file mode 100644 index 0000000..388540f --- /dev/null +++ b/app/src/main/res/layout/fragment_details_task.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + +