Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

러닝탭 화면 구현 (현재 러너 카운트 받아오기) #11

Merged
merged 10 commits into from
Nov 17, 2022
9 changes: 9 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
id "com.android.application"
id "org.jetbrains.kotlin.android"
id "kotlin-kapt"
id "dagger.hilt.android.plugin"
}

android {
Expand Down Expand Up @@ -30,6 +32,9 @@ android {
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
dataBinding true
}
}

dependencies {
Expand All @@ -51,4 +56,8 @@ dependencies {

// leakcanary 메모리 누수 체크
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanaryVersion"

// Hilt
implementation "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-android-compiler:$hiltVersion"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package com.whyranoid.mogakrun

import android.app.Application
import com.whyranoid.mogakrun.util.TimberDebugTree
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber

@HiltAndroidApp
class MogakrunApplication : Application() {
override fun onCreate() {
super.onCreate()
Expand Down
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ buildscript {
leakcanaryVersion = "2.10"
kotlinxCoroutinesVersion = "1.6.4"
paging3Version = "3.1.1"
hiltVersion = "2.44"
lottieVersion = "5.2.0" // 병한이 : 로티 추가했습니당
activityKtxVersion = "1.6.1"
fragmentKtxVersion = "1.5.4"
lifecycleViewmodelKtxVersion = "2.5.1"
}
dependencies {
classpath "com.google.gms:google-services:$googleServiceVersion"
Expand All @@ -24,4 +29,5 @@ plugins {
id "com.android.library" version "7.3.1" apply false
id "org.jetbrains.kotlin.android" version "1.7.20" apply false
id 'org.jetbrains.kotlin.jvm' version '1.7.20' apply false
id "com.google.dagger.hilt.android" version "2.44" apply false
}
6 changes: 6 additions & 0 deletions data/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ plugins {
id "com.android.library"
id "org.jetbrains.kotlin.android"
id "com.google.gms.google-services"
id "kotlin-kapt"
id "dagger.hilt.android.plugin"
}

android {
Expand Down Expand Up @@ -42,4 +44,8 @@ dependencies {
implementation platform("com.google.firebase:firebase-bom:$firebaseVersion")
implementation "com.google.firebase:firebase-analytics-ktx"
implementation "com.google.firebase:firebase-firestore-ktx"

// Hilt
implementation "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-android-compiler:$hiltVersion"
}
20 changes: 20 additions & 0 deletions data/src/main/java/com/whyranoid/data/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.whyranoid.data.di

import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {

@Provides
@Singleton
fun provideFireStoreDatabase(): FirebaseFirestore =
Firebase.firestore
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.whyranoid.data.di.running

import kotlinx.coroutines.flow.Flow

interface RunningDataSource {

fun getCurrentRunnerCount(): Flow<Int>

suspend fun startRunning(uid: String): Boolean

suspend fun finishRunning(uid: String): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.whyranoid.data.di.running

import com.google.firebase.firestore.FieldValue
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

class RunningDataSourceImpl(private val db: FirebaseFirestore) : RunningDataSource {

override fun getCurrentRunnerCount(): Flow<Int> = callbackFlow {
db.collection("Runners")
.document("runnersId")
.addSnapshotListener { snapshot, _ ->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 error를 사용하지 않음에도 불구하고 error로 표기해놔서 승민님께 리뷰를 받았는데 _ 로 안쓰는 변수임을 잘 표현해주셨네요..!! error가 어떠한 상황에 발생하는 값인지 확인하고 예외처리가 필요하다면 예외처리해주고 그렇지 않다면 _ 로 사용하지 않음을 명시해주는 것이 좋아보이네요!! 나중에 같이 논의해보면 좋을 것 같습니다

snapshot?.let {
val count = it.data?.size ?: -1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

달리는 사람이 없을 때 -1이라는 값을 플로우로 방출하는 것 같은데 이에 대한 처리가 보이지 않는 것 같습니다! (제가 못 찾는 것일 수도 있지만요..^^) -> 달리고 있는 사람이 -1일 수는 없으니까요!
-1로 에러 케이스임을 명시해준 것은 분명히 좋지만 -1대신 0을 사용하면 별도의 케이스 처리를 해줄 필요도 없을 것 같고 승민님이 리뷰하신 것처럼 0이라는 값을 상수로 관리하면 보기도 좋고 관리하기도 좋아보입니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#13

trySend(count)
}
}

awaitClose()
}

override suspend fun startRunning(uid: String): Boolean {
return suspendCoroutine { continuation ->
db.collection("Runners")
.document("runnersId")
.update(uid, uid)
.addOnSuccessListener {
continuation.resume(true)
}
.addOnFailureListener {
continuation.resume(false)
}
}
}

override suspend fun finishRunning(uid: String): Boolean {
return suspendCoroutine { continuation ->
db.collection("Runners")
.document("runnersId")
.update(uid, FieldValue.delete())
.addOnSuccessListener {
continuation.resume(true)
}
.addOnFailureListener {
continuation.resume(false)
}
}
}
Comment on lines +11 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하드 코딩된 "Runners", "runnersId", -1 등을 변수로 관리하면 가독성이 더 좋을 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#13

}
27 changes: 27 additions & 0 deletions data/src/main/java/com/whyranoid/data/di/running/RunningModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.whyranoid.data.di.running

import com.google.firebase.firestore.FirebaseFirestore
import com.whyranoid.data.running.RunningRepositoryImpl
import com.whyranoid.domain.repository.RunningRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
class RunningModule {

@Provides
@Singleton
fun provideRunningDataSource(db: FirebaseFirestore): RunningDataSource {
return RunningDataSourceImpl(db)
}

@Provides
@Singleton
fun provideRunningRepository(runningDataSource: RunningDataSource): RunningRepository {
return RunningRepositoryImpl(runningDataSource)
}
Comment on lines +22 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희 이번에 인터페이스주입도 그냥 Binds 대신 Provides 사용하기로 했었나요?? 기억이 잘 안나서요!
저도 항상 Provides만 써오긴 했습니다 ㅎㅎ

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확정하지는 않았던거 같은데 오늘 리뷰때 이야기 해보면 좋을거 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#13 : Provides 대신 Binds 사용하기로 결정

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.whyranoid.data.running

import com.whyranoid.data.di.running.RunningDataSource
import com.whyranoid.domain.repository.RunningRepository
import kotlinx.coroutines.flow.Flow

class RunningRepositoryImpl(private val runningDataSource: RunningDataSource) : RunningRepository {
override fun getCurrentRunnerCount(): Flow<Int> {
return runningDataSource.getCurrentRunnerCount()
}

override suspend fun startRunning(uid: String): Boolean {
return true
}

override suspend fun finishRunning(uid: String): Boolean {
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.whyranoid.domain.repository.RunningRepository
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class GetCurrentRunnerCountUseCase @Inject constructor(private val runningRepository: RunningRepository) {
class GetRunnerCountUseCase @Inject constructor(private val runningRepository: RunningRepository) {
operator fun invoke(): Flow<Int> {
return runningRepository.getCurrentRunnerCount()
}
Expand Down
23 changes: 21 additions & 2 deletions presentation/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
plugins {
id "com.android.library"
id "org.jetbrains.kotlin.android"
id "kotlin-kapt"
id "dagger.hilt.android.plugin"
}

android {
Expand Down Expand Up @@ -28,13 +30,15 @@ android {
kotlinOptions {
jvmTarget = "11"
}
dataBinding {
enable = true
buildFeatures {
dataBinding true
}
}

dependencies {

implementation project(":domain")

implementation "androidx.core:core-ktx:$coreKtxVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation "com.google.android.material:material:$materialVersion"
Expand All @@ -45,4 +49,19 @@ dependencies {

// timber 로그
implementation "com.jakewharton.timber:timber:$timberVersion"

// 병한이 : 로티 디펜던시 추가
// lottie
implementation "com.airbnb.android:lottie:$lottieVersion"

// Hilt
implementation "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-android-compiler:$hiltVersion"

// by viewModels
implementation "androidx.activity:activity-ktx:$activityKtxVersion"
implementation "androidx.fragment:fragment-ktx:$fragmentKtxVersion"

// ViewModelScope
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleViewmodelKtxVersion"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.whyranoid.presentation

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ internal abstract class BaseFragment<VDB : ViewDataBinding>(
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
_binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.whyranoid.presentation.runningstart

import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.whyranoid.presentation.R
import com.whyranoid.presentation.base.BaseFragment
import com.whyranoid.presentation.databinding.FragmentRunningStartBinding
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch

@AndroidEntryPoint
internal class RunningStartFragment :
BaseFragment<FragmentRunningStartBinding>(R.layout.fragment_running_start) {

private val viewModel by viewModels<RunningStartViewModel>()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.vm = viewModel

lifecycleScope.launch {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flow를 collect하는 최상위 스코프는 fragment의 lifecycleScope네요..!! (물론 내부에서 viewLifecycleOwner에서 collect를 하는 범위를 컨트롤 해주시긴하지만) 저는 최상위 스코프도 viewLifecycleOwner.lifecycleScope로 두고 사용했거든요!
무한히 collect하는 스코프의 수집 범위를 컨트롤하는 결과는 동일하기도하고 이에 관련해서 차이가 없을 것 같다고 생각이 들긴하는데 어떻게 생각하시나요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#13 : 달리는 사람 수 라이프사이클 변경

viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.runnerCount.collect { runnerCount ->
binding.tvRunnerCountNumber.text = runnerCount.toString()
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.whyranoid.presentation.runningstart

import androidx.lifecycle.ViewModel
import com.whyranoid.domain.usecase.GetRunnerCountUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class RunningStartViewModel @Inject constructor(
getRunnerCountUseCase: GetRunnerCountUseCase
) : ViewModel() {

val runnerCount = getRunnerCountUseCase()
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading