Skip to content

Commit

Permalink
[경북대 Android 류지원] 6주차 과제_STEP1 (#16)
Browse files Browse the repository at this point in the history
* init: load previous codes

이전 코드 불러오기

* refactor: implement databinding on ErrorActivity

전주 피드백 사항인 ErrorActivity databinding 추가 적용

* docs: edit README

* feat: implement SplashView

splashview 구현

* feat: implement loading serviceConfig in layer

mvvm 패턴에 알맞게 데이터 레이어에 serviceConfig 불러오도록 구현

* init: load previous codes

이전 코드 불러오기

* refactor: implement databinding on ErrorActivity

전주 피드백 사항인 ErrorActivity databinding 추가 적용

* feat: implement SplashView

splashview 구현

* feat: implement loading serviceConfig in layer

mvvm 패턴에 알맞게 데이터 레이어에 serviceConfig 불러오도록 구현

* refactor: add coroutines for async

비동기 작업을 위해 코루틴 추가
  • Loading branch information
akuby21 authored Jul 30, 2024
1 parent b33295f commit 3207489
Show file tree
Hide file tree
Showing 16 changed files with 266 additions and 8 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
- 코드 컨벤션을 준수하며 프로그래밍한다.
## 구현할 기능 목록
### 1단계 기능
- [ ] 스플래시 화면 구현
- [ ] Remote Config 값 불러와 비교하기
- [ ] 에러시 serviceMessage 출력
- [x] 스플래시 화면 구현
- [x] Remote Config 값 불러와 비교하기
- [x] 에러시 serviceMessage 출력
6 changes: 6 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
id("org.jetbrains.kotlin.android")
id("kotlin-kapt")
id("com.google.dagger.hilt.android")
id("com.google.gms.google-services")
}

android {
Expand Down Expand Up @@ -68,6 +69,9 @@ dependencies {
implementation("androidx.test:core-ktx:1.5.0")
implementation("androidx.activity:activity-ktx:1.9.0")
implementation("androidx.test.espresso:espresso-contrib:3.6.1")
implementation("androidx.activity:activity:1.8.0")
implementation("com.google.firebase:firebase-config-ktx:22.0.0")
implementation("com.google.firebase:firebase-common-ktx:21.0.0")
androidTestImplementation("androidx.test:core:1.5.0")
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk-android:1.13.11")
Expand All @@ -91,6 +95,8 @@ dependencies {

implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.3")

implementation(platform("com.google.firebase:firebase-bom:33.1.2"))

}

kapt {
Expand Down
13 changes: 8 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".presenter.view.ErrorActivity"
android:exported="false" />
<activity
android:name=".presenter.view.MapActivity"
android:name=".presenter.view.SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".presenter.view.ErrorActivity"
android:exported="false" />
<activity
android:name=".presenter.view.MapActivity"
android:exported="false"/>
<activity
android:name=".presenter.view.PlaceSearchActivity"
android:exported="false"></activity>
android:exported="false" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.view.View
import android.widget.TextView
import androidx.databinding.BindingAdapter
import campus.tech.kakao.map.R
import campus.tech.kakao.map.domain.vo.ServiceState
import campus.tech.kakao.map.presenter.view.MapActivity

@BindingAdapter("visibleGone")
Expand All @@ -19,3 +20,8 @@ fun setErrorTest(view: TextView, type: ErrorEnum){
else -> view.resources.getString(R.string.else_error)
}
}

@BindingAdapter("splashErrorVisible")
fun isError(view: TextView, serviceState: ServiceState){
view.visibility = if(serviceState == ServiceState.ON_SERVICE) View.GONE else View.VISIBLE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package campus.tech.kakao.map.data

import campus.tech.kakao.map.data.datasource.Local.Entity.toVO
import campus.tech.kakao.map.data.datasource.Remote.ConfigService
import campus.tech.kakao.map.domain.ConfigRepository
import campus.tech.kakao.map.domain.vo.Config
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject

class ConfigRepositoryImpl @Inject constructor(private val configService: ConfigService) : ConfigRepository{
override suspend fun getConfig(): Config = withContext(Dispatchers.IO){ configService.getConfig().toVO() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package campus.tech.kakao.map.data.datasource.Local.Entity

import campus.tech.kakao.map.domain.vo.Config
import campus.tech.kakao.map.domain.vo.ServiceState
import com.google.firebase.remoteconfig.FirebaseRemoteConfig.DEFAULT_VALUE_FOR_STRING

data class ConfigEntity(
val serviceState : String,
val serviceMessage : String
)

fun ConfigEntity.toVO() : Config =
Config(
mapServiceState(serviceState),
if(serviceMessage != DEFAULT_VALUE_FOR_STRING) serviceMessage else "unknown"
)

fun mapServiceState(serviceState: String): ServiceState =
when(serviceState) {
"ON_SERVICE" -> ServiceState.ON_SERVICE
"OUT_OF_ORDER" -> ServiceState.OUT_OF_ORDER
else -> ServiceState.ELSE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package campus.tech.kakao.map.data.datasource.Remote

import campus.tech.kakao.map.R
import campus.tech.kakao.map.data.datasource.Local.Entity.ConfigEntity
import campus.tech.kakao.map.domain.vo.ServiceState
import com.google.firebase.Firebase
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import com.google.firebase.remoteconfig.remoteConfig
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.tasks.asDeferred
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext

class ConfigService {
private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
private val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 0
}

init{
remoteConfig.setConfigSettingsAsync(configSettings)
}

suspend fun getConfig() : ConfigEntity = withContext(Dispatchers.IO){
remoteConfig.fetchAndActivate().await()
ConfigEntity(
remoteConfig.getString("serviceState"),
remoteConfig.getString("serviceMessage")
)
}

}
32 changes: 32 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/di/ConfigModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package campus.tech.kakao.map.data.di

import android.content.SharedPreferences
import campus.tech.kakao.map.data.ConfigRepositoryImpl
import campus.tech.kakao.map.data.PlaceRepositoryImpl
import campus.tech.kakao.map.data.datasource.Local.DB.RoomDB
import campus.tech.kakao.map.data.datasource.Remote.ConfigService
import campus.tech.kakao.map.data.datasource.Remote.RemoteService
import campus.tech.kakao.map.data.datasource.Remote.RetrofitService
import campus.tech.kakao.map.domain.ConfigRepository
import campus.tech.kakao.map.domain.PlaceRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object ConfigModule {

@Provides
@Singleton
fun provideConfigRepository(
configService: ConfigService
) : ConfigRepository =
ConfigRepositoryImpl(configService)

@Provides
@Singleton
fun provideConfigService() : ConfigService = ConfigService()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package campus.tech.kakao.map.domain

import campus.tech.kakao.map.domain.vo.Config

interface ConfigRepository {
suspend fun getConfig() : Config
}
6 changes: 6 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/domain/vo/Config.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package campus.tech.kakao.map.domain.vo

data class Config(
val serviceState : ServiceState,
val serviceMessage : String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package campus.tech.kakao.map.domain.vo

enum class ServiceState {
ON_SERVICE,LOADING,OUT_OF_ORDER,ELSE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package campus.tech.kakao.map.presenter.view

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.databinding.DataBindingUtil
import campus.tech.kakao.map.R
import campus.tech.kakao.map.databinding.ActivitySplashBinding
import campus.tech.kakao.map.domain.vo.ServiceState
import campus.tech.kakao.map.presenter.viewModel.MapViewModel
import campus.tech.kakao.map.presenter.viewModel.SplashViewModel
import com.google.firebase.Firebase
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.get
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import com.google.firebase.remoteconfig.remoteConfig
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class SplashActivity : AppCompatActivity() {
private val viewModel: SplashViewModel by viewModels()
private lateinit var binding: ActivitySplashBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)

binding = DataBindingUtil.setContentView(this, R.layout.activity_splash)
binding.lifecycleOwner = this
binding.viewModel = viewModel

viewModel.config.observe(this){
if(it.serviceState == ServiceState.ON_SERVICE){
startActivity(Intent(this,MapActivity::class.java))
}
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package campus.tech.kakao.map.presenter.viewModel

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import campus.tech.kakao.map.domain.ConfigRepository
import campus.tech.kakao.map.domain.vo.Config
import campus.tech.kakao.map.domain.vo.ServiceState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class SplashViewModel @Inject constructor(
private val configRepository: ConfigRepository
) : ViewModel() {
private val _config: MutableLiveData<Config> = MutableLiveData(
Config(serviceState = ServiceState.LOADING, serviceMessage = "Loading...")
)
val config: LiveData<Config> = _config

init {
viewModelScope.launch {
_config.postValue(configRepository.getConfig())
}
}
}
38 changes: 38 additions & 0 deletions app/src/main/res/layout/activity_splash.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?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="viewModel"
type="campus.tech.kakao.map.presenter.viewModel.SplashViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".presenter.view.SplashActivity">

<ImageView
android:id="@+id/img"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/place_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>

<TextView
android:id="@+id/errorText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/normal_100"
splashErrorVisible="@{viewModel.config.serviceState}"
text="@{viewModel.config.serviceMessage}"
app:layout_constraintTop_toBottomOf="@+id/img"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
11 changes: 11 additions & 0 deletions app/src/main/res/xml/remote_config_defaults.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<defaults>
<entry>
<key>serviceMessage</key>
<value>서버 점검 중입니다. 나중에 다시 시도해 주세요.</value>
</entry>
<entry>
<key>serviceState</key>
<value>ON_SERVICE</value>
</entry>
</defaults>
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
id("org.jlleitschuh.gradle.ktlint") version "12.1.0" apply false
id("com.google.dagger.hilt.android") version "2.48.1" apply false
id("com.google.gms.google-services") version "4.4.2" apply false
}

allprojects {
Expand Down

0 comments on commit 3207489

Please sign in to comment.