Initial commit
							
								
								
									
										14
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,14 @@ | ||||
| *.iml | ||||
| .gradle | ||||
| /local.properties | ||||
| /.idea/caches | ||||
| /.idea/libraries | ||||
| /.idea/modules.xml | ||||
| /.idea/workspace.xml | ||||
| /.idea/navEditor.xml | ||||
| /.idea/assetWizardSettings.xml | ||||
| .DS_Store | ||||
| /build | ||||
| /captures | ||||
| .externalNativeBuild | ||||
| .cxx | ||||
							
								
								
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | ||||
| ToDo App | ||||
							
								
								
									
										122
									
								
								.idea/codeStyles/Project.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,122 @@ | ||||
| <component name="ProjectCodeStyleConfiguration"> | ||||
|   <code_scheme name="Project" version="173"> | ||||
|     <JetCodeStyleSettings> | ||||
|       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> | ||||
|     </JetCodeStyleSettings> | ||||
|     <codeStyleSettings language="XML"> | ||||
|       <indentOptions> | ||||
|         <option name="CONTINUATION_INDENT_SIZE" value="4" /> | ||||
|       </indentOptions> | ||||
|       <arrangement> | ||||
|         <rules> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>xmlns:android</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>xmlns:.*</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|               <order>BY_NAME</order> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>.*:id</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>.*:name</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>name</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>style</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>.*</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>^$</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|               <order>BY_NAME</order> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>.*</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|               <order>ANDROID_ATTRIBUTE_ORDER</order> | ||||
|             </rule> | ||||
|           </section> | ||||
|           <section> | ||||
|             <rule> | ||||
|               <match> | ||||
|                 <AND> | ||||
|                   <NAME>.*</NAME> | ||||
|                   <XML_ATTRIBUTE /> | ||||
|                   <XML_NAMESPACE>.*</XML_NAMESPACE> | ||||
|                 </AND> | ||||
|               </match> | ||||
|               <order>BY_NAME</order> | ||||
|             </rule> | ||||
|           </section> | ||||
|         </rules> | ||||
|       </arrangement> | ||||
|     </codeStyleSettings> | ||||
|     <codeStyleSettings language="kotlin"> | ||||
|       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> | ||||
|     </codeStyleSettings> | ||||
|   </code_scheme> | ||||
| </component> | ||||
							
								
								
									
										5
									
								
								.idea/codeStyles/codeStyleConfig.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,5 @@ | ||||
| <component name="ProjectCodeStyleConfiguration"> | ||||
|   <state> | ||||
|     <option name="USE_PER_PROJECT_SETTINGS" value="true" /> | ||||
|   </state> | ||||
| </component> | ||||
							
								
								
									
										21
									
								
								.idea/gradle.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="GradleMigrationSettings" migrationVersion="1" /> | ||||
|   <component name="GradleSettings"> | ||||
|     <option name="linkedExternalProjectsSettings"> | ||||
|       <GradleProjectSettings> | ||||
|         <option name="testRunner" value="PLATFORM" /> | ||||
|         <option name="distributionType" value="DEFAULT_WRAPPED" /> | ||||
|         <option name="externalProjectPath" value="$PROJECT_DIR$" /> | ||||
|         <option name="gradleJvm" value="1.8" /> | ||||
|         <option name="modules"> | ||||
|           <set> | ||||
|             <option value="$PROJECT_DIR$" /> | ||||
|             <option value="$PROJECT_DIR$/app" /> | ||||
|           </set> | ||||
|         </option> | ||||
|         <option name="resolveModulePerSourceSet" value="false" /> | ||||
|       </GradleProjectSettings> | ||||
|     </option> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										25
									
								
								.idea/jarRepositories.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,25 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="RemoteRepositoriesConfiguration"> | ||||
|     <remote-repository> | ||||
|       <option name="id" value="central" /> | ||||
|       <option name="name" value="Maven Central repository" /> | ||||
|       <option name="url" value="https://repo1.maven.org/maven2" /> | ||||
|     </remote-repository> | ||||
|     <remote-repository> | ||||
|       <option name="id" value="jboss.community" /> | ||||
|       <option name="name" value="JBoss Community repository" /> | ||||
|       <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" /> | ||||
|     </remote-repository> | ||||
|     <remote-repository> | ||||
|       <option name="id" value="BintrayJCenter" /> | ||||
|       <option name="name" value="BintrayJCenter" /> | ||||
|       <option name="url" value="https://jcenter.bintray.com/" /> | ||||
|     </remote-repository> | ||||
|     <remote-repository> | ||||
|       <option name="id" value="Google" /> | ||||
|       <option name="name" value="Google" /> | ||||
|       <option name="url" value="https://dl.google.com/dl/android/maven2/" /> | ||||
|     </remote-repository> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										9
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | ||||
|     <output url="file://$PROJECT_DIR$/build/classes" /> | ||||
|   </component> | ||||
|   <component name="ProjectType"> | ||||
|     <option name="id" value="Android" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										12
									
								
								.idea/runConfigurations.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="RunConfigurationProducerService"> | ||||
|     <option name="ignoredProducers"> | ||||
|       <set> | ||||
|         <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> | ||||
|         <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> | ||||
|         <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> | ||||
|       </set> | ||||
|     </option> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										1
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										80
									
								
								app/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,80 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply plugin: 'kotlin-android' | ||||
| apply plugin: 'kotlin-android-extensions' | ||||
| apply plugin: 'kotlin-kapt' | ||||
| apply plugin: "androidx.navigation.safeargs.kotlin" | ||||
| 
 | ||||
