Skip to content

Commit

Permalink
부산대 Android 박정훈 5주차 과제 Step1 (#42)
Browse files Browse the repository at this point in the history
* init: 4주차 코드 가져오기

* refactor: 장소 DB 처리 코드 개선

- local, remote DB 객체 연결

* refactor: 네트워크와 데이터베이스 작업 분리

- PlaceDBHelper: 로컬 데이터베이스에서 장소 정보를 가져오고 저장하는 기능 유지

* refactor: 지도 정보 뷰모델에서 처리

* refactor: 에러 메시지 표시 기능 개선

- 에러 텍스트를 네트워크 상태에 따라 visible/gone으로 처리하는 것으로 변경

* refactor: room 라이브러리 사용

* refactor: 지역, 원격 repository 분리

* refactor: MapViewModel에서 LiveData를 Flow로 변경

* delete: PlaceContract 및 테스트 코드 삭제

* refactor: data layer 패키지 분리

* chore: hilt 라이브러리 추가

* refactor: Hilt 사용 및 Module 파일 생성

* feat: 네트워크 연결 시 정상화면 처리 기능 추가

- 지도 화면을 스와이프 하면 네트워크 상태에 따라 화면 갱신
  • Loading branch information
Pjhn authored Jul 28, 2024
1 parent 537ceed commit 9411703
Show file tree
Hide file tree
Showing 22 changed files with 788 additions and 56 deletions.
9 changes: 9 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.google.dagger.hilt.android")
id("kotlin-kapt")
}

Expand Down Expand Up @@ -52,6 +53,14 @@ android {
}

dependencies {
kapt("com.google.dagger:hilt-compiler:2.48.1")
kapt("androidx.room:room-compiler:2.6.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation ("androidx.activity:activity-ktx:1.1.0")
implementation ("androidx.fragment:fragment-ktx:1.2.5")
implementation("com.google.dagger:hilt-android:2.48.1")
implementation("androidx.room:room-ktx:2.6.1")
implementation("androidx.room:room-runtime:2.6.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.4.0")
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
android:theme="@style/Theme.Map"
tools:targetApi="31">
<activity
android:name=".presentation.MapActivity"
android:name=".presentation.map.MapActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand All @@ -25,10 +25,10 @@
</intent-filter>
</activity>
<activity
android:name=".presentation.SearchViewModel"
android:name=".presentation.search.SearchViewModel"
android:exported="false" />
<activity
android:name=".presentation.SearchActivity"
android:name=".presentation.search.SearchActivity"
android:exported="false"/>


Expand Down
11 changes: 0 additions & 11 deletions app/src/main/java/campus/tech/kakao/map/MainActivity.kt

This file was deleted.

14 changes: 6 additions & 8 deletions app/src/main/java/campus/tech/kakao/map/PlaceApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import android.app.Application
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import campus.tech.kakao.map.data.PlaceRepositoryImpl
import campus.tech.kakao.map.data.PlaceRemoteDataRepository
import campus.tech.kakao.map.domain.repository.PlaceRepository
import com.kakao.vectormap.KakaoMapSdk
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class PlaceApplication: Application() {

val placeRepository: PlaceRepository by lazy { PlaceRepositoryImpl.getInstance(this)}

override fun onCreate() {
super.onCreate()
appInstance = this
Expand All @@ -29,11 +29,9 @@ class PlaceApplication: Application() {
val actNetwork: NetworkCapabilities =
connectivityManager.getNetworkCapabilities(network) ?: return false

return when {
actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
else -> false
}
return actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package campus.tech.kakao.map.data

import android.content.Context
import campus.tech.kakao.map.domain.model.Place
import javax.inject.Inject

class LastVisitedPlaceManager @Inject constructor(context: Context) {

private val sharedPreferences = context.getSharedPreferences("LastVisitedPlace", Context.MODE_PRIVATE)

fun saveLastVisitedPlace(place: Place) {
val editor = sharedPreferences.edit()
editor.putString("placeName", place.place)
editor.putString("roadAddressName", place.address)
editor.putString("categoryName", place.category)
editor.putString("yPos", place.yPos)
editor.putString("xPos", place.xPos)
editor.apply()
}

fun getLastVisitedPlace(): Place? {
val placeName = sharedPreferences.getString("placeName", null)
val roadAddressName = sharedPreferences.getString("roadAddressName", null)
val categoryName = sharedPreferences.getString("categoryName", null)
val yPos = sharedPreferences.getString("yPos", null)
val xPos = sharedPreferences.getString("xPos", null)

return if (placeName != null && roadAddressName != null && categoryName != null && yPos != null && xPos != null) {
Place("", placeName, roadAddressName, categoryName, xPos, yPos)
} else {
null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package campus.tech.kakao.map.data

import campus.tech.kakao.map.data.dao.PlaceDao
import campus.tech.kakao.map.data.entity.PlaceEntity
import campus.tech.kakao.map.data.entity.PlaceLogEntity
import campus.tech.kakao.map.domain.model.Place
import campus.tech.kakao.map.domain.repository.PlaceRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

open class PlaceLocalDataRepository @Inject constructor(
private val placeDao: PlaceDao,
) : PlaceRepository {

override suspend fun getPlaces(placeName: String): List<Place> {
return withContext(Dispatchers.IO) {
placeDao.getPlaces(placeName).map {
Place(it.id, it.place, it.address, it.type, it.xPos, it.yPos)
}
}
}

override suspend fun updatePlaces(places: List<Place>) {
withContext(Dispatchers.IO) {
placeDao.deleteAllPlaces()
placeDao.insertPlaces(places.map {
PlaceEntity(it.id, it.place, it.address, it.category, it.xPos, it.yPos)
})
}
}

override suspend fun getPlaceById(id: String): Place? {
return withContext(Dispatchers.IO) {
placeDao.getPlaceById(id)?.let {
Place(it.id, it.place, it.address, it.type, it.xPos, it.yPos)
}
}
}

override suspend fun updateLogs(logs: List<Place>) {
withContext(Dispatchers.IO) {
placeDao.deleteAllLogs()
placeDao.insertLogs(logs.map {
PlaceLogEntity(it.id, it.place)
})
}
}

override suspend fun removeLog(id: String) {
withContext(Dispatchers.IO) {
placeDao.removeLog(id)
}
}

override suspend fun getLogs(): List<Place> {
return withContext(Dispatchers.IO) {
placeDao.getLogs().map {
Place(it.id, it.place, "", "", "", "")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package campus.tech.kakao.map.data

import android.content.Context
import campus.tech.kakao.map.BuildConfig
import campus.tech.kakao.map.data.dao.PlaceDao
import campus.tech.kakao.map.data.net.KakaoApi
import campus.tech.kakao.map.domain.model.Place
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

class PlaceRemoteDataRepository @Inject constructor(
private val placeDao: PlaceDao,
private val kakaoApi: KakaoApi
) : PlaceLocalDataRepository(placeDao){
override suspend fun getPlaces(placeName: String): List<Place> {
return withContext(Dispatchers.IO) {
val resultPlaces = mutableListOf<Place>()
for (page in 1..3) {
val response = kakaoApi.getSearchKeyword(
key = BuildConfig.KAKAO_REST_API_KEY,
query = placeName,
size = 15,
page = page
)
if (response.isSuccessful) {
response.body()?.documents?.let { resultPlaces.addAll(it) }
} else throw RuntimeException("통신 에러 발생")
}
updatePlaces(resultPlaces)
resultPlaces
}
}
}
34 changes: 34 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/dao/PlaceDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package campus.tech.kakao.map.data.dao

import androidx.room.*
import androidx.room.Insert
import androidx.room.Query
import campus.tech.kakao.map.data.entity.PlaceEntity
import campus.tech.kakao.map.data.entity.PlaceLogEntity

@Dao
interface PlaceDao {
@Query("SELECT * FROM places WHERE place LIKE :keyword")
suspend fun getPlaces(keyword: String): List<PlaceEntity>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertPlaces(places: List<PlaceEntity>)

@Query("SELECT * FROM places WHERE id = :id")
suspend fun getPlaceById(id: String): PlaceEntity?

@Query("DELETE FROM places")
suspend fun deleteAllPlaces()

@Query("SELECT * FROM logs")
suspend fun getLogs(): List<PlaceLogEntity>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertLogs(logs: List<PlaceLogEntity>)

@Query("DELETE FROM logs WHERE id = :id")
suspend fun removeLog(id: String)

@Query("DELETE FROM logs")
suspend fun deleteAllLogs()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package campus.tech.kakao.map.data.database

import androidx.room.*
import campus.tech.kakao.map.data.dao.PlaceDao
import campus.tech.kakao.map.data.entity.PlaceEntity
import campus.tech.kakao.map.data.entity.PlaceLogEntity

@Database(entities = [PlaceEntity::class, PlaceLogEntity::class], version = 1)
abstract class PlaceDatabase: RoomDatabase(){
abstract fun placeDao(): PlaceDao
}
20 changes: 20 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/entity/Entity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package campus.tech.kakao.map.data.entity

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

@Entity(tableName = "places")
data class PlaceEntity(
@PrimaryKey val id: String,
val place: String,
val address: String,
val type: String,
val xPos: String,
val yPos: String
)

@Entity(tableName = "logs")
data class PlaceLogEntity(
@PrimaryKey val id: String,
val place: String
)
33 changes: 33 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/di/DatabaseModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package campus.tech.kakao.map.di

import android.content.Context
import androidx.room.Room
import campus.tech.kakao.map.data.dao.PlaceDao
import campus.tech.kakao.map.data.database.PlaceDatabase
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 provideAppDatabase(@ApplicationContext context: Context): PlaceDatabase {
return Room.databaseBuilder(
context.applicationContext,
PlaceDatabase::class.java,
"place_database"
).build()
}

@Provides
@Singleton
fun providePlaceDao(placeDatabase: PlaceDatabase): PlaceDao {
return placeDatabase.placeDao()
}
}
30 changes: 30 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package campus.tech.kakao.map.di

import campus.tech.kakao.map.data.net.KakaoApi
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
private const val BASE_URL = "https://dapi.kakao.com/"
@Singleton
@Provides
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}

@Singleton
@Provides
fun provideKakaoApi(retrofit: Retrofit): KakaoApi {
return retrofit.create(KakaoApi::class.java)
}
}
Loading

0 comments on commit 9411703

Please sign in to comment.