Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
3 changes: 3 additions & 0 deletions Assignment_13/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
1 change: 0 additions & 1 deletion newProject/.idea/misc.xml → Assignment_13/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Assignment_13/.idea/render.experimental.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
85 changes: 85 additions & 0 deletions Assignment_13/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
id("org.jetbrains.kotlin.plugin.compose")
id("kotlin-kapt")
}

android {
namespace = "com.example.assignment"
compileSdk = 35

defaultConfig {
applicationId = "com.example.assignment"
minSdk = 33
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_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
dataBinding = true
viewBinding = true
compose = true
}
}

dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.activity.compose)
implementation(libs.recyclerview)
implementation(libs.kotlin.metadata.jvm)
implementation(libs.androidx.fragment.ktx)
implementation("com.github.bumptech.glide:glide:4.16.0")


implementation(libs.androidx.ui)
implementation(libs.androidx.material)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material.icons.extended)

implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.livedata.ktx)

implementation(libs.androidx.navigation.compose)

implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
implementation(libs.androidx.hilt.navigation.compose)

implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.android)

implementation(libs.androidx.room.runtime)
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

<application
android:name="com.example.assignment.WordApp"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Assignment"
tools:targetApi="31">
android:theme="@style/Theme.Assignment">
<activity android:name="com.example.assignment.feature_word.presentation.AddEditWordActivity" />
<activity
android:name=".MainActivity"
android:name="com.example.assignment.feature_word.presentation.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.assignment

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class WordApp : Application()
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.example.assignment.di

import android.app.Application
import android.content.Context
import androidx.room.Room
import com.example.assignment.feature_word.data.data_source.WordDatabase
import com.example.assignment.feature_word.data.data_source.migration_1_2
import com.example.assignment.feature_word.data.repository.WordRepositoryImpl
import com.example.assignment.feature_word.domain.repository.WordRepository
import com.example.assignment.feature_word.domain.use_case.AddWord
import com.example.assignment.feature_word.domain.use_case.DeleteWord
import com.example.assignment.feature_word.domain.use_case.GetWord
import com.example.assignment.feature_word.domain.use_case.GetWords
import com.example.assignment.feature_word.domain.use_case.WordUseCases
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 AppModule {

@Provides
@Singleton
fun provideWordDatabase(app: Application): WordDatabase {
return Room.databaseBuilder(
app,
WordDatabase::class.java,
WordDatabase.DATABASE_NAME
).addMigrations(migration_1_2).build()
}

@Provides
@Singleton
fun provideWordRepository(db: WordDatabase): WordRepository {
return WordRepositoryImpl(db.wordDao)
}

@Provides
@Singleton
fun provideWordUseCases(repository: WordRepository): WordUseCases {
return WordUseCases(
getWords = GetWords(repository),
deleteWord = DeleteWord(repository),
addWord = AddWord(repository),
getWord = GetWord(repository)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.example.assignment.feature_word.data.data_source

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.example.assignment.feature_word.domain.model.Word
import kotlinx.coroutines.flow.Flow


@Dao
interface WordDao {

@Query("SELECT * FROM word")
fun getWords(): Flow<List<Word>>

@Query("SELECT * FROM word WHERE id = :id")
suspend fun getWordById(id: Int): Word?

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertWord(word: Word)

@Delete
suspend fun deleteWord(word: Word)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example.assignment.feature_word.data.data_source

import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.assignment.feature_word.domain.model.Word

@Database(entities = [Word::class], version = 2, exportSchema = false)
abstract class WordDatabase : RoomDatabase() {

abstract val wordDao : WordDao

companion object {
const val DATABASE_NAME = "words_db"
}
}

val migration_1_2 = object : Migration(1,2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"ALTER TABLE word ADD COLUMN imageUri TEXT"
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.assignment.feature_word.data.repository

import android.content.Context
import android.net.Uri
import com.example.assignment.feature_word.data.data_source.WordDao
import com.example.assignment.feature_word.domain.model.Word
import com.example.assignment.feature_word.domain.repository.WordRepository
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import java.io.File
import java.io.FileOutputStream

class WordRepositoryImpl(
private val dao: WordDao
) : WordRepository {
override fun getWords(): Flow<List<Word>> {
return dao.getWords()
}

override suspend fun getWordById(id: Int): Word? {
return dao.getWordById(id)
}

override suspend fun insertWord(word: Word) {
dao.insertWord(word)
}

override suspend fun deleteWord(word: Word) {
dao.deleteWord(word)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.assignment.feature_word.domain.model

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class Word(
val word: String,
val meaning: String,
val imageUri: String? = null,
@PrimaryKey(autoGenerate = true) val id: Int? = null
)

class InvalidWordException(message: String): Exception(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.assignment.feature_word.domain.repository

import android.net.Uri
import com.example.assignment.feature_word.domain.model.Word
import kotlinx.coroutines.flow.Flow

interface WordRepository {

fun getWords(): Flow<List<Word>>

suspend fun getWordById(id: Int): Word?

suspend fun insertWord(word: Word)

suspend fun deleteWord(word: Word)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.assignment.feature_word.domain.use_case

import com.example.assignment.feature_word.domain.model.InvalidWordException
import com.example.assignment.feature_word.domain.model.Word
import com.example.assignment.feature_word.domain.repository.WordRepository

class AddWord(
private val repository: WordRepository
) {

@Throws(InvalidWordException::class)
suspend operator fun invoke(word: Word) {
if(word.word.isBlank()) {
throw InvalidWordException("단어명 항목이 비어있습니다.")
}
if(word.meaning.isBlank()) {
throw InvalidWordException("단어 뜻 항목이 비어있습니다.")
}
repository.insertWord(word)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.assignment.feature_word.domain.use_case

import com.example.assignment.feature_word.domain.model.Word
import com.example.assignment.feature_word.domain.repository.WordRepository

class DeleteWord(
private val repository: WordRepository
) {
suspend operator fun invoke(word: Word) {
repository.deleteWord(word)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.assignment.feature_word.domain.use_case

import com.example.assignment.feature_word.domain.model.Word
import com.example.assignment.feature_word.domain.repository.WordRepository

class GetWord(
private val repository: WordRepository
) {

suspend operator fun invoke(id: Int): Word? {
return repository.getWordById(id)
}

}
Loading