diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..c968170e --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +CleanNoteApp \ No newline at end of file diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 00000000..4a53bee8 --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index fb7f4a8a..b589d56e 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 00000000..165d9c32 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 00000000..8493627b --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 4e3844e8..ecd50f02 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,18 +1,19 @@ + diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..a269cb1a --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,22 @@ + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 00000000..5815a4a6 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 860da66a..0ad17cbd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,7 @@ - + + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 00000000..16660f1d --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/sonarlint/issuestore/4/9/49714c180cf12e6bb0fb0f86b8a2e6b52e75ed1d b/.idea/sonarlint/issuestore/4/9/49714c180cf12e6bb0fb0f86b8a2e6b52e75ed1d new file mode 100644 index 00000000..6f1e916c --- /dev/null +++ b/.idea/sonarlint/issuestore/4/9/49714c180cf12e6bb0fb0f86b8a2e6b52e75ed1d @@ -0,0 +1,2 @@ + +O kotlin:S1172"2Remove this unused function parameter "darkTheme".(áèžìûÿÿÿÿ \ No newline at end of file diff --git a/.idea/sonarlint/issuestore/5/d/5dd0036e6eaabc1cbb2545b80a0bfffc2708a45b b/.idea/sonarlint/issuestore/5/d/5dd0036e6eaabc1cbb2545b80a0bfffc2708a45b new file mode 100644 index 00000000..e69de29b diff --git a/.idea/sonarlint/issuestore/9/e/9ea6805d7eed655f05d5c8957775a6e66211bf8e b/.idea/sonarlint/issuestore/9/e/9ea6805d7eed655f05d5c8957775a6e66211bf8e new file mode 100644 index 00000000..e69de29b diff --git a/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 b/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 new file mode 100644 index 00000000..e69de29b diff --git a/.idea/sonarlint/issuestore/f/4/f4a01d6a4fcb971362ec00a83903fd3902f52164 b/.idea/sonarlint/issuestore/f/4/f4a01d6a4fcb971362ec00a83903fd3902f52164 new file mode 100644 index 00000000..e69de29b diff --git a/.idea/sonarlint/issuestore/index.pb b/.idea/sonarlint/issuestore/index.pb index e69de29b..003d1499 100644 --- a/.idea/sonarlint/issuestore/index.pb +++ b/.idea/sonarlint/issuestore/index.pb @@ -0,0 +1,11 @@ + +y +Iapp/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Shape.kt,9\e\9ea6805d7eed655f05d5c8957775a6e66211bf8e +@ +app/build.gradle,f\4\f4a01d6a4fcb971362ec00a83903fd3902f52164 +< + build.gradle,f\0\f07866736216be0ee2aba49e392191aeae700a35 +y +Iapp/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Theme.kt,4\9\49714c180cf12e6bb0fb0f86b8a2e6b52e75ed1d +y +Iapp/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Color.kt,5\d\5dd0036e6eaabc1cbb2545b80a0bfffc2708a45b \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..5fee77e4 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ + +# JetCleanNote + +App - Light | App-Dark | Add Note Screen +:-------------------------:|:-------------------------:|:-------------------------: +![](https://github.com/user-attachments/assets/f100b17d-3f61-4bb0-929f-e3f79ee46f89) | ![](https://github.com/user-attachments/assets/a3d0c267-af5d-4a08-9564-b8202dd3045c) | ![](https://github.com/user-attachments/assets/d6e5bb4c-965b-4c76-a747-65d2a6a1cb1a) diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 5ec04ab2..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,90 +0,0 @@ -plugins { - id 'com.android.application' - id 'kotlin-android' - id 'kotlin-kapt' - id 'dagger.hilt.android.plugin' -} - -android { - compileSdk 31 - - defaultConfig { - applicationId "com.plcoding.cleanarchitecturenoteapp" - minSdk 21 - targetSdk 31 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - vectorDrawables { - useSupportLibrary true - } - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - useIR = true - } - buildFeatures { - compose true - } - composeOptions { - kotlinCompilerExtensionVersion compose_version - kotlinCompilerVersion '1.5.21' - } - packagingOptions { - resources { - excludes += '/META-INF/{AL2.0,LGPL2.1}' - } - } -} - -dependencies { - - implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.1' - implementation 'com.google.android.material:material:1.4.0' - implementation "androidx.compose.ui:ui:$compose_version" - implementation "androidx.compose.material:material:$compose_version" - implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1' - implementation 'androidx.activity:activity-compose:1.3.1' - testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" - debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" - - // Compose dependencies - implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0-beta01" - implementation "androidx.navigation:navigation-compose:2.4.0-alpha09" - implementation "androidx.compose.material:material-icons-extended:$compose_version" - implementation "androidx.hilt:hilt-navigation-compose:1.0.0-alpha03" - - // Coroutines - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1' - - //Dagger - Hilt - implementation "com.google.dagger:hilt-android:2.38.1" - kapt "com.google.dagger:hilt-android-compiler:2.37" - implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03" - kapt "androidx.hilt:hilt-compiler:1.0.0" - - // Room - implementation "androidx.room:room-runtime:2.3.0" - kapt "androidx.room:room-compiler:2.3.0" - - // Kotlin Extensions and Coroutines support for Room - implementation "androidx.room:room-ktx:2.3.0" -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..bc76a4f2 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,85 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + id("com.google.devtools.ksp") + id("com.google.dagger.hilt.android") +} + +android { + namespace = "com.ibrahimcanerdogan.cleannote" + compileSdk = 35 + + defaultConfig { + applicationId = "com.ibrahimcanerdogan.cleannote" + minSdk = 24 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) + + // Compose dependencies + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.1") + implementation("androidx.navigation:navigation-compose:2.9.0") + implementation("androidx.compose.material:material-icons-extended:1.7.8") + implementation("androidx.hilt:hilt-navigation-compose:1.2.0") + + // Coroutines + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") + + //Dagger - Hilt + implementation("com.google.dagger:hilt-android:2.49") + ksp("com.google.dagger:hilt-android-compiler:2.49") + ksp("androidx.hilt:hilt-compiler:1.0.0") + + // Room + implementation("androidx.room:room-runtime:2.7.1") + ksp("androidx.room:room-compiler:2.7.1") + implementation("androidx.room:room-ktx:2.7.1") + + // Splash Screen + implementation("androidx.core:core-splashscreen:1.0.0") + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb434..ff59496d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/app/src/androidTest/java/com/plcoding/cleanarchitecturenoteapp/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/ibrahimcanerdogan/cleannote/ExampleInstrumentedTest.kt similarity index 81% rename from app/src/androidTest/java/com/plcoding/cleanarchitecturenoteapp/ExampleInstrumentedTest.kt rename to app/src/androidTest/java/com/ibrahimcanerdogan/cleannote/ExampleInstrumentedTest.kt index 19411d6c..d0b17737 100644 --- a/app/src/androidTest/java/com/plcoding/cleanarchitecturenoteapp/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/ibrahimcanerdogan/cleannote/ExampleInstrumentedTest.kt @@ -1,4 +1,4 @@ -package com.plcoding.cleanarchitecturenoteapp +package com.ibrahimcanerdogan.cleannote import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -19,6 +19,6 @@ class ExampleInstrumentedTest { fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.plcoding.cleanarchitecturenoteapp", appContext.packageName) + assertEquals("com.ibrahimcanerdogan.cleannote", appContext.packageName) } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 052e8301..d365a59a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,19 +1,20 @@ + package="com.ibrahimcanerdogan.cleannote"> + android:theme="@style/Theme.CleanNoteApp"> + android:theme="@style/Theme.CleanNoteApp"> diff --git a/app/src/main/icon_launcher-playstore.png b/app/src/main/icon_launcher-playstore.png new file mode 100644 index 00000000..94d62423 Binary files /dev/null and b/app/src/main/icon_launcher-playstore.png differ diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/MainActivity.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/MainActivity.kt new file mode 100644 index 00000000..69e0cccc --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/MainActivity.kt @@ -0,0 +1,29 @@ +package com.ibrahimcanerdogan.cleannote + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.material3.Surface +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import com.ibrahimcanerdogan.cleannote.ui.navigation.NoteNavigation +import com.ibrahimcanerdogan.cleannote.ui.theme.CleanNoteAppTheme +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + @ExperimentalAnimationApi + override fun onCreate(savedInstanceState: Bundle?) { + installSplashScreen() + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + CleanNoteAppTheme { + Surface { + NoteNavigation() + } + } + } + } +} diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/NoteApp.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/NoteApp.kt new file mode 100644 index 00000000..47d5733f --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/NoteApp.kt @@ -0,0 +1,7 @@ +package com.ibrahimcanerdogan.cleannote + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class NoteApp : Application() \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/database/NoteDao.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/database/NoteDao.kt new file mode 100644 index 00000000..f37e20a4 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/database/NoteDao.kt @@ -0,0 +1,21 @@ +package com.ibrahimcanerdogan.cleannote.data.database + +import androidx.room.* +import com.ibrahimcanerdogan.cleannote.data.model.Note +import kotlinx.coroutines.flow.Flow + +@Dao +interface NoteDao { + + @Query("SELECT * FROM note") + fun getAllNoteDatabase(): Flow> + + @Query("SELECT * FROM note WHERE id = :id") + suspend fun getSingleNoteDatabase(id: Int): Note? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertNoteDatabase(note: Note) + + @Delete + suspend fun deleteNoteDatabase(note: Note) +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/database/NoteDatabase.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/database/NoteDatabase.kt new file mode 100644 index 00000000..b850825c --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/database/NoteDatabase.kt @@ -0,0 +1,19 @@ +package com.ibrahimcanerdogan.cleannote.data.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.ibrahimcanerdogan.cleannote.data.model.Note + +@Database( + entities = [Note::class], + version = 1, + exportSchema = false +) +abstract class NoteDatabase: RoomDatabase() { + + abstract val noteDao: NoteDao + + companion object { + const val DATABASE_NAME = "notes_db" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/model/Note.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/model/Note.kt new file mode 100644 index 00000000..4ad952f3 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/model/Note.kt @@ -0,0 +1,20 @@ +package com.ibrahimcanerdogan.cleannote.data.model + +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.ibrahimcanerdogan.cleannote.ui.theme.* + +@Entity(tableName = "note") +data class Note( + val title: String, + val content: String, + val timestamp: Long, + val color: Int, + @PrimaryKey val id: Int? = null +) { + companion object { + val noteColors = listOf(RedOrange, LightGreen, Violet, BabyBlue, RedPink) + } +} + +class InvalidNoteException(message: String): Exception(message) \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/repository/NoteRepositoryImpl.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/repository/NoteRepositoryImpl.kt new file mode 100644 index 00000000..7f2f46f7 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/data/repository/NoteRepositoryImpl.kt @@ -0,0 +1,27 @@ +package com.ibrahimcanerdogan.cleannote.data.repository + +import com.ibrahimcanerdogan.cleannote.data.database.NoteDao +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import kotlinx.coroutines.flow.Flow + +class NoteRepositoryImpl( + private val noteDao: NoteDao +) : NoteRepository { + + override fun getAllNoteRepository(): Flow> { + return noteDao.getAllNoteDatabase() + } + + override suspend fun getSingleNoteRepository(id: Int): Note? { + return noteDao.getSingleNoteDatabase(id) + } + + override suspend fun insertNoteRepository(note: Note) { + noteDao.insertNoteDatabase(note) + } + + override suspend fun deleteNoteRepository(note: Note) { + noteDao.deleteNoteDatabase(note) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/DatabaseModule.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/DatabaseModule.kt new file mode 100644 index 00000000..8f3aafe6 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/DatabaseModule.kt @@ -0,0 +1,26 @@ +package com.ibrahimcanerdogan.cleannote.di + +import android.content.Context +import androidx.room.Room +import com.ibrahimcanerdogan.cleannote.data.database.NoteDatabase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DatabaseModule { + + @Provides + @Singleton + fun provideNoteDatabase(@ApplicationContext context: Context): NoteDatabase { + return Room.databaseBuilder( + context, + NoteDatabase::class.java, + NoteDatabase.DATABASE_NAME + ).build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/RepositoryModule.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/RepositoryModule.kt new file mode 100644 index 00000000..d7d8b933 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/RepositoryModule.kt @@ -0,0 +1,21 @@ +package com.ibrahimcanerdogan.cleannote.di + +import com.ibrahimcanerdogan.cleannote.data.database.NoteDatabase +import com.ibrahimcanerdogan.cleannote.data.repository.NoteRepositoryImpl +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object RepositoryModule { + + @Provides + @Singleton + fun provideNoteRepository(noteDatabase: NoteDatabase): NoteRepository { + return NoteRepositoryImpl(noteDatabase.noteDao) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/UseCaseModule.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/UseCaseModule.kt new file mode 100644 index 00000000..4965a76b --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/di/UseCaseModule.kt @@ -0,0 +1,29 @@ +package com.ibrahimcanerdogan.cleannote.di + +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import com.ibrahimcanerdogan.cleannote.domain.usecase.AddNote +import com.ibrahimcanerdogan.cleannote.domain.usecase.DeleteNote +import com.ibrahimcanerdogan.cleannote.domain.usecase.GetNote +import com.ibrahimcanerdogan.cleannote.domain.usecase.GetNotes +import com.ibrahimcanerdogan.cleannote.domain.usecase.NoteUseCase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object UseCaseModule { + + @Provides + @Singleton + fun provideNoteUseCases(repository: NoteRepository): NoteUseCase { + return NoteUseCase( + getNotes = GetNotes(repository), + deleteNote = DeleteNote(repository), + addNote = AddNote(repository), + getNote = GetNote(repository) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/repository/NoteRepository.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/repository/NoteRepository.kt new file mode 100644 index 00000000..1ac7b8b6 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/repository/NoteRepository.kt @@ -0,0 +1,15 @@ +package com.ibrahimcanerdogan.cleannote.domain.repository + +import com.ibrahimcanerdogan.cleannote.data.model.Note +import kotlinx.coroutines.flow.Flow + +interface NoteRepository { + + fun getAllNoteRepository(): Flow> + + suspend fun getSingleNoteRepository(id: Int): Note? + + suspend fun insertNoteRepository(note: Note) + + suspend fun deleteNoteRepository(note: Note) +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/AddNote.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/AddNote.kt new file mode 100644 index 00000000..a296ee49 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/AddNote.kt @@ -0,0 +1,22 @@ +package com.ibrahimcanerdogan.cleannote.domain.usecase + +import com.ibrahimcanerdogan.cleannote.data.model.InvalidNoteException +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import javax.inject.Inject + +class AddNote @Inject constructor( + private val repository: NoteRepository +) { + + @Throws(InvalidNoteException::class) + suspend operator fun invoke(note: Note) { + if(note.title.isBlank()) { + throw InvalidNoteException("The title of the note can't be empty.") + } + if(note.content.isBlank()) { + throw InvalidNoteException("The content of the note can't be empty.") + } + repository.insertNoteRepository(note) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/DeleteNote.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/DeleteNote.kt new file mode 100644 index 00000000..67f7c626 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/DeleteNote.kt @@ -0,0 +1,14 @@ +package com.ibrahimcanerdogan.cleannote.domain.usecase + +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import javax.inject.Inject + +class DeleteNote @Inject constructor( + private val repository: NoteRepository +) { + + suspend operator fun invoke(note: Note) { + repository.deleteNoteRepository(note) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/GetNote.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/GetNote.kt new file mode 100644 index 00000000..e6fb60b2 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/GetNote.kt @@ -0,0 +1,14 @@ +package com.ibrahimcanerdogan.cleannote.domain.usecase + +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import javax.inject.Inject + +class GetNote @Inject constructor( + private val repository: NoteRepository +) { + + suspend operator fun invoke(id: Int): Note? { + return repository.getSingleNoteRepository(id) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/GetNotes.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/GetNotes.kt new file mode 100644 index 00000000..1f34bb9e --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/GetNotes.kt @@ -0,0 +1,37 @@ +package com.ibrahimcanerdogan.cleannote.domain.usecase + +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.repository.NoteRepository +import com.ibrahimcanerdogan.cleannote.domain.util.NoteOrder +import com.ibrahimcanerdogan.cleannote.domain.util.OrderType +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class GetNotes @Inject constructor( + private val repository: NoteRepository +) { + + operator fun invoke( + noteOrder: NoteOrder = NoteOrder.Date(OrderType.Descending) + ): Flow> { + return repository.getAllNoteRepository().map { notes -> + when(noteOrder.orderType) { + is OrderType.Ascending -> { + when(noteOrder) { + is NoteOrder.Title -> notes.sortedBy { it.title.lowercase() } + is NoteOrder.Date -> notes.sortedBy { it.timestamp } + is NoteOrder.Color -> notes.sortedBy { it.color } + } + } + is OrderType.Descending -> { + when(noteOrder) { + is NoteOrder.Title -> notes.sortedByDescending { it.title.lowercase() } + is NoteOrder.Date -> notes.sortedByDescending { it.timestamp } + is NoteOrder.Color -> notes.sortedByDescending { it.color } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/NoteUseCase.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/NoteUseCase.kt new file mode 100644 index 00000000..99cd5608 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/usecase/NoteUseCase.kt @@ -0,0 +1,8 @@ +package com.ibrahimcanerdogan.cleannote.domain.usecase + +data class NoteUseCase( + val getNotes: GetNotes, + val deleteNote: DeleteNote, + val addNote: AddNote, + val getNote: GetNote +) diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/util/NoteOrder.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/util/NoteOrder.kt new file mode 100644 index 00000000..732abe55 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/util/NoteOrder.kt @@ -0,0 +1,15 @@ +package com.ibrahimcanerdogan.cleannote.domain.util + +sealed class NoteOrder(val orderType: OrderType) { + class Title(orderType: OrderType): NoteOrder(orderType) + class Date(orderType: OrderType): NoteOrder(orderType) + class Color(orderType: OrderType): NoteOrder(orderType) + + fun copy(orderType: OrderType): NoteOrder { + return when(this) { + is Title -> Title(orderType) + is Date -> Date(orderType) + is Color -> Color(orderType) + } + } +} diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/util/OrderType.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/util/OrderType.kt new file mode 100644 index 00000000..6fdc0e83 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/domain/util/OrderType.kt @@ -0,0 +1,6 @@ +package com.ibrahimcanerdogan.cleannote.domain.util + +sealed class OrderType { + data object Ascending: OrderType() + data object Descending: OrderType() +} diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/DefaultRadioButton.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/DefaultRadioButton.kt new file mode 100644 index 00000000..ed94208b --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/DefaultRadioButton.kt @@ -0,0 +1,37 @@ +package com.ibrahimcanerdogan.cleannote.ui.component + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.material3.RadioButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun DefaultRadioButton( + text: String, + selected: Boolean, + onSelect: () -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically + ) { + RadioButton( + selected = selected, + onClick = onSelect, + colors = RadioButtonDefaults.colors( + selectedColor = MaterialTheme.colorScheme.primary, + unselectedColor = MaterialTheme.colorScheme.onBackground + ) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = text, style = MaterialTheme.typography.bodyLarge) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/OrderSection.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/OrderSection.kt new file mode 100644 index 00000000..e05fbd6f --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/OrderSection.kt @@ -0,0 +1,61 @@ +package com.ibrahimcanerdogan.cleannote.ui.component + +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.ibrahimcanerdogan.cleannote.domain.util.NoteOrder +import com.ibrahimcanerdogan.cleannote.domain.util.OrderType + +@Composable +fun OrderSection( + modifier: Modifier = Modifier, + noteOrder: NoteOrder = NoteOrder.Date(OrderType.Descending), + onOrderChange: (NoteOrder) -> Unit +) { + Column( + modifier = modifier + ) { + Row( + modifier = Modifier.fillMaxWidth() + ) { + DefaultRadioButton( + text = "Title", + selected = noteOrder is NoteOrder.Title, + onSelect = { onOrderChange(NoteOrder.Title(noteOrder.orderType)) } + ) + Spacer(modifier = Modifier.width(8.dp)) + DefaultRadioButton( + text = "Date", + selected = noteOrder is NoteOrder.Date, + onSelect = { onOrderChange(NoteOrder.Date(noteOrder.orderType)) } + ) + Spacer(modifier = Modifier.width(8.dp)) + DefaultRadioButton( + text = "Color", + selected = noteOrder is NoteOrder.Color, + onSelect = { onOrderChange(NoteOrder.Color(noteOrder.orderType)) } + ) + } + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth() + ) { + DefaultRadioButton( + text = "Ascending", + selected = noteOrder.orderType is OrderType.Ascending, + onSelect = { + onOrderChange(noteOrder.copy(OrderType.Ascending)) + } + ) + Spacer(modifier = Modifier.width(8.dp)) + DefaultRadioButton( + text = "Descending", + selected = noteOrder.orderType is OrderType.Descending, + onSelect = { + onOrderChange(noteOrder.copy(OrderType.Descending)) + } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/TransparentHintTextField.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/TransparentHintTextField.kt new file mode 100644 index 00000000..a0888f60 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/component/TransparentHintTextField.kt @@ -0,0 +1,43 @@ +package com.ibrahimcanerdogan.cleannote.ui.component + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusState +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle + +@Composable +fun TransparentHintTextField( + text: String, + hint: String, + modifier: Modifier = Modifier, + isHintVisible: Boolean = true, + onValueChange: (String) -> Unit, + textStyle: TextStyle = TextStyle(), + singleLine: Boolean = false, + onFocusChange: (FocusState) -> Unit +) { + Box( + modifier = modifier + ) { + BasicTextField( + value = text, + onValueChange = onValueChange, + singleLine = singleLine, + textStyle = textStyle, + modifier = Modifier + .fillMaxWidth() + .onFocusChanged { + onFocusChange(it) + } + ) + if(isHintVisible) { + Text(text = hint, style = textStyle, color = Color.DarkGray) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/navigation/NoteNavigation.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/navigation/NoteNavigation.kt new file mode 100644 index 00000000..489cd349 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/navigation/NoteNavigation.kt @@ -0,0 +1,48 @@ +package com.ibrahimcanerdogan.cleannote.ui.navigation + +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument +import com.ibrahimcanerdogan.cleannote.ui.view.edit.AddEditNoteScreen +import com.ibrahimcanerdogan.cleannote.ui.view.list.NoteListScreen + +@Composable +fun NoteNavigation() { + val navController = rememberNavController() + NavHost( + navController = navController, + startDestination = NoteScreen.NotesScreen.route + ) { + composable(route = NoteScreen.NotesScreen.route) { + NoteListScreen(navController = navController) + } + composable( + route = NoteScreen.AddEditNoteScreen.route + "?noteId={noteId}¬eColor={noteColor}", + arguments = listOf( + navArgument( + name = "noteId" + ) { + type = NavType.IntType + defaultValue = -1 + }, + navArgument( + name = "noteColor" + ) { + type = NavType.IntType + defaultValue = -1 + }, + ) + ) { + val color = it.arguments?.getInt("noteColor") ?: -1 + AddEditNoteScreen( + navController = navController, + noteColor = color + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/navigation/NoteScreen.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/navigation/NoteScreen.kt new file mode 100644 index 00000000..e7a13c46 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/navigation/NoteScreen.kt @@ -0,0 +1,6 @@ +package com.ibrahimcanerdogan.cleannote.ui.navigation + +sealed class NoteScreen(val route: String) { + data object NotesScreen: NoteScreen("notes_screen") + data object AddEditNoteScreen: NoteScreen("add_edit_note_screen") +} diff --git a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Color.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Color.kt similarity index 76% rename from app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Color.kt rename to app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Color.kt index 9b76e750..bc534250 100644 --- a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Color.kt +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Color.kt @@ -1,8 +1,9 @@ -package com.plcoding.cleanarchitecturenoteapp.ui.theme +package com.ibrahimcanerdogan.cleannote.ui.theme import androidx.compose.ui.graphics.Color val DarkGray = Color(0xFF202020) +val LightGray = Color(0xFFD3D3D3) val LightBlue = Color(0xFFD7E8DE) val RedOrange = Color(0xffffab91) diff --git a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Shape.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Shape.kt similarity index 71% rename from app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Shape.kt rename to app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Shape.kt index 3a70048a..fb5eaebf 100644 --- a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Shape.kt +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Shape.kt @@ -1,7 +1,7 @@ -package com.plcoding.cleanarchitecturenoteapp.ui.theme +package com.ibrahimcanerdogan.cleannote.ui.theme import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Shapes +import androidx.compose.material3.Shapes import androidx.compose.ui.unit.dp val Shapes = Shapes( diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Theme.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Theme.kt new file mode 100644 index 00000000..e74bac3d --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Theme.kt @@ -0,0 +1,52 @@ +package com.ibrahimcanerdogan.cleannote.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Color.White, + background = DarkGray, + onBackground = Color.White, + surface = LightBlue, + onSurface = DarkGray +) + +private val LightColorScheme = lightColorScheme( + primary = Color.White, + background = LightGray, + onBackground = Color.White, + surface = LightBlue, + onSurface = DarkGray +) + +@Composable +fun CleanNoteAppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Type.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Type.kt similarity index 85% rename from app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Type.kt rename to app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Type.kt index 4db73a88..9ddba820 100644 --- a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Type.kt +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/theme/Type.kt @@ -1,6 +1,6 @@ -package com.plcoding.cleanarchitecturenoteapp.ui.theme +package com.ibrahimcanerdogan.cleannote.ui.theme -import androidx.compose.material.Typography +import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -8,7 +8,7 @@ import androidx.compose.ui.unit.sp // Set of Material typography styles to start with val Typography = Typography( - body1 = TextStyle( + bodyLarge = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, fontSize = 16.sp diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteEvent.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteEvent.kt new file mode 100644 index 00000000..9dae1160 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteEvent.kt @@ -0,0 +1,13 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.edit + +import androidx.compose.ui.focus.FocusState + +sealed class AddEditNoteEvent{ + data class EnteredTitle(val value: String): AddEditNoteEvent() + data class ChangeTitleFocus(val focusState: FocusState): AddEditNoteEvent() + data class EnteredContent(val value: String): AddEditNoteEvent() + data class ChangeContentFocus(val focusState: FocusState): AddEditNoteEvent() + data class ChangeColor(val color: Int): AddEditNoteEvent() + data object SaveNote: AddEditNoteEvent() +} + diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteScreen.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteScreen.kt new file mode 100644 index 00000000..6bb4962a --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteScreen.kt @@ -0,0 +1,150 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.edit + +import androidx.compose.animation.Animatable +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Save +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.ui.component.TransparentHintTextField +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +@Composable +fun AddEditNoteScreen( + navController: NavController, + noteColor: Int, + viewModel: AddEditNoteViewModel = hiltViewModel() +) { + val titleState = viewModel.noteTitle.value + val contentState = viewModel.noteContent.value + + val snackbarHostState = remember { SnackbarHostState() } + + val noteBackgroundAnimatable = remember { + Animatable( + Color(if (noteColor != -1) noteColor else viewModel.noteColor.value) + ) + } + val scope = rememberCoroutineScope() + + LaunchedEffect(key1 = true) { + viewModel.eventFlow.collectLatest { event -> + when (event) { + is AddEditNoteViewModel.UiEvent.ShowSnackbar -> { + snackbarHostState.showSnackbar( + message = event.message + ) + } + + is AddEditNoteViewModel.UiEvent.SaveNote -> { + navController.navigateUp() + } + } + } + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + floatingActionButton = { + FloatingActionButton( + onClick = { + viewModel.onEvent(AddEditNoteEvent.SaveNote) + }, + shape = CircleShape, + containerColor = MaterialTheme.colorScheme.primary + ) { + Icon(imageVector = Icons.Default.Save, contentDescription = "Save note") + } + } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .background(noteBackgroundAnimatable.value) + .padding(paddingValues) + .padding(16.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Note.noteColors.forEach { color -> + val colorInt = color.toArgb() + Box( + modifier = Modifier + .size(50.dp) + .shadow(15.dp, CircleShape) + .clip(CircleShape) + .background(color) + .border( + width = 3.dp, + color = if (viewModel.noteColor.value == colorInt) { + Color.Black + } else Color.Transparent, + shape = CircleShape + ) + .clickable { + scope.launch { + noteBackgroundAnimatable.animateTo( + targetValue = Color(colorInt), + animationSpec = tween( + durationMillis = 500 + ) + ) + } + viewModel.onEvent(AddEditNoteEvent.ChangeColor(colorInt)) + } + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + TransparentHintTextField( + text = titleState.stateText, + hint = titleState.stateHint, + onValueChange = { + viewModel.onEvent(AddEditNoteEvent.EnteredTitle(it)) + }, + onFocusChange = { + viewModel.onEvent(AddEditNoteEvent.ChangeTitleFocus(it)) + }, + isHintVisible = titleState.stateIsHintVisible, + singleLine = true, + textStyle = MaterialTheme.typography.headlineSmall + ) + Spacer(modifier = Modifier.height(16.dp)) + TransparentHintTextField( + text = contentState.stateText, + hint = contentState.stateHint, + onValueChange = { + viewModel.onEvent(AddEditNoteEvent.EnteredContent(it)) + }, + onFocusChange = { + viewModel.onEvent(AddEditNoteEvent.ChangeContentFocus(it)) + }, + isHintVisible = contentState.stateIsHintVisible, + textStyle = MaterialTheme.typography.bodyLarge, + modifier = Modifier.fillMaxHeight() + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteViewModel.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteViewModel.kt new file mode 100644 index 00000000..60fc564b --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/AddEditNoteViewModel.kt @@ -0,0 +1,119 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.edit + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.graphics.toArgb +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ibrahimcanerdogan.cleannote.data.model.InvalidNoteException +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.usecase.NoteUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class AddEditNoteViewModel @Inject constructor( + private val noteUseCase: NoteUseCase, + savedStateHandle: SavedStateHandle +) : ViewModel() { + + private val _noteTitle = mutableStateOf(NoteTextFieldState(stateHint = "Note Title")) + val noteTitle: State = _noteTitle + + private val _noteContent = mutableStateOf(NoteTextFieldState(stateHint = "Note Description")) + val noteContent: State = _noteContent + + private val _noteColor = mutableIntStateOf(Note.noteColors.random().toArgb()) + val noteColor: State = _noteColor + + private val _eventFlow = MutableSharedFlow() + val eventFlow = _eventFlow.asSharedFlow() + + private var currentNoteId: Int? = null + + init { + savedStateHandle.get("noteId")?.let { noteId -> + if (noteId != -1) { + viewModelScope.launch { + noteUseCase.getNote(noteId)?.also { note -> + currentNoteId = note.id + _noteTitle.value = noteTitle.value.copy( + stateText = note.title, + stateIsHintVisible = false + ) + _noteContent.value = _noteContent.value.copy( + stateText = note.content, + stateIsHintVisible = false + ) + _noteColor.intValue = note.color + } + } + } + } + } + + fun onEvent(event: AddEditNoteEvent) { + when (event) { + is AddEditNoteEvent.EnteredTitle -> { + _noteTitle.value = noteTitle.value.copy( + stateText = event.value + ) + } + + is AddEditNoteEvent.ChangeTitleFocus -> { + _noteTitle.value = noteTitle.value.copy( + stateIsHintVisible = !event.focusState.isFocused && noteTitle.value.stateText.isBlank() + ) + } + + is AddEditNoteEvent.EnteredContent -> { + _noteContent.value = _noteContent.value.copy( + stateText = event.value + ) + } + + is AddEditNoteEvent.ChangeContentFocus -> { + _noteContent.value = _noteContent.value.copy( + stateIsHintVisible = !event.focusState.isFocused && _noteContent.value.stateText.isBlank() + ) + } + + is AddEditNoteEvent.ChangeColor -> { + _noteColor.intValue = event.color + } + + is AddEditNoteEvent.SaveNote -> { + viewModelScope.launch { + try { + noteUseCase.addNote( + Note( + title = noteTitle.value.stateText, + content = noteContent.value.stateText, + timestamp = System.currentTimeMillis(), + color = noteColor.value, + id = currentNoteId + ) + ) + _eventFlow.emit(UiEvent.SaveNote) + } catch (e: InvalidNoteException) { + _eventFlow.emit( + UiEvent.ShowSnackbar( + message = e.message ?: "Couldn't save note" + ) + ) + } + } + } + } + } + + sealed class UiEvent { + data class ShowSnackbar(val message: String) : UiEvent() + data object SaveNote : UiEvent() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/NoteTextFieldState.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/NoteTextFieldState.kt new file mode 100644 index 00000000..d9f244f6 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/edit/NoteTextFieldState.kt @@ -0,0 +1,7 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.edit + +data class NoteTextFieldState( + val stateText: String = "", + val stateHint: String = "", + val stateIsHintVisible: Boolean = true +) diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListEvent.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListEvent.kt new file mode 100644 index 00000000..9f5d2e09 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListEvent.kt @@ -0,0 +1,11 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.list + +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.util.NoteOrder + +sealed class NoteListEvent { + data class Order(val noteOrder: NoteOrder): NoteListEvent() + data class DeleteNote(val note: Note): NoteListEvent() + data object RestoreNote: NoteListEvent() + data object ToggleOrderSection: NoteListEvent() +} diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListScreen.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListScreen.kt new file mode 100644 index 00000000..16a47d1b --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListScreen.kt @@ -0,0 +1,207 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.list + +import androidx.compose.animation.* +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import com.ibrahimcanerdogan.cleannote.ui.component.OrderSection +import com.ibrahimcanerdogan.cleannote.ui.navigation.NoteScreen +import kotlinx.coroutines.launch +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.automirrored.filled.Sort +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material.icons.filled.Delete +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.drawscope.clipPath +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp +import androidx.core.graphics.ColorUtils +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.ui.theme.DarkGray + +@Composable +fun NoteListScreen( + navController: NavController, + viewModel: NoteListViewModel = hiltViewModel() +) { + val state = viewModel.state.value + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + floatingActionButton = { + FloatingActionButton( + onClick = { + navController.navigate(NoteScreen.AddEditNoteScreen.route) + }, + shape = CircleShape, + containerColor = MaterialTheme.colorScheme.primary + ) { + Icon(imageVector = Icons.Default.Add, contentDescription = "Add note") + } + } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "JetNote", + style = MaterialTheme.typography.headlineMedium + ) + IconButton( + onClick = { + viewModel.onEvent(NoteListEvent.ToggleOrderSection) + }, + ) { + Icon( + imageVector = Icons.AutoMirrored.Default.Sort, + contentDescription = "Sort" + ) + } + } + AnimatedVisibility( + visible = state.isOrderSectionVisible, + enter = fadeIn() + slideInVertically() + ) { + OrderSection( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + noteOrder = state.noteOrder, + onOrderChange = { + viewModel.onEvent(NoteListEvent.Order(it)) + } + ) + } + Spacer(modifier = Modifier.height(5.dp)) + LazyColumn(modifier = Modifier.fillMaxSize()) { + items(state.notes) { note -> + NoteItem( + note = note, + modifier = Modifier + .fillMaxWidth() + .clickable { + navController.navigate( + NoteScreen.AddEditNoteScreen.route + + "?noteId=${note.id}¬eColor=${note.color}" + ) + }, + onDeleteClick = { + viewModel.onEvent(NoteListEvent.DeleteNote(note)) + scope.launch { + val result = snackbarHostState.showSnackbar( + message = "Note deleted", + actionLabel = "Undo" + ) + if(result == SnackbarResult.ActionPerformed) { + viewModel.onEvent(NoteListEvent.RestoreNote) + } + } + } + ) + Spacer(modifier = Modifier.height(16.dp)) + } + } + } + } +} + +@Composable +fun NoteItem( + note: Note, + modifier: Modifier = Modifier, + cornerRadius: Dp = 10.dp, + cutCornerSize: Dp = 30.dp, + onDeleteClick: () -> Unit +) { + Box( + modifier = modifier + ) { + Canvas(modifier = Modifier.matchParentSize()) { + val clipPath = Path().apply { + lineTo(size.width - cutCornerSize.toPx(), 0f) + lineTo(size.width, cutCornerSize.toPx()) + lineTo(size.width, size.height) + lineTo(0f, size.height) + close() + } + + clipPath(clipPath) { + drawRoundRect( + color = Color(note.color), + size = size, + cornerRadius = CornerRadius(cornerRadius.toPx()) + ) + drawRoundRect( + color = Color( + ColorUtils.blendARGB(note.color, 0x000000, 0.2f) + ), + topLeft = Offset(size.width - cutCornerSize.toPx(), -100f), + size = Size(cutCornerSize.toPx() + 100f, cutCornerSize.toPx() + 100f), + cornerRadius = CornerRadius(cornerRadius.toPx()) + ) + } + } + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + .padding(end = 32.dp) + ) { + Text( + text = note.title, + style = MaterialTheme.typography.headlineSmall, + color = DarkGray, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = note.content, + style = MaterialTheme.typography.bodyLarge, + color = DarkGray, + maxLines = 10, + overflow = TextOverflow.Ellipsis + ) + } + IconButton( + onClick = onDeleteClick, + modifier = Modifier.align(Alignment.BottomEnd) + ) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = "Delete note", + tint = MaterialTheme.colorScheme.onSurface + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListState.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListState.kt new file mode 100644 index 00000000..92bec41b --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListState.kt @@ -0,0 +1,11 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.list + +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.util.NoteOrder +import com.ibrahimcanerdogan.cleannote.domain.util.OrderType + +data class NoteListState( + val notes: List = emptyList(), + val noteOrder: NoteOrder = NoteOrder.Date(OrderType.Descending), + val isOrderSectionVisible: Boolean = false +) diff --git a/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListViewModel.kt b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListViewModel.kt new file mode 100644 index 00000000..58555c51 --- /dev/null +++ b/app/src/main/java/com/ibrahimcanerdogan/cleannote/ui/view/list/NoteListViewModel.kt @@ -0,0 +1,78 @@ +package com.ibrahimcanerdogan.cleannote.ui.view.list + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ibrahimcanerdogan.cleannote.data.model.Note +import com.ibrahimcanerdogan.cleannote.domain.usecase.NoteUseCase +import com.ibrahimcanerdogan.cleannote.domain.util.NoteOrder +import com.ibrahimcanerdogan.cleannote.domain.util.OrderType +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class NoteListViewModel @Inject constructor( + private val noteUseCase: NoteUseCase +) : ViewModel() { + + private val _state = mutableStateOf(NoteListState()) + val state: State = _state + + private var recentlyDeletedNote: Note? = null + + private var getNotesJob: Job? = null + + init { + getNotes(NoteOrder.Date(OrderType.Descending)) + } + + fun onEvent(event: NoteListEvent) { + when (event) { + is NoteListEvent.Order -> { + if (state.value.noteOrder::class == event.noteOrder::class && + state.value.noteOrder.orderType == event.noteOrder.orderType + ) { + return + } + getNotes(event.noteOrder) + } + + is NoteListEvent.DeleteNote -> { + viewModelScope.launch { + noteUseCase.deleteNote(event.note) + recentlyDeletedNote = event.note + } + } + + is NoteListEvent.RestoreNote -> { + viewModelScope.launch { + noteUseCase.addNote(recentlyDeletedNote ?: return@launch) + recentlyDeletedNote = null + } + } + + is NoteListEvent.ToggleOrderSection -> { + _state.value = state.value.copy( + isOrderSectionVisible = !state.value.isOrderSectionVisible + ) + } + } + } + + private fun getNotes(noteOrder: NoteOrder) { + getNotesJob?.cancel() + getNotesJob = noteUseCase.getNotes(noteOrder) + .onEach { notes -> + _state.value = state.value.copy( + notes = notes, + noteOrder = noteOrder + ) + } + .launchIn(viewModelScope) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/MainActivity.kt b/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/MainActivity.kt deleted file mode 100644 index 8282fe24..00000000 --- a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/MainActivity.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.plcoding.cleanarchitecturenoteapp - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import com.plcoding.cleanarchitecturenoteapp.ui.theme.CleanArchitectureNoteAppTheme - -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - CleanArchitectureNoteAppTheme { - - } - } - } -} diff --git a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Theme.kt b/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Theme.kt deleted file mode 100644 index 24a1508f..00000000 --- a/app/src/main/java/com/plcoding/cleanarchitecturenoteapp/ui/theme/Theme.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.plcoding.cleanarchitecturenoteapp.ui.theme - -import androidx.compose.material.MaterialTheme -import androidx.compose.material.darkColors -import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color - -private val DarkColorPalette = darkColors( - primary = Color.White, - background = DarkGray, - onBackground = Color.White, - surface = LightBlue, - onSurface = DarkGray -) - -@Composable -fun CleanArchitectureNoteAppTheme(darkTheme: Boolean = true, content: @Composable() () -> Unit) { - MaterialTheme( - colors = DarkColorPalette, - typography = Typography, - shapes = Shapes, - content = content - ) -} \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_launcher_foreground.xml b/app/src/main/res/drawable/icon_launcher_foreground.xml new file mode 100644 index 00000000..83c3cba7 --- /dev/null +++ b/app/src/main/res/drawable/icon_launcher_foreground.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/icon_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/icon_launcher.xml new file mode 100644 index 00000000..519a0847 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/icon_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/icon_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/icon_launcher_round.xml new file mode 100644 index 00000000..519a0847 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/icon_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/icon_launcher.webp b/app/src/main/res/mipmap-hdpi/icon_launcher.webp new file mode 100644 index 00000000..0ce139e8 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/icon_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/icon_launcher_round.webp b/app/src/main/res/mipmap-hdpi/icon_launcher_round.webp new file mode 100644 index 00000000..5ad44c91 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/icon_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/icon_launcher.webp b/app/src/main/res/mipmap-mdpi/icon_launcher.webp new file mode 100644 index 00000000..27c0b414 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/icon_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/icon_launcher_round.webp b/app/src/main/res/mipmap-mdpi/icon_launcher_round.webp new file mode 100644 index 00000000..3680e68b Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/icon_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/icon_launcher.webp b/app/src/main/res/mipmap-xhdpi/icon_launcher.webp new file mode 100644 index 00000000..e1f712a8 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/icon_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/icon_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/icon_launcher_round.webp new file mode 100644 index 00000000..d472fe8e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/icon_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/icon_launcher.webp b/app/src/main/res/mipmap-xxhdpi/icon_launcher.webp new file mode 100644 index 00000000..6f9e233f Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/icon_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/icon_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/icon_launcher_round.webp new file mode 100644 index 00000000..b9c1919a Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/icon_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/icon_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/icon_launcher.webp new file mode 100644 index 00000000..7b3c94cd Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/icon_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/icon_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/icon_launcher_round.webp new file mode 100644 index 00000000..c8de0428 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/icon_launcher_round.webp differ diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml deleted file mode 100644 index 423caff1..00000000 --- a/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values/icon_launcher_background.xml b/app/src/main/res/values/icon_launcher_background.xml new file mode 100644 index 00000000..dc8c7221 --- /dev/null +++ b/app/src/main/res/values/icon_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e3eec93a..6dc35484 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - CleanArchitectureNoteApp + Clean Note \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index c2739918..33a1f20f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,26 +1,3 @@ - - - - - - -