| android { | ||||
|     compileSdkVersion 29 | ||||
|     buildToolsVersion "30.0.0" | ||||
| 
 | ||||
|     defaultConfig { | ||||
|         applicationId "com.example.todoapp" | ||||
|         minSdkVersion 26 | ||||
|         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' | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     buildFeatures{ | ||||
|         dataBinding = true | ||||
|     } | ||||
| 
 | ||||
|     compileOptions { | ||||
|         sourceCompatibility JavaVersion.VERSION_1_8 | ||||
|         targetCompatibility JavaVersion.VERSION_1_8 | ||||
|     } | ||||
| 
 | ||||
|     kotlinOptions { | ||||
|         jvmTarget = JavaVersion.VERSION_1_8.toString() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     implementation fileTree(dir: "libs", include: ["*.jar"]) | ||||
|     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" | ||||
|     implementation 'androidx.core:core-ktx:1.3.0' | ||||
|     implementation 'androidx.appcompat:appcompat:1.1.0' | ||||
|     implementation 'androidx.constraintlayout:constraintlayout:1.1.3' | ||||
|     implementation 'androidx.legacy:legacy-support-v4:1.0.0' | ||||
|     testImplementation 'junit:junit:4.13' | ||||
|     androidTestImplementation 'androidx.test.ext:junit:1.1.1' | ||||
|     androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' | ||||
| 
 | ||||
|     // Navigation Component | ||||
|     implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0' | ||||
|     implementation 'androidx.navigation:navigation-ui-ktx:2.3.0' | ||||
| 
 | ||||
|     // Room components | ||||
|     implementation "androidx.room:room-runtime:2.2.5" | ||||
|     kapt "androidx.room:room-compiler:2.2.5" | ||||
|     implementation "androidx.room:room-ktx:2.2.5" | ||||
|     androidTestImplementation "androidx.room:room-testing:2.2.5" | ||||
| 
 | ||||
|     // Lifecycle components | ||||
|     implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" | ||||
|     implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0" | ||||
|     implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" | ||||
| 
 | ||||
|     // Kotlin components | ||||
|     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72" | ||||
|     api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5" | ||||
|     api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5" | ||||
| 
 | ||||
|     // DataBinding | ||||
|     kapt "com.android.databinding:compiler:3.2.0-alpha10" | ||||
|     kapt "androidx.databinding:databinding-common:4.0.0" | ||||
| 
 | ||||
|     // RecyclerView Animator | ||||
|     implementation 'jp.wasabeef:recyclerview-animators:3.0.0' | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										21
									
								
								app/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # You can control the set of applied configuration files using the | ||||
| # proguardFiles setting in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
| 
 | ||||
| # If your project uses WebView with JS, uncomment the following | ||||
| # and specify the fully qualified class name to the JavaScript interface | ||||
| # class: | ||||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||||
| #   public *; | ||||
| #} | ||||
| 
 | ||||
| # Uncomment this to preserve the line number information for | ||||
| # debugging stack traces. | ||||
| #-keepattributes SourceFile,LineNumberTable | ||||
| 
 | ||||
| # If you keep the line number information, uncomment this to | ||||
| # hide the original source file name. | ||||
| #-renamesourcefileattribute SourceFile | ||||
| @ -0,0 +1,24 @@ | ||||
| package com.example.todoapp | ||||
| 
 | ||||
| import androidx.test.platform.app.InstrumentationRegistry | ||||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||||
| 
 | ||||
| import org.junit.Test | ||||
| import org.junit.runner.RunWith | ||||
| 
 | ||||
| import org.junit.Assert.* | ||||
| 
 | ||||
| /** | ||||
|  * Instrumented test, which will execute on an Android device. | ||||
|  * | ||||
|  * See [testing documentation](http://d.android.com/tools/testing). | ||||
|  */ | ||||
| @RunWith(AndroidJUnit4::class) | ||||
| class ExampleInstrumentedTest { | ||||
|     @Test | ||||
|     fun useAppContext() { | ||||
|         // Context of the app under test. | ||||
|         val appContext = InstrumentationRegistry.getInstrumentation().targetContext | ||||
|         assertEquals("com.example.todoapp", appContext.packageName) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								app/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="com.example.todoapp"> | ||||
| 
 | ||||
|     <application | ||||
|         android:allowBackup="true" | ||||
|         android:icon="@mipmap/ic_launcher" | ||||
|         android:label="@string/app_name" | ||||
|         android:roundIcon="@mipmap/ic_launcher_round" | ||||
|         android:supportsRtl="true" | ||||
|         android:theme="@style/AppTheme"> | ||||
|         <activity android:name=".MainActivity"> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.MAIN" /> | ||||
|                 <category android:name="android.intent.category.LAUNCHER" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|     </application> | ||||
| 
 | ||||
| </manifest> | ||||
							
								
								
									
										21
									
								
								app/src/main/java/com/example/todoapp/MainActivity.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| package com.example.todoapp | ||||
| 
 | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import android.os.Bundle | ||||
| import androidx.navigation.findNavController | ||||
| import androidx.navigation.ui.setupActionBarWithNavController | ||||
| 
 | ||||
| class MainActivity : AppCompatActivity() { | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|         setContentView(R.layout.activity_main) | ||||
| 
 | ||||
|         setupActionBarWithNavController(findNavController(R.id.navHostFragment)) | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     override fun onSupportNavigateUp(): Boolean { | ||||
|         val navController = findNavController(R.id.navHostFragment) | ||||
|         return navController.navigateUp() || super.onSupportNavigateUp() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								app/src/main/java/com/example/todoapp/data/Converter.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,18 @@ | ||||
| package com.example.todoapp.data | ||||
| 
 | ||||
| import androidx.room.TypeConverter | ||||
| import com.example.todoapp.data.models.Priority | ||||
| 
 | ||||
| class Converter { | ||||
| 
 | ||||
|     @TypeConverter | ||||
|     fun fromPriority(priority: Priority): String { | ||||
|         return priority.name | ||||
|     } | ||||
| 
 | ||||
|     @TypeConverter | ||||
|     fun toPriority(priority: String): Priority { | ||||
|         return Priority.valueOf(priority) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										34
									
								
								app/src/main/java/com/example/todoapp/data/ToDoDao.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,34 @@ | ||||
| package com.example.todoapp.data | ||||
| 
 | ||||
| import androidx.lifecycle.LiveData | ||||
| import androidx.room.* | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| 
 | ||||
| @Dao | ||||
| interface ToDoDao { | ||||
| 
 | ||||
|     @Query("SELECT * FROM todo_table ORDER BY id ASC") | ||||
|     fun getAllData(): LiveData<List<ToDoData>> | ||||
| 
 | ||||
|     @Insert(onConflict = OnConflictStrategy.IGNORE) | ||||
|     suspend fun insertData(toDoData: ToDoData) | ||||
| 
 | ||||
|     @Update | ||||
|     suspend fun updateData(toDoData: ToDoData) | ||||
| 
 | ||||
|     @Delete | ||||
|     suspend fun deleteItem(toDoData: ToDoData) | ||||
| 
 | ||||
|     @Query("DELETE FROM todo_table") | ||||
|     suspend fun deleteAll() | ||||
| 
 | ||||
|     @Query("SELECT * FROM todo_table WHERE title LIKE :searchQuery") | ||||
|     fun searchDatabase(searchQuery: String): LiveData<List<ToDoData>> | ||||
| 
 | ||||
|     @Query("SELECT * FROM todo_table ORDER BY CASE WHEN priority LIKE 'H%' THEN 1 WHEN priority LIKE 'M%' THEN 2 WHEN priority LIKE 'L%' THEN 3 END") | ||||
|     fun sortByHighPriority(): LiveData<List<ToDoData>> | ||||
| 
 | ||||
|     @Query("SELECT * FROM todo_table ORDER BY CASE WHEN priority LIKE 'L%' THEN 1 WHEN priority LIKE 'M%' THEN 2 WHEN priority LIKE 'H%' THEN 3 END") | ||||
|     fun sortByLowPriority(): LiveData<List<ToDoData>> | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										37
									
								
								app/src/main/java/com/example/todoapp/data/ToDoDatabase.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,37 @@ | ||||
| package com.example.todoapp.data | ||||
| 
 | ||||
| import android.content.Context | ||||
| import androidx.room.Database | ||||
| import androidx.room.Room | ||||
| import androidx.room.RoomDatabase | ||||
| import androidx.room.TypeConverters | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| 
 | ||||
| @Database(entities = [ToDoData::class], version = 1, exportSchema = false) | ||||
| @TypeConverters(Converter::class) | ||||
| abstract class ToDoDatabase: RoomDatabase() { | ||||
| 
 | ||||
|     abstract fun toDoDao(): ToDoDao | ||||
| 
 | ||||
|     companion object { | ||||
|         @Volatile | ||||
|         private var INSTANCE: ToDoDatabase? = null | ||||
| 
 | ||||
|         fun getDatabase(context: Context): ToDoDatabase { | ||||
|             val tempInstance = INSTANCE | ||||
|             if(tempInstance != null){ | ||||
|                 return tempInstance | ||||
|             } | ||||
|             synchronized(this){ | ||||
|                 val instance = Room.databaseBuilder( | ||||
|                     context.applicationContext, | ||||
|                     ToDoDatabase::class.java, | ||||
|                     "todo_database" | ||||
|                 ).build() | ||||
|                 INSTANCE = instance | ||||
|                 return instance | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,7 @@ | ||||
| package com.example.todoapp.data.models | ||||
| 
 | ||||
| enum class Priority { | ||||
|     HIGH, | ||||
|     MEDIUM, | ||||
|     LOW | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| package com.example.todoapp.data.models | ||||
| 
 | ||||
| import android.os.Parcelable | ||||
| import androidx.room.Entity | ||||
| import androidx.room.PrimaryKey | ||||
| import kotlinx.android.parcel.Parcelize | ||||
| 
 | ||||
| @Entity(tableName = "todo_table") | ||||
| @Parcelize | ||||
| data class ToDoData( | ||||
|     @PrimaryKey(autoGenerate = true) | ||||
|     var id: Int, | ||||
|     var title: String, | ||||
|     var priority: Priority, | ||||
|     var description: String | ||||
| ): Parcelable | ||||
| @ -0,0 +1,33 @@ | ||||
| package com.example.todoapp.data.repository | ||||
| 
 | ||||
| import androidx.lifecycle.LiveData | ||||
| import com.example.todoapp.data.ToDoDao | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| 
 | ||||
| class ToDoRepository(private val toDoDao: ToDoDao) { | ||||
| 
 | ||||
|     val getAllData: LiveData<List<ToDoData>> = toDoDao.getAllData() | ||||
|     val sortByHighPriority: LiveData<List<ToDoData>> = toDoDao.sortByHighPriority() | ||||
|     val sortByLowPriority: LiveData<List<ToDoData>> = toDoDao.sortByLowPriority() | ||||
| 
 | ||||
|     suspend fun insertData(toDoData: ToDoData){ | ||||
|         toDoDao.insertData(toDoData) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun updateData(toDoData: ToDoData){ | ||||
|         toDoDao.updateData(toDoData) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun deleteItem(toDoData: ToDoData){ | ||||
|         toDoDao.deleteItem(toDoData) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun deleteAll(){ | ||||
|         toDoDao.deleteAll() | ||||
|     } | ||||
| 
 | ||||
|     fun searchDatabase(searchQuery: String): LiveData<List<ToDoData>> { | ||||
|         return toDoDao.searchDatabase(searchQuery) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package com.example.todoapp.data.viewmodel | ||||
| 
 | ||||
| import android.app.Application | ||||
| import androidx.lifecycle.AndroidViewModel | ||||
| import androidx.lifecycle.LiveData | ||||
| import androidx.lifecycle.viewModelScope | ||||
| import com.example.todoapp.data.ToDoDatabase | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| import com.example.todoapp.data.repository.ToDoRepository | ||||
| import kotlinx.coroutines.Dispatchers | ||||
| import kotlinx.coroutines.launch | ||||
| 
 | ||||
| class ToDoViewModel(application: Application) : AndroidViewModel(application) { | ||||
| 
 | ||||
|     private val toDoDao = ToDoDatabase.getDatabase( | ||||
|         application | ||||
|     ).toDoDao() | ||||
|     private val repository: ToDoRepository | ||||
| 
 | ||||
|     val getAllData: LiveData<List<ToDoData>> | ||||
|     val sortByHighPriority: LiveData<List<ToDoData>> | ||||
|     val sortByLowPriority: LiveData<List<ToDoData>> | ||||
| 
 | ||||
|     init { | ||||
|         repository = ToDoRepository(toDoDao) | ||||
|         getAllData = repository.getAllData | ||||
|         sortByHighPriority = repository.sortByHighPriority | ||||
|         sortByLowPriority = repository.sortByLowPriority | ||||
|     } | ||||
| 
 | ||||
|     fun insertData(toDoData: ToDoData) { | ||||
|         viewModelScope.launch(Dispatchers.IO) { | ||||
|             repository.insertData(toDoData) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun updateData(toDoData: ToDoData) { | ||||
|         viewModelScope.launch(Dispatchers.IO) { | ||||
|             repository.updateData(toDoData) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun deleteItem(toDoData: ToDoData) { | ||||
|         viewModelScope.launch(Dispatchers.IO) { | ||||
|             repository.deleteItem(toDoData) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun deleteAll() { | ||||
|         viewModelScope.launch(Dispatchers.IO) { | ||||
|             repository.deleteAll() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun searchDatabase(searchQuery: String): LiveData<List<ToDoData>>{ | ||||
|         return repository.searchDatabase(searchQuery) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,66 @@ | ||||
| package com.example.todoapp.fragments | ||||
| 
 | ||||
| import android.view.View | ||||
| import android.widget.Spinner | ||||
| import androidx.cardview.widget.CardView | ||||
| import androidx.constraintlayout.widget.ConstraintLayout | ||||
| import androidx.databinding.BindingAdapter | ||||
| import androidx.lifecycle.MutableLiveData | ||||
| import androidx.navigation.findNavController | ||||
| import com.example.todoapp.R | ||||
| import com.example.todoapp.data.models.Priority | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| import com.example.todoapp.fragments.list.ListFragmentDirections | ||||
| import com.google.android.material.floatingactionbutton.FloatingActionButton | ||||
| 
 | ||||
| class BindingAdapters { | ||||
| 
 | ||||
|     companion object{ | ||||
| 
 | ||||
|         @BindingAdapter("android:navigateToAddFragment") | ||||
|         @JvmStatic | ||||
|         fun navigateToAddFragment(view: FloatingActionButton, navigate: Boolean){ | ||||
|             view.setOnClickListener { | ||||
|                 if(navigate){ | ||||
|                     view.findNavController().navigate(R.id.action_listFragment_to_addFragment) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         @BindingAdapter("android:emptyDatabase") | ||||
|         @JvmStatic | ||||
|         fun emptyDatabase(view: View, emptyDatabase: MutableLiveData<Boolean>){ | ||||
|             when(emptyDatabase.value){ | ||||
|                 true -> view.visibility = View.VISIBLE | ||||
|                 false -> view.visibility = View.INVISIBLE | ||||
|             } | ||||
|         } | ||||
|         @BindingAdapter("android:parsePriorityToInt") | ||||
|         @JvmStatic | ||||
|         fun parsePriorityToInt(view: Spinner, priority: Priority){ | ||||
|             when(priority){ | ||||
|                 Priority.HIGH -> { view.setSelection(0) } | ||||
|                 Priority.MEDIUM -> { view.setSelection(1) } | ||||
|                 Priority.LOW -> { view.setSelection(2) } | ||||
|             } | ||||
|         } | ||||
|         @BindingAdapter("android:parsePriorityColor") | ||||
|         @JvmStatic | ||||
|         fun parsePriorityColor(cardView: CardView, priority: Priority){ | ||||
|             when(priority){ | ||||
|                 Priority.HIGH -> { cardView.setCardBackgroundColor(cardView.context.getColor(R.color.red)) } | ||||
|                 Priority.MEDIUM -> { cardView.setCardBackgroundColor(cardView.context.getColor(R.color.yellow)) } | ||||
|                 Priority.LOW -> { cardView.setCardBackgroundColor(cardView.context.getColor(R.color.green)) } | ||||
|             } | ||||
|         } | ||||
|         @BindingAdapter("android:sendDataToUpdateFragment") | ||||
|         @JvmStatic | ||||
|         fun sendDataToUpdateFragment(view: ConstraintLayout, currentItem: ToDoData){ | ||||
|             view.setOnClickListener { | ||||
|                 val action = ListFragmentDirections.actionListFragmentToUpdateFragment(currentItem) | ||||
|                 view.findNavController().navigate(action) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package com.example.todoapp.fragments | ||||
| 
 | ||||
| import android.app.Application | ||||
| import android.text.TextUtils | ||||
| import android.view.View | ||||
| import android.widget.AdapterView | ||||
| import android.widget.TextView | ||||
| import androidx.core.content.ContextCompat | ||||
| import androidx.lifecycle.AndroidViewModel | ||||
| import androidx.lifecycle.MutableLiveData | ||||
| import com.example.todoapp.R | ||||
| import com.example.todoapp.data.models.Priority | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| 
 | ||||
| class SharedViewModel(application: Application): AndroidViewModel(application) { | ||||
| 
 | ||||
|     /** ============================= List Fragment ============================= */ | ||||
| 
 | ||||
|     val emptyDatabase: MutableLiveData<Boolean> = MutableLiveData(false) | ||||
| 
 | ||||
|     fun checkIfDatabaseEmpty(toDoData: List<ToDoData>){ | ||||
|         emptyDatabase.value = toDoData.isEmpty() | ||||
|     } | ||||
| 
 | ||||
|     /** ============================= Add/Update Fragment ============================= */ | ||||
| 
 | ||||
|     val listener: AdapterView.OnItemSelectedListener = object : | ||||
|         AdapterView.OnItemSelectedListener{ | ||||
|         override fun onNothingSelected(p0: AdapterView<*>?) {} | ||||
|         override fun onItemSelected( | ||||
|             parent: AdapterView<*>?, | ||||
|             view: View?, | ||||
|             position: Int, | ||||
|             id: Long | ||||
|         ) { | ||||
|             when(position){ | ||||
|                 0 -> { (parent?.getChildAt(0) as TextView).setTextColor(ContextCompat.getColor(application, R.color.red)) } | ||||
|                 1 -> { (parent?.getChildAt(0) as TextView).setTextColor(ContextCompat.getColor(application, R.color.yellow)) } | ||||
|                 2 -> { (parent?.getChildAt(0) as TextView).setTextColor(ContextCompat.getColor(application, R.color.green)) } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun verifyDataFromUser(title: String, description: String): Boolean { | ||||
|         return if(TextUtils.isEmpty(title) || TextUtils.isEmpty(description)){ | ||||
|             false | ||||
|         } else !(title.isEmpty() || description.isEmpty()) | ||||
|     } | ||||
| 
 | ||||
|     fun parsePriority(priority: String): Priority { | ||||
|         return when(priority){ | ||||
|             "High Priority" -> { Priority.HIGH } | ||||
|             "Medium Priority" -> { Priority.MEDIUM } | ||||
|             "Low Priority" -> { Priority.LOW } | ||||
|             else -> Priority.LOW | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,71 @@ | ||||
| package com.example.todoapp.fragments.add | ||||
| 
 | ||||
| import android.os.Bundle | ||||
| import android.view.* | ||||
| import android.widget.Toast | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.fragment.app.viewModels | ||||
| import androidx.navigation.fragment.findNavController | ||||
| import com.example.todoapp.R | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| import com.example.todoapp.data.viewmodel.ToDoViewModel | ||||
| import com.example.todoapp.fragments.SharedViewModel | ||||
| import kotlinx.android.synthetic.main.fragment_add.* | ||||
| import kotlinx.android.synthetic.main.fragment_add.view.* | ||||
| 
 | ||||
| class AddFragment : Fragment() { | ||||
| 
 | ||||
|     private val mToDoViewModel: ToDoViewModel by viewModels() | ||||
|     private val mSharedViewModel: SharedViewModel by viewModels() | ||||
| 
 | ||||
|     override fun onCreateView( | ||||
|         inflater: LayoutInflater, container: ViewGroup?, | ||||
|         savedInstanceState: Bundle? | ||||
|     ): View? { | ||||
|         // Inflate the layout for this fragment | ||||
|         val view = inflater.inflate(R.layout.fragment_add, container, false) | ||||
| 
 | ||||
|         // Set Menu | ||||
|         setHasOptionsMenu(true) | ||||
| 
 | ||||
|         // Spinner Item Selected Listener | ||||
|         view.priorities_spinner.onItemSelectedListener = mSharedViewModel.listener | ||||
| 
 | ||||
|         return view | ||||
|     } | ||||
| 
 | ||||
|     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { | ||||
|         inflater.inflate(R.menu.add_fragment_menu, menu) | ||||
|     } | ||||
| 
 | ||||
|     override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||
|         if(item.itemId == R.id.menu_add){ | ||||
|             insertDataToDb() | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item) | ||||
|     } | ||||
| 
 | ||||
|     private fun insertDataToDb() { | ||||
|         val mTitle = title_et.text.toString() | ||||
|         val mPriority = priorities_spinner.selectedItem.toString() | ||||
|         val mDescription = description_et.text.toString() | ||||
| 
 | ||||
|         val validation = mSharedViewModel.verifyDataFromUser(mTitle, mDescription) | ||||
|         if(validation){ | ||||
|             // Insert Data to Database | ||||
|             val newData = ToDoData( | ||||
|                 0, | ||||
|                 mTitle, | ||||
|                 mSharedViewModel.parsePriority(mPriority), | ||||
|                 mDescription | ||||
|             ) | ||||
|             mToDoViewModel.insertData(newData) | ||||
|             Toast.makeText(requireContext(), "Successfully added!", Toast.LENGTH_SHORT).show() | ||||
|             // Navigate Back | ||||
|             findNavController().navigate(R.id.action_addFragment_to_listFragment) | ||||
|         }else{ | ||||
|             Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_SHORT).show() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,158 @@ | ||||
| package com.example.todoapp.fragments.list | ||||
| 
 | ||||
| import android.app.AlertDialog | ||||
| import android.os.Bundle | ||||
| import android.view.* | ||||
| import androidx.appcompat.widget.SearchView | ||||
| import android.widget.Toast | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.fragment.app.viewModels | ||||
| import androidx.lifecycle.Observer | ||||
| import androidx.recyclerview.widget.* | ||||
| import com.example.todoapp.R | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| import com.example.todoapp.data.viewmodel.ToDoViewModel | ||||
| import com.example.todoapp.databinding.FragmentListBinding | ||||
| import com.example.todoapp.fragments.SharedViewModel | ||||
| import com.example.todoapp.fragments.list.adapter.ListAdapter | ||||
| import com.google.android.material.snackbar.Snackbar | ||||
| import jp.wasabeef.recyclerview.animators.SlideInUpAnimator | ||||
| 
 | ||||
| class ListFragment : Fragment(), SearchView.OnQueryTextListener { | ||||
| 
 | ||||
|     private val mToDoViewModel: ToDoViewModel by viewModels() | ||||
|     private val mSharedViewModel: SharedViewModel by viewModels() | ||||
| 
 | ||||
|     private var _binding: FragmentListBinding? = null | ||||
|     private val binding get() = _binding!! | ||||
| 
 | ||||
|     private val adapter: ListAdapter by lazy { ListAdapter() } | ||||
| 
 | ||||
|     override fun onCreateView( | ||||
|         inflater: LayoutInflater, container: ViewGroup?, | ||||
|         savedInstanceState: Bundle? | ||||
|     ): View? { | ||||
|         // Data binding | ||||
|         _binding = FragmentListBinding.inflate(inflater, container, false) | ||||
|         binding.lifecycleOwner = this | ||||
|         binding.mSharedViewModel = mSharedViewModel | ||||
| 
 | ||||
|         // Setup RecyclerView | ||||
|         setupRecyclerview() | ||||
| 
 | ||||
|         // Observe LiveData | ||||
|         mToDoViewModel.getAllData.observe(viewLifecycleOwner, Observer { data -> | ||||
|             mSharedViewModel.checkIfDatabaseEmpty(data) | ||||
|             adapter.setData(data) | ||||
|         }) | ||||
| 
 | ||||
|         // Set Menu | ||||
|         setHasOptionsMenu(true) | ||||
| 
 | ||||
|         return binding.root | ||||
|     } | ||||
| 
 | ||||
|     private fun setupRecyclerview() { | ||||
|         val recyclerView = binding.recyclerView | ||||
|         recyclerView.adapter = adapter | ||||
|         recyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) | ||||
|         recyclerView.itemAnimator = SlideInUpAnimator().apply { | ||||
|             addDuration = 300 | ||||
|         } | ||||
| 
 | ||||
|         // Swipe to Delete | ||||
|         swipeToDelete(recyclerView) | ||||
|     } | ||||
| 
 | ||||
|     private fun swipeToDelete(recyclerView: RecyclerView) { | ||||
|         val swipeToDeleteCallback = object : SwipeToDelete() { | ||||
|             override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { | ||||
|                 val deletedItem = adapter.dataList[viewHolder.adapterPosition] | ||||
|                 // Delete Item | ||||
|                 mToDoViewModel.deleteItem(deletedItem) | ||||
|                 adapter.notifyItemRemoved(viewHolder.adapterPosition) | ||||
|                 // Restore Deleted Item | ||||
|                 restoreDeletedData(viewHolder.itemView, deletedItem, viewHolder.adapterPosition) | ||||
|             } | ||||
|         } | ||||
|         val itemTouchHelper = ItemTouchHelper(swipeToDeleteCallback) | ||||
|         itemTouchHelper.attachToRecyclerView(recyclerView) | ||||
|     } | ||||
| 
 | ||||
|     private fun restoreDeletedData(view: View, deletedItem: ToDoData, position: Int) { | ||||
|         val snackBar = Snackbar.make( | ||||
|             view, "Deleted '${deletedItem.title}'", | ||||
|             Snackbar.LENGTH_LONG | ||||
|         ) | ||||
|         snackBar.setAction("Undo") { | ||||
|             mToDoViewModel.insertData(deletedItem) | ||||
|             adapter.notifyItemChanged(position) | ||||
|         } | ||||
|         snackBar.show() | ||||
|     } | ||||
| 
 | ||||
|     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { | ||||
|         inflater.inflate(R.menu.list_fragment_menu, menu) | ||||
| 
 | ||||
|         val search = menu.findItem(R.id.menu_search) | ||||
|         val searchView = search.actionView as? SearchView | ||||
|         searchView?.isSubmitButtonEnabled = true | ||||
|         searchView?.setOnQueryTextListener(this) | ||||
|     } | ||||
| 
 | ||||
|     override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||
|         when (item.itemId) { | ||||
|             R.id.menu_delete_all -> confirmRemoval() | ||||
|             R.id.menu_priority_high -> mToDoViewModel.sortByHighPriority.observe(this, Observer { adapter.setData(it) }) | ||||
|             R.id.menu_priority_low -> mToDoViewModel.sortByLowPriority.observe(this, Observer { adapter.setData(it) }) | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item) | ||||
|     } | ||||
| 
 | ||||
|     override fun onQueryTextSubmit(query: String?): Boolean { | ||||
|         if (query != null) { | ||||
|             searchThroughDatabase(query) | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun onQueryTextChange(query: String?): Boolean { | ||||
|         if (query != null) { | ||||
|             searchThroughDatabase(query) | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     private fun searchThroughDatabase(query: String) { | ||||
|         val searchQuery = "%$query%" | ||||
| 
 | ||||
|         mToDoViewModel.searchDatabase(searchQuery).observe(this, Observer { list -> | ||||
|             list?.let { | ||||
|                 adapter.setData(it) | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     // Show AlertDialog to Confirm Removal of All Items from Database Table | ||||
|     private fun confirmRemoval() { | ||||
|         val builder = AlertDialog.Builder(requireContext()) | ||||
|         builder.setPositiveButton("Yes") { _, _ -> | ||||
|             mToDoViewModel.deleteAll() | ||||
|             Toast.makeText( | ||||
|                 requireContext(), | ||||
|                 "Successfully Removed Everything!", | ||||
|                 Toast.LENGTH_SHORT | ||||
|             ).show() | ||||
|         } | ||||
|         builder.setNegativeButton("No") { _, _ -> } | ||||
|         builder.setTitle("Delete everything?") | ||||
|         builder.setMessage("Are you sure you want to remove everything?") | ||||
|         builder.create().show() | ||||
|     } | ||||
| 
 | ||||
|     override fun onDestroyView() { | ||||
|         super.onDestroyView() | ||||
|         _binding = null | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package com.example.todoapp.fragments.list | ||||
| 
 | ||||
| import androidx.recyclerview.widget.ItemTouchHelper | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| 
 | ||||
| abstract class SwipeToDelete: ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { | ||||
|     override fun onMove( | ||||
|         recyclerView: RecyclerView, | ||||
|         viewHolder: RecyclerView.ViewHolder, | ||||
|         target: RecyclerView.ViewHolder | ||||
|     ): Boolean { | ||||
|         return false | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,53 @@ | ||||
| package com.example.todoapp.fragments.list.adapter | ||||
| 
 | ||||
| import android.view.LayoutInflater | ||||
| import android.view.ViewGroup | ||||
| import androidx.recyclerview.widget.DiffUtil | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| import com.example.todoapp.databinding.RowLayoutBinding | ||||
| 
 | ||||
| class ListAdapter : RecyclerView.Adapter<ListAdapter.MyViewHolder>() { | ||||
| 
 | ||||
|     var dataList = emptyList<ToDoData>() | ||||
| 
 | ||||
|     class MyViewHolder(private val binding: RowLayoutBinding) : RecyclerView.ViewHolder(binding.root){ | ||||
| 
 | ||||
|         fun bind(toDoData: ToDoData){ | ||||
|             binding.toDoData = toDoData | ||||
|             binding.executePendingBindings() | ||||
|         } | ||||
|         companion object{ | ||||
|             fun from(parent: ViewGroup): MyViewHolder { | ||||
|                 val layoutInflater = LayoutInflater.from(parent.context) | ||||
|                 val binding = RowLayoutBinding.inflate(layoutInflater, parent, false) | ||||
|                 return MyViewHolder( | ||||
|                     binding | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { | ||||
|         return MyViewHolder.from( | ||||
|             parent | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun getItemCount(): Int { | ||||
|         return dataList.size | ||||
|     } | ||||
| 
 | ||||
|     override fun onBindViewHolder(holder: MyViewHolder, position: Int) { | ||||
|         val currentItem = dataList[position] | ||||
|         holder.bind(currentItem) | ||||
|     } | ||||
| 
 | ||||
|     fun setData(toDoData: List<ToDoData>){ | ||||
|         val toDoDiffUtil = ToDoDiffUtil(dataList, toDoData) | ||||
|         val toDoDiffResult = DiffUtil.calculateDiff(toDoDiffUtil) | ||||
|         this.dataList = toDoData | ||||
|         toDoDiffResult.dispatchUpdatesTo(this) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,29 @@ | ||||
| package com.example.todoapp.fragments.list.adapter | ||||
| 
 | ||||
| import androidx.recyclerview.widget.DiffUtil | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| 
 | ||||
| class ToDoDiffUtil( | ||||
|     private val oldList: List<ToDoData>, | ||||
|     private val newList: List<ToDoData> | ||||
| ): DiffUtil.Callback() { | ||||
| 
 | ||||
|     override fun getOldListSize(): Int { | ||||
|         return oldList.size | ||||
|     } | ||||
| 
 | ||||
|     override fun getNewListSize(): Int { | ||||
|         return newList.size | ||||
|     } | ||||
| 
 | ||||
|     override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { | ||||
|         return oldList[oldItemPosition] === newList[newItemPosition] | ||||
|     } | ||||
| 
 | ||||
|     override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { | ||||
|         return oldList[oldItemPosition].id == newList[newItemPosition].id | ||||
|                 && oldList[oldItemPosition].title == newList[newItemPosition].title | ||||
|                 && oldList[oldItemPosition].description == newList[newItemPosition].description | ||||
|                 && oldList[oldItemPosition].priority == newList[newItemPosition].priority | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,104 @@ | ||||
| package com.example.todoapp.fragments.update | ||||
| 
 | ||||
| import android.app.AlertDialog | ||||
| import android.os.Bundle | ||||
| import android.view.* | ||||
| import android.widget.Toast | ||||
| import androidx.fragment.app.Fragment | ||||
| import androidx.fragment.app.viewModels | ||||
| import androidx.navigation.fragment.findNavController | ||||
| import androidx.navigation.fragment.navArgs | ||||
| import com.example.todoapp.R | ||||
| import com.example.todoapp.data.models.ToDoData | ||||
| import com.example.todoapp.data.viewmodel.ToDoViewModel | ||||
| import com.example.todoapp.databinding.FragmentUpdateBinding | ||||
| import com.example.todoapp.fragments.SharedViewModel | ||||
| import kotlinx.android.synthetic.main.fragment_update.* | ||||
| import kotlinx.android.synthetic.main.fragment_update.view.* | ||||
| 
 | ||||
| class UpdateFragment : Fragment() { | ||||
| 
 | ||||
|     private val args by navArgs<UpdateFragmentArgs>() | ||||
| 
 | ||||
|     private val mSharedViewModel: SharedViewModel by viewModels() | ||||
|     private val mToDoViewModel: ToDoViewModel by viewModels() | ||||
| 
 | ||||
|     private var _binding: FragmentUpdateBinding? = null | ||||
|     private val binding get() = _binding!! | ||||
| 
 | ||||
|     override fun onCreateView( | ||||
|         inflater: LayoutInflater, container: ViewGroup?, | ||||
|         savedInstanceState: Bundle? | ||||
|     ): View? { | ||||
|         // Data binding | ||||
|         _binding = FragmentUpdateBinding.inflate(inflater, container, false) | ||||
|         binding.args = args | ||||
| 
 | ||||
|         // Set Menu | ||||
|         setHasOptionsMenu(true) | ||||
| 
 | ||||
|         // Spinner Item Selected Listener | ||||
|         binding.currentPrioritiesSpinner.onItemSelectedListener = mSharedViewModel.listener | ||||
| 
 | ||||
|         return binding.root | ||||
|     } | ||||
| 
 | ||||
|     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { | ||||
|         inflater.inflate(R.menu.update_fragment_menu, menu) | ||||
|     } | ||||
| 
 | ||||
|     override fun onOptionsItemSelected(item: MenuItem): Boolean { | ||||
|         when (item.itemId) { | ||||
|             R.id.menu_save -> updateItem() | ||||
|             R.id.menu_delete -> confirmItemRemoval() | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item) | ||||
|     } | ||||
| 
 | ||||
|     private fun updateItem() { | ||||
|         val title = current_title_et.text.toString() | ||||
|         val description = current_description_et.text.toString() | ||||
|         val getPriority = current_priorities_spinner.selectedItem.toString() | ||||
| 
 | ||||
|         val validation = mSharedViewModel.verifyDataFromUser(title, description) | ||||
|         if (validation) { | ||||
|             // Update Current Item | ||||
|             val updatedItem = ToDoData( | ||||
|                 args.currentItem.id, | ||||
|                 title, | ||||
|                 mSharedViewModel.parsePriority(getPriority), | ||||
|                 description | ||||
|             ) | ||||
|             mToDoViewModel.updateData(updatedItem) | ||||
|             Toast.makeText(requireContext(), "Successfully updated!", Toast.LENGTH_SHORT).show() | ||||
|             // Navigate back | ||||
|             findNavController().navigate(R.id.action_updateFragment_to_listFragment) | ||||
|         } else { | ||||
|             Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_SHORT) | ||||
|                 .show() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Show AlertDialog to Confirm Item Removal | ||||
|     private fun confirmItemRemoval() { | ||||
|         val builder = AlertDialog.Builder(requireContext()) | ||||
|         builder.setPositiveButton("Yes") { _, _ -> | ||||
|             mToDoViewModel.deleteItem(args.currentItem) | ||||
|             Toast.makeText( | ||||
|                 requireContext(), | ||||
|                 "Successfully Removed: ${args.currentItem.title}", | ||||
|                 Toast.LENGTH_SHORT | ||||
|             ).show() | ||||
|             findNavController().navigate(R.id.action_updateFragment_to_listFragment) | ||||
|         } | ||||
|         builder.setNegativeButton("No") { _, _ -> } | ||||
|         builder.setTitle("Delete '${args.currentItem.title}'?") | ||||
|         builder.setMessage("Are you sure you want to remove '${args.currentItem.title}'?") | ||||
|         builder.create().show() | ||||
|     } | ||||
| 
 | ||||
|     override fun onDestroyView() { | ||||
|         super.onDestroyView() | ||||
|         _binding = null | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								app/src/main/res/anim/from_left.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <set xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <translate android:fromXDelta="-100%" android:toXDelta="0%" android:duration="300"/> | ||||
| 
 | ||||
| </set> | ||||
							
								
								
									
										6
									
								
								app/src/main/res/anim/from_right.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <set xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <translate android:fromXDelta="100%" android:toXDelta="0%" android:duration="300"/> | ||||
| 
 | ||||
| </set> | ||||
							
								
								
									
										6
									
								
								app/src/main/res/anim/to_left.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <set xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <translate android:fromXDelta="0%" android:toXDelta="-100%" android:duration="300"/> | ||||
| 
 | ||||
| </set> | ||||
							
								
								
									
										6
									
								
								app/src/main/res/anim/to_right.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <set xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <translate android:fromXDelta="0%" android:toXDelta="100%" android:duration="300"/> | ||||
| 
 | ||||
| </set> | ||||
							
								
								
									
										30
									
								
								app/src/main/res/drawable-v24/ic_launcher_foreground.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,30 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:aapt="http://schemas.android.com/aapt" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportWidth="108" | ||||
|     android:viewportHeight="108"> | ||||
|     <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> | ||||
|         <aapt:attr name="android:fillColor"> | ||||
|             <gradient | ||||
|                 android:endX="85.84757" | ||||
|                 android:endY="92.4963" | ||||
|                 android:startX="42.9492" | ||||
|                 android:startY="49.59793" | ||||
|                 android:type="linear"> | ||||
|                 <item | ||||
|                     android:color="#44000000" | ||||
|                     android:offset="0.0" /> | ||||
|                 <item | ||||
|                     android:color="#00000000" | ||||
|                     android:offset="1.0" /> | ||||
|             </gradient> | ||||
|         </aapt:attr> | ||||
|     </path> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFF" | ||||
|         android:fillType="nonZero" | ||||
|         android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" | ||||
|         android:strokeWidth="1" | ||||
|         android:strokeColor="#00000000" /> | ||||
| </vector> | ||||
							
								
								
									
										20
									
								
								app/src/main/res/drawable/custom_input.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,20 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <selector xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <item android:state_enabled="true" android:state_focused="true"> | ||||
|         <shape android:shape="rectangle"> | ||||
|             <solid android:color="@color/white"/> | ||||
|             <stroke android:width="1dp" android:color="@color/colorPrimary"/> | ||||
|             <corners android:radius="5dp"/> | ||||
|         </shape> | ||||
|     </item> | ||||
| 
 | ||||
|     <item android:state_enabled="true"> | ||||
|         <shape android:shape="rectangle"> | ||||
|             <solid android:color="@color/white"/> | ||||
|             <stroke android:width="1dp" android:color="@color/lightGray"/> | ||||
|             <corners android:radius="5dp"/> | ||||
|         </shape> | ||||
|     </item> | ||||
| 
 | ||||
| </selector> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_add.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> | ||||
| </vector> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_check.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> | ||||
| </vector> | ||||
							
								
								
									
										170
									
								
								app/src/main/res/drawable/ic_launcher_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,170 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportWidth="108" | ||||
|     android:viewportHeight="108"> | ||||
|     <path | ||||
|         android:fillColor="#3DDC84" | ||||
|         android:pathData="M0,0h108v108h-108z" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M9,0L9,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,0L19,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,0L29,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,0L39,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,0L49,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,0L59,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,0L69,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,0L79,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M89,0L89,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M99,0L99,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,9L108,9" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,19L108,19" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,29L108,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,39L108,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,49L108,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,59L108,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,69L108,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,79L108,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,89L108,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,99L108,99" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,29L89,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,39L89,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,49L89,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,59L89,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,69L89,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,79L89,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,19L29,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,19L39,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,19L49,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,19L59,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,19L69,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,19L79,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
| </vector> | ||||
							
								
								
									
										9
									
								
								app/src/main/res/drawable/ic_no_data.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,9 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="146dp" | ||||
|     android:height="116dp" | ||||
|     android:viewportWidth="146" | ||||
|     android:viewportHeight="116"> | ||||
|   <path | ||||
|       android:fillColor="@color/lightGray" | ||||
|       android:pathData="M123.87,2.693A4.052,4.052 0,0 0,120.045 0L25.956,0a4.052,4.052 0,0 0,-3.826 2.693L0.23,64.613A3.993,3.993 0,0 0,0 65.948v46.024A4.042,4.042 0,0 0,4.056 116L141.945,116A4.042,4.042 0,0 0,146 111.972L146,65.948a3.994,3.994 0,0 0,-0.23 -1.335ZM9.78,61.916l19.049,-53.86h88.341l19.049,53.86Z"/> | ||||
| </vector> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_save.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/> | ||||
| </vector> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_search.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24" | ||||
|     android:tint="?attr/colorControlNormal"> | ||||
|   <path | ||||
|       android:fillColor="@android:color/white" | ||||
|       android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/> | ||||
| </vector> | ||||
							
								
								
									
										8
									
								
								app/src/main/res/drawable/item_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
| 
 | ||||
|     <solid android:color="@color/white"/> | ||||
|     <stroke android:width="1dp" android:color="@color/lightGray"/> | ||||
|     <corners android:radius="16dp"/> | ||||
| 
 | ||||
| </shape> | ||||
							
								
								
									
										21
									
								
								app/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     tools:context=".MainActivity"> | ||||
| 
 | ||||
|     <fragment | ||||
|         android:id="@+id/navHostFragment" | ||||
|         android:name="androidx.navigation.fragment.NavHostFragment" | ||||
|         android:layout_width="409dp" | ||||
|         android:layout_height="729dp" | ||||
|         app:defaultNavHost="true" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintHorizontal_bias="0.5" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         app:navGraph="@navigation/my_nav" /> | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
							
								
								
									
										58
									
								
								app/src/main/res/layout/fragment_add.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,58 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:padding="24dp" | ||||
|     tools:context=".fragments.add.AddFragment"> | ||||
| 
 | ||||
| 
 | ||||
|     <EditText | ||||
|         android:id="@+id/title_et" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="60dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:ems="10" | ||||
|         android:hint="@string/title" | ||||
|         android:inputType="textPersonName" | ||||
|         android:paddingStart="24dp" | ||||
|         android:paddingEnd="24dp" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintHorizontal_bias="0.5" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|     <Spinner | ||||
|         android:id="@+id/priorities_spinner" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="60dp" | ||||
|         android:layout_marginTop="8dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:entries="@array/priorities" | ||||
|         android:paddingStart="20dp" | ||||
|         android:paddingEnd="20dp" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintHorizontal_bias="0.5" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/title_et" /> | ||||
| 
 | ||||
|     <EditText | ||||
|         android:id="@+id/description_et" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_marginTop="8dp" | ||||
|         android:background="@android:color/transparent" | ||||
|         android:ems="10" | ||||
|         android:gravity="top|start" | ||||
|         android:hint="@string/description" | ||||
|         android:inputType="textMultiLine" | ||||
|         android:paddingStart="24dp" | ||||
|         android:paddingTop="16dp" | ||||
|         android:paddingEnd="24dp" | ||||
|         app:layout_constraintBottom_toBottomOf="parent" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintHorizontal_bias="0.5" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/priorities_spinner" /> | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
							
								
								
									
										72
									
								
								app/src/main/res/layout/fragment_list.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,72 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools"> | ||||
| 
 | ||||
|     <data> | ||||
|         <variable | ||||
|             name="mSharedViewModel" | ||||
|             type="com.example.todoapp.fragments.SharedViewModel" /> | ||||
|     </data> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:id="@+id/listLayout" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         tools:context=".fragments.list.ListFragment"> | ||||
| 
 | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:id="@+id/recyclerView" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="0dp" | ||||
|             android:clipToPadding="false" | ||||
|             android:paddingTop="8dp" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.5" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|         <com.google.android.material.floatingactionbutton.FloatingActionButton | ||||
|             android:id="@+id/floatingActionButton" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginEnd="24dp" | ||||
|             android:layout_marginBottom="24dp" | ||||
|             android:clickable="true" | ||||
|             android:focusable="true" | ||||
|             android:navigateToAddFragment="@{true}" | ||||
|             android:src="@drawable/ic_add" | ||||
|             android:tint="@color/white" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" /> | ||||
| 
 | ||||
|         <ImageView | ||||
|             android:id="@+id/no_data_imageView" | ||||
|             android:layout_width="100dp" | ||||
|             android:layout_height="100dp" | ||||
|             android:emptyDatabase="@{mSharedViewModel.emptyDatabase}" | ||||
|             android:src="@drawable/ic_no_data" | ||||
|             android:visibility="invisible" | ||||
|             app:layout_constraintBottom_toBottomOf="@+id/recyclerView" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toStartOf="@+id/recyclerView" | ||||
|             app:layout_constraintTop_toTopOf="@+id/recyclerView" | ||||
|             app:layout_constraintVertical_bias="0.37" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/no_data_textView" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_marginTop="12dp" | ||||
|             android:alpha="0.5" | ||||
|             android:emptyDatabase="@{mSharedViewModel.emptyDatabase}" | ||||
|             android:text="@string/no_data" | ||||
|             android:textSize="16sp" | ||||
|             android:visibility="invisible" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintStart_toStartOf="@+id/recyclerView" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/no_data_imageView" /> | ||||
| 
 | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| </layout> | ||||
							
								
								
									
										70
									
								
								app/src/main/res/layout/fragment_update.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,70 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools"> | ||||
| 
 | ||||
|     <data> | ||||
|         <variable | ||||
|             name="args" | ||||
|             type="com.example.todoapp.fragments.update.UpdateFragmentArgs" /> | ||||
|     </data> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:padding="24dp" | ||||
|         tools:context=".fragments.update.UpdateFragment"> | ||||
| 
 | ||||
|         <EditText | ||||
|             android:id="@+id/current_title_et" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="60dp" | ||||
|             android:background="@drawable/custom_input" | ||||
|             android:ems="10" | ||||
|             android:hint="@string/title" | ||||
|             android:inputType="textPersonName" | ||||
|             android:paddingStart="24dp" | ||||
|             android:paddingEnd="24dp" | ||||
|             android:text="@{args.currentItem.title}" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.5" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|         <Spinner | ||||
|             android:id="@+id/current_priorities_spinner" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="60dp" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:background="@drawable/custom_input" | ||||
|             android:entries="@array/priorities" | ||||
|             android:paddingStart="20dp" | ||||
|             android:paddingEnd="20dp" | ||||
|             android:parsePriorityToInt="@{args.currentItem.priority}" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.5" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/current_title_et" /> | ||||
| 
 | ||||
|         <EditText | ||||
|             android:id="@+id/current_description_et" | ||||
|             android:layout_width="0dp" | ||||
|             android:layout_height="0dp" | ||||
|             android:layout_marginTop="8dp" | ||||
|             android:background="@drawable/custom_input" | ||||
|             android:ems="10" | ||||
|             android:gravity="top|start" | ||||
|             android:hint="@string/description" | ||||
|             android:inputType="textMultiLine" | ||||
|             android:paddingStart="24dp" | ||||
|             android:paddingTop="16dp" | ||||
|             android:paddingEnd="24dp" | ||||
|             android:text="@{args.currentItem.description}" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.5" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toBottomOf="@+id/current_priorities_spinner" /> | ||||
| 
 | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| </layout> | ||||
							
								
								
									
										75
									
								
								app/src/main/res/layout/row_layout.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,75 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools"> | ||||
| 
 | ||||
|     <data> | ||||
|         <variable | ||||
|             name="toDoData" | ||||
|             type="com.example.todoapp.data.models.ToDoData" /> | ||||
|     </data> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_margin="4dp"> | ||||
| 
 | ||||
|         <androidx.constraintlayout.widget.ConstraintLayout | ||||
|             android:id="@+id/row_background" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:background="@drawable/item_background" | ||||
|             android:sendDataToUpdateFragment="@{toDoData}" | ||||
|             app:layout_constraintBottom_toBottomOf="parent" | ||||
|             app:layout_constraintEnd_toEndOf="parent" | ||||
|             app:layout_constraintHorizontal_bias="0.5" | ||||
|             app:layout_constraintStart_toStartOf="parent" | ||||
|             app:layout_constraintTop_toTopOf="parent"> | ||||
| 
 | ||||
|             <androidx.cardview.widget.CardView | ||||
|                 android:id="@+id/priority_indicator" | ||||
|                 android:layout_width="16dp" | ||||
|                 android:layout_height="16dp" | ||||
|                 android:layout_marginTop="16dp" | ||||
|                 android:layout_marginEnd="16dp" | ||||
|                 android:parsePriorityColor="@{toDoData.priority}" | ||||
|                 app:cardBackgroundColor="@color/red" | ||||
|                 app:cardCornerRadius="100dp" | ||||
|                 app:layout_constraintEnd_toEndOf="parent" | ||||
|                 app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@+id/title_txt" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginStart="20dp" | ||||
|                 android:layout_marginTop="16dp" | ||||
|                 android:maxLength="20" | ||||
|                 android:text="@{toDoData.title}" | ||||
|                 android:textColor="@color/darkGray" | ||||
|                 android:textSize="20sp" | ||||
|                 android:textStyle="bold" | ||||
|                 app:layout_constraintStart_toStartOf="parent" | ||||
|                 app:layout_constraintTop_toTopOf="parent" /> | ||||
| 
 | ||||
|             <TextView | ||||
|                 android:id="@+id/description_txt" | ||||
|                 android:layout_width="0dp" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginTop="8dp" | ||||
|                 android:layout_marginEnd="16dp" | ||||
|                 android:layout_marginBottom="16dp" | ||||
|                 android:maxLength="300" | ||||
|                 android:maxLines="10" | ||||
|                 android:text="@{toDoData.description}" | ||||
|                 android:textColor="@color/darkGray" | ||||
|                 app:layout_constraintBottom_toBottomOf="parent" | ||||
|                 app:layout_constraintEnd_toEndOf="parent" | ||||
|                 app:layout_constraintHorizontal_bias="0.0" | ||||
|                 app:layout_constraintStart_toStartOf="@+id/title_txt" | ||||
|                 app:layout_constraintTop_toBottomOf="@+id/title_txt" | ||||
|                 app:layout_constraintVertical_bias="0.0" /> | ||||
| 
 | ||||
|         </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| </layout> | ||||
							
								
								
									
										13
									
								
								app/src/main/res/menu/add_fragment_menu.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,13 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/menu_add" | ||||
|         android:title="@string/add" | ||||
|         android:icon="@drawable/ic_check" | ||||
|         android:iconTint="@color/white" | ||||
|         app:showAsAction="ifRoom"/> | ||||
| 
 | ||||
| 
 | ||||
| </menu> | ||||
							
								
								
									
										33
									
								
								app/src/main/res/menu/list_fragment_menu.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,33 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/menu_search" | ||||
|         android:title="@string/search" | ||||
|         android:icon="@drawable/ic_search" | ||||
|         android:iconTint="@color/white" | ||||
|         app:showAsAction="ifRoom" | ||||
|         app:actionViewClass="androidx.appcompat.widget.SearchView"/> | ||||
| 
 | ||||
|     <group android:checkableBehavior="single"> | ||||
|         <item | ||||
|             android:id="@+id/menu_sortBy" | ||||
|             android:title="@string/sort_by"> | ||||
|             <menu> | ||||
|                 <item | ||||
|                     android:id="@+id/menu_priority_high" | ||||
|                     android:title="@string/priority_high"/> | ||||
|                 <item | ||||
|                     android:id="@+id/menu_priority_low" | ||||
|                     android:title="@string/priority_low"/> | ||||
|             </menu> | ||||
|         </item> | ||||
|     </group> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/menu_delete_all" | ||||
|         android:title="@string/delete_all" | ||||
|         app:showAsAction="never"/> | ||||
| 
 | ||||
| </menu> | ||||
							
								
								
									
										17
									
								
								app/src/main/res/menu/update_fragment_menu.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,17 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/menu_save" | ||||
|         android:title="@string/save" | ||||
|         android:icon="@drawable/ic_save" | ||||
|         android:iconTint="@color/white" | ||||
|         app:showAsAction="ifRoom"/> | ||||
| 
 | ||||
|     <item | ||||
|         android:id="@+id/menu_delete" | ||||
|         android:title="@string/delete" | ||||
|         app:showAsAction="never"/> | ||||
| 
 | ||||
| </menu> | ||||
							
								
								
									
										5
									
								
								app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <background android:drawable="@drawable/ic_launcher_background" /> | ||||
|     <foreground android:drawable="@drawable/ic_launcher_foreground" /> | ||||
| </adaptive-icon> | ||||
							
								
								
									
										5
									
								
								app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <background android:drawable="@drawable/ic_launcher_background" /> | ||||
|     <foreground android:drawable="@drawable/ic_launcher_foreground" /> | ||||
| </adaptive-icon> | ||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-hdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-hdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-mdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-mdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 10 KiB | 
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										53
									
								
								app/src/main/res/navigation/my_nav.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,53 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <navigation xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:id="@+id/my_nav" | ||||
|     app:startDestination="@id/listFragment"> | ||||
| 
 | ||||
|     <fragment | ||||
|         android:id="@+id/listFragment" | ||||
|         android:name="com.example.todoapp.fragments.list.ListFragment" | ||||
|         android:label="ToDo List" | ||||
|         tools:layout="@layout/fragment_list" > | ||||
|         <action | ||||
|             android:id="@+id/action_listFragment_to_addFragment" | ||||
|             app:destination="@id/addFragment" | ||||
|             app:enterAnim="@anim/from_right" | ||||
|             app:exitAnim="@anim/to_left" | ||||
|             app:popEnterAnim="@anim/from_left" | ||||
|             app:popExitAnim="@anim/to_right" /> | ||||
|         <action | ||||
|             android:id="@+id/action_listFragment_to_updateFragment" | ||||
|             app:destination="@id/updateFragment" | ||||
|             app:enterAnim="@anim/from_left" | ||||
|             app:exitAnim="@anim/to_right" | ||||
|             app:popEnterAnim="@anim/from_right" | ||||
|             app:popExitAnim="@anim/to_left" /> | ||||
|     </fragment> | ||||
|     <fragment | ||||
|         android:id="@+id/addFragment" | ||||
|         android:name="com.example.todoapp.fragments.add.AddFragment" | ||||
|         android:label="Add" | ||||
|         tools:layout="@layout/fragment_add" > | ||||
|         <action | ||||
|             android:id="@+id/action_addFragment_to_listFragment" | ||||
|             app:destination="@id/listFragment" | ||||
|             app:enterAnim="@anim/from_left" | ||||
|             app:exitAnim="@anim/to_right" /> | ||||
|     </fragment> | ||||
|     <fragment | ||||
|         android:id="@+id/updateFragment" | ||||
|         android:name="com.example.todoapp.fragments.update.UpdateFragment" | ||||
|         android:label="Update" | ||||
|         tools:layout="@layout/fragment_update" > | ||||
|         <action | ||||
|             android:id="@+id/action_updateFragment_to_listFragment" | ||||
|             app:destination="@id/listFragment" | ||||
|             app:enterAnim="@anim/from_right" | ||||
|             app:exitAnim="@anim/to_left" /> | ||||
|         <argument | ||||
|             android:name="currentItem" | ||||
|             app:argType="com.example.todoapp.data.models.ToDoData" /> | ||||
|     </fragment> | ||||
| </navigation> | ||||
							
								
								
									
										13
									
								
								app/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,13 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="colorPrimary">#6200EA</color> | ||||
|     <color name="colorPrimaryDark">#5502C8</color> | ||||
|     <color name="colorAccent">#9D46FF</color> | ||||
| 
 | ||||
|     <color name="white">#FFFFFF</color> | ||||
|     <color name="lightGray">#E6E6E6</color> | ||||
|     <color name="darkGray">#4B4B4B</color> | ||||
|     <color name="red">#FF4646</color> | ||||
|     <color name="yellow">#FFC114</color> | ||||
|     <color name="green">#00C980</color> | ||||
| </resources> | ||||
							
								
								
									
										22
									
								
								app/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,22 @@ | ||||
| <resources> | ||||
|     <string name="app_name">ToDo App</string> | ||||
|     <string name="hello_blank_fragment">Hello blank fragment</string> | ||||
|     <string name="no_data">No Data</string> | ||||
| 
 | ||||
|     <string name="title">Title</string> | ||||
|     <string name="description">Description</string> | ||||
|     <string name="search">Search</string> | ||||
|     <string name="sort_by">Sort By</string> | ||||
|     <string name="priority_high">Priority High</string> | ||||
|     <string name="priority_low">Priority Low</string> | ||||
|     <string name="delete_all">Delete All</string> | ||||
|     <string name="add">Add</string> | ||||
|     <string name="save">Save</string> | ||||
|     <string name="delete">Delete</string> | ||||
| 
 | ||||
|     <string-array name="priorities"> | ||||
|         <item>High Priority</item> | ||||
|         <item>Medium Priority</item> | ||||
|         <item>Low Priority</item> | ||||
|     </string-array> | ||||
| </resources> | ||||
							
								
								
									
										10
									
								
								app/src/main/res/values/styles.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,10 @@ | ||||
| <resources> | ||||
|     <!-- Base application theme. --> | ||||
|     <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | ||||
|         <!-- Customize your theme here. --> | ||||
|         <item name="colorPrimary">@color/colorPrimary</item> | ||||
|         <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ||||
|         <item name="colorAccent">@color/colorAccent</item> | ||||
|     </style> | ||||
| 
 | ||||
| </resources> | ||||
							
								
								
									
										17
									
								
								app/src/test/java/com/example/todoapp/ExampleUnitTest.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,17 @@ | ||||
| package com.example.todoapp | ||||
| 
 | ||||
| import org.junit.Test | ||||
| 
 | ||||
| import org.junit.Assert.* | ||||
| 
 | ||||
| /** | ||||
|  * Example local unit test, which will execute on the development machine (host). | ||||
|  * | ||||
|  * See [testing documentation](http://d.android.com/tools/testing). | ||||
|  */ | ||||
| class ExampleUnitTest { | ||||
|     @Test | ||||
|     fun addition_isCorrect() { | ||||
|         assertEquals(4, 2 + 2) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										32
									
								
								build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,32 @@ | ||||
| // Top-level build file where you can add configuration options common to all sub-projects/modules. | ||||
| buildscript { | ||||
| 
 | ||||
|     ext { | ||||
|         kotlin_version = '1.3.72' | ||||
|         nav_version = "2.3.0-beta01" | ||||
|     } | ||||
| 
 | ||||
|     repositories { | ||||
|         google() | ||||
|         jcenter() | ||||
|     } | ||||
|     dependencies { | ||||
|         classpath "com.android.tools.build:gradle:4.0.0" | ||||
| 
 | ||||
|         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||||
|         classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" | ||||
|         // NOTE: Do not place your application dependencies here; they belong | ||||
|         // in the individual module build.gradle files | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| allprojects { | ||||
|     repositories { | ||||
|         google() | ||||
|         jcenter() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| task clean(type: Delete) { | ||||
|     delete rootProject.buildDir | ||||
| } | ||||
							
								
								
									
										21
									
								
								gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| # Project-wide Gradle settings. | ||||
| # IDE (e.g. Android Studio) users: | ||||
| # Gradle settings configured through the IDE *will override* | ||||
| # any settings specified in this file. | ||||
| # For more details on how to configure your build environment visit | ||||
| # http://www.gradle.org/docs/current/userguide/build_environment.html | ||||
| # Specifies the JVM arguments used for the daemon process. | ||||
| # The setting is particularly useful for tweaking memory settings. | ||||
| org.gradle.jvmargs=-Xmx2048m | ||||
| # When configured, Gradle will run in incubating parallel mode. | ||||
| # This option should only be used with decoupled projects. More details, visit | ||||
| # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | ||||
| # org.gradle.parallel=true | ||||
| # AndroidX package structure to make it clearer which packages are bundled with the | ||||
| # Android operating system, and which are packaged with your app"s APK | ||||
| # https://developer.android.com/topic/libraries/support-library/androidx-rn | ||||
| android.useAndroidX=true | ||||
| # Automatically convert third-party libraries to use AndroidX | ||||
| android.enableJetifier=true | ||||
| # Kotlin code style for this project: "official" or "obsolete": | ||||
| kotlin.code.style=official | ||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										6
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,6 @@ | ||||
| #Fri Jun 26 09:49:12 CEST 2020 | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip | ||||
							
								
								
									
										172
									
								
								gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,172 @@ | ||||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| ############################################################################## | ||||
| ## | ||||
| ##  Gradle start up script for UN*X | ||||
| ## | ||||
| ############################################################################## | ||||
| 
 | ||||
| # Attempt to set APP_HOME | ||||
| # Resolve links: $0 may be a link | ||||
| PRG="$0" | ||||
| # Need this for relative symlinks. | ||||
| while [ -h "$PRG" ] ; do | ||||
|     ls=`ls -ld "$PRG"` | ||||
|     link=`expr "$ls" : '.*-> \(.*\)$'` | ||||
|     if expr "$link" : '/.*' > /dev/null; then | ||||
|         PRG="$link" | ||||
|     else | ||||
|         PRG=`dirname "$PRG"`"/$link" | ||||
|     fi | ||||
| done | ||||
| SAVED="`pwd`" | ||||
| cd "`dirname \"$PRG\"`/" >/dev/null | ||||
| APP_HOME="`pwd -P`" | ||||
| cd "$SAVED" >/dev/null | ||||
| 
 | ||||
| APP_NAME="Gradle" | ||||
| APP_BASE_NAME=`basename "$0"` | ||||
| 
 | ||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| DEFAULT_JVM_OPTS="" | ||||
| 
 | ||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||
| MAX_FD="maximum" | ||||
| 
 | ||||
| warn () { | ||||
|     echo "$*" | ||||
| } | ||||
| 
 | ||||
| die () { | ||||
|     echo | ||||
|     echo "$*" | ||||
|     echo | ||||
|     exit 1 | ||||
| } | ||||
| 
 | ||||
| # OS specific support (must be 'true' or 'false'). | ||||
| cygwin=false | ||||
| msys=false | ||||
| darwin=false | ||||
| nonstop=false | ||||
| case "`uname`" in | ||||
|   CYGWIN* ) | ||||
|     cygwin=true | ||||
|     ;; | ||||
|   Darwin* ) | ||||
|     darwin=true | ||||
|     ;; | ||||
|   MINGW* ) | ||||
|     msys=true | ||||
|     ;; | ||||
|   NONSTOP* ) | ||||
|     nonstop=true | ||||
|     ;; | ||||
| esac | ||||
| 
 | ||||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||||
| 
 | ||||
| # Determine the Java command to use to start the JVM. | ||||
| if [ -n "$JAVA_HOME" ] ; then | ||||
|     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||||
|         # IBM's JDK on AIX uses strange locations for the executables | ||||
|         JAVACMD="$JAVA_HOME/jre/sh/java" | ||||
|     else | ||||
|         JAVACMD="$JAVA_HOME/bin/java" | ||||
|     fi | ||||
|     if [ ! -x "$JAVACMD" ] ; then | ||||
|         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||||
| 
 | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
|     fi | ||||
| else | ||||
|     JAVACMD="java" | ||||
|     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| 
 | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
| fi | ||||
| 
 | ||||
| # Increase the maximum file descriptors if we can. | ||||
| if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | ||||
|     MAX_FD_LIMIT=`ulimit -H -n` | ||||
|     if [ $? -eq 0 ] ; then | ||||
|         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | ||||
|             MAX_FD="$MAX_FD_LIMIT" | ||||
|         fi | ||||
|         ulimit -n $MAX_FD | ||||
|         if [ $? -ne 0 ] ; then | ||||
|             warn "Could not set maximum file descriptor limit: $MAX_FD" | ||||
|         fi | ||||
|     else | ||||
|         warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | ||||
|     fi | ||||
| fi | ||||
| 
 | ||||
| # For Darwin, add options to specify how the application appears in the dock | ||||
| if $darwin; then | ||||
|     GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | ||||
| fi | ||||
| 
 | ||||
| # For Cygwin, switch paths to Windows format before running java | ||||
| if $cygwin ; then | ||||
|     APP_HOME=`cygpath --path --mixed "$APP_HOME"` | ||||
|     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | ||||
|     JAVACMD=`cygpath --unix "$JAVACMD"` | ||||
| 
 | ||||
|     # We build the pattern for arguments to be converted via cygpath | ||||
|     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | ||||
|     SEP="" | ||||
|     for dir in $ROOTDIRSRAW ; do | ||||
|         ROOTDIRS="$ROOTDIRS$SEP$dir" | ||||
|         SEP="|" | ||||
|     done | ||||
|     OURCYGPATTERN="(^($ROOTDIRS))" | ||||
|     # Add a user-defined pattern to the cygpath arguments | ||||
|     if [ "$GRADLE_CYGPATTERN" != "" ] ; then | ||||
|         OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | ||||
|     fi | ||||
|     # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||||
|     i=0 | ||||
|     for arg in "$@" ; do | ||||
|         CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | ||||
|         CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option | ||||
| 
 | ||||
|         if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition | ||||
|             eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | ||||
|         else | ||||
|             eval `echo args$i`="\"$arg\"" | ||||
|         fi | ||||
|         i=$((i+1)) | ||||
|     done | ||||
|     case $i in | ||||
|         (0) set -- ;; | ||||
|         (1) set -- "$args0" ;; | ||||
|         (2) set -- "$args0" "$args1" ;; | ||||
|         (3) set -- "$args0" "$args1" "$args2" ;; | ||||
|         (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | ||||
|         (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | ||||
|         (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | ||||
|         (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | ||||
|         (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | ||||
|         (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | ||||
|     esac | ||||
| fi | ||||
| 
 | ||||
| # Escape application args | ||||
| save () { | ||||
|     for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | ||||
|     echo " " | ||||
| } | ||||
| APP_ARGS=$(save "$@") | ||||
| 
 | ||||
| # Collect all arguments for the java command, following the shell quoting and substitution rules | ||||
| eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | ||||
| 
 | ||||
| # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong | ||||
| if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then | ||||
|   cd "$(dirname "$0")" | ||||
| fi | ||||
| 
 | ||||
| exec "$JAVACMD" "$@" | ||||
							
								
								
									
										84
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,84 @@ | ||||
| @if "%DEBUG%" == "" @echo off | ||||
| @rem ########################################################################## | ||||
| @rem | ||||
| @rem  Gradle startup script for Windows | ||||
| @rem | ||||
| @rem ########################################################################## | ||||
| 
 | ||||
| @rem Set local scope for the variables with windows NT shell | ||||
| if "%OS%"=="Windows_NT" setlocal | ||||
| 
 | ||||
| set DIRNAME=%~dp0 | ||||
| if "%DIRNAME%" == "" set DIRNAME=. | ||||
| set APP_BASE_NAME=%~n0 | ||||
| set APP_HOME=%DIRNAME% | ||||
| 
 | ||||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| set DEFAULT_JVM_OPTS= | ||||
| 
 | ||||
| @rem Find java.exe | ||||
| if defined JAVA_HOME goto findJavaFromJavaHome | ||||
| 
 | ||||
| set JAVA_EXE=java.exe | ||||
| %JAVA_EXE% -version >NUL 2>&1 | ||||
| if "%ERRORLEVEL%" == "0" goto init | ||||
| 
 | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
| 
 | ||||
| goto fail | ||||
| 
 | ||||
| :findJavaFromJavaHome | ||||
| set JAVA_HOME=%JAVA_HOME:"=% | ||||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||
| 
 | ||||
| if exist "%JAVA_EXE%" goto init | ||||
| 
 | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
| 
 | ||||
| goto fail | ||||
| 
 | ||||
| :init | ||||
| @rem Get command-line arguments, handling Windows variants | ||||
| 
 | ||||
| if not "%OS%" == "Windows_NT" goto win9xME_args | ||||
| 
 | ||||
| :win9xME_args | ||||
| @rem Slurp the command line arguments. | ||||
| set CMD_LINE_ARGS= | ||||
| set _SKIP=2 | ||||
| 
 | ||||
| :win9xME_args_slurp | ||||
| if "x%~1" == "x" goto execute | ||||
| 
 | ||||
| set CMD_LINE_ARGS=%* | ||||
| 
 | ||||
| :execute | ||||
| @rem Setup the command line | ||||
| 
 | ||||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||
| 
 | ||||
| @rem Execute Gradle | ||||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||||
| 
 | ||||
| :end | ||||
| @rem End local scope for the variables with windows NT shell | ||||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||||
| 
 | ||||
| :fail | ||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||
| rem the _cmd.exe /c_ return code! | ||||
| if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||
| exit /b 1 | ||||
| 
 | ||||
| :mainEnd | ||||
| if "%OS%"=="Windows_NT" endlocal | ||||
| 
 | ||||
| :omega | ||||
							
								
								
									
										2
									
								
								settings.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,2 @@ | ||||
| include ':app' | ||||
| rootProject.name = "ToDo App" | ||||