From 943a34bdf7f886b50fc0adc21cfa08f02f6f3798 Mon Sep 17 00:00:00 2001 From: "HyunWoo Lee (Nunu Lee)" <54518925+l2hyunwoo@users.noreply.github.com> Date: Sun, 15 Oct 2023 21:13:20 +0900 Subject: [PATCH] =?UTF-8?q?[feature/remove-databinding]=20Data=20Binding?= =?UTF-8?q?=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=EC=99=80=20kap?= =?UTF-8?q?t=20=ED=94=8C=EB=9F=AC=EA=B7=B8=EC=9D=B8=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=20(#371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove databinding at attendance code dialog * Livedata의 combine 함수 구현하기 * color resource 값 가져오기 * AttendanceActivity쪽 데이터 바인딩 제거 * remove kotlin-kapt and databinding * ktlint apply * remove useless var and change transformation method with livedata * resolve package conflicts * remove useless log * viewModel 상호작용 위치 변경 * apply ktlint --------- Co-authored-by: hjh1161514 --- app/build.gradle.kts | 2 +- .../feature/attendance/AttendanceActivity.kt | 89 ++- .../attendance/AttendanceCodeDialog.kt | 26 +- .../feature/attendance/AttendanceViewModel.kt | 62 +- .../java/org/sopt/official/util/Resource.kt | 5 + .../main/res/layout/activity_attendance.xml | 638 +++++++++--------- .../res/layout/dialog_attendance_code.xml | 335 +++++---- .../org/sopt/official/plugin/CommonConfigs.kt | 2 - build.gradle.kts | 1 - .../lifecycle/FragmentLifecycleOwner.kt | 11 + .../official/common/lifecycle/LiveData.kt | 18 + .../mission/detail/MissionDetailViewModel.kt | 1 - gradle/libs.versions.toml | 2 +- 13 files changed, 621 insertions(+), 571 deletions(-) create mode 100644 core/common/src/main/java/org/sopt/official/common/lifecycle/FragmentLifecycleOwner.kt create mode 100644 core/common/src/main/java/org/sopt/official/common/lifecycle/LiveData.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f5f25654f..bfca95ef5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -75,7 +75,6 @@ android { } } buildFeatures { - viewBinding = true compose = true } composeOptions { @@ -118,6 +117,7 @@ dependencies { implementation(libs.process.phoenix) implementation(libs.compose.destination.core) + implementation(libs.androidx.lifecycle.process) ksp(libs.compose.destination.ksp) androidTestImplementation(platform(libs.compose.bom)) diff --git a/app/src/main/java/org/sopt/official/feature/attendance/AttendanceActivity.kt b/app/src/main/java/org/sopt/official/feature/attendance/AttendanceActivity.kt index 9313bc35b..7c43e5058 100644 --- a/app/src/main/java/org/sopt/official/feature/attendance/AttendanceActivity.kt +++ b/app/src/main/java/org/sopt/official/feature/attendance/AttendanceActivity.kt @@ -14,6 +14,7 @@ import android.widget.TextView import android.widget.Toast import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope @@ -32,26 +33,91 @@ import org.sopt.official.domain.entity.attendance.EventType import org.sopt.official.domain.entity.attendance.SoptEvent import org.sopt.official.feature.attendance.adapter.AttendanceAdapter import org.sopt.official.feature.attendance.model.AttendanceState +import org.sopt.official.util.colorOf import org.sopt.official.util.dp +import org.sopt.official.util.stringOf @AndroidEntryPoint class AttendanceActivity : AppCompatActivity() { private lateinit var binding: ActivityAttendanceBinding - private val attendanceViewModel by viewModels() + private val viewModel by viewModels() private lateinit var attendanceAdapter: AttendanceAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityAttendanceBinding.inflate(layoutInflater) setContentView(binding.root) - binding.viewModel = attendanceViewModel - binding.lifecycleOwner = this initView() initUiInteraction() initListener() - fetchData() observeData() + observeProgressState() + } + + private fun observeProgressState() { + viewModel.isFirstToSecondLineActive.observe(this) { + binding.lineFirstToSecondActive.isInvisible = !it + } + viewModel.isSecondToThirdLineActive.observe(this) { + binding.lineSecondToThirdActive.isInvisible = !it + } + viewModel.isFirstProgressBarAttendance.observe(this) { + binding.ivAttendanceProgress1Check.setImageResource( + if (it) R.drawable.ic_attendance_check_gray else R.drawable.ic_attendance_close_gray + ) + } + viewModel.isFirstProgressBarActive.observe(this) { + binding.ivAttendanceProgress1Check.isInvisible = !it + binding.tvAttendanceProgress1.setTextColor( + if (it) colorOf(R.color.white_100) else colorOf(R.color.gray_100) + ) + } + viewModel.isSecondProgressBarAttendance.observe(this) { + binding.ivAttendanceProgress2Check.setImageResource( + if (it) R.drawable.ic_attendance_check_gray else R.drawable.ic_attendance_close_gray + ) + } + viewModel.isSecondProgressBarActive.observe(this) { + binding.ivAttendanceProgress2Check.isInvisible = !it + binding.tvAttendanceProgress2.setTextColor( + if (it) colorOf(R.color.white_100) else colorOf(R.color.gray_100) + ) + } + viewModel.isThirdProgressBarVisible.observe(this) { + binding.ivAttendanceProgress3Tardy.isInvisible = !it + binding.ivAttendanceProgress3Attendance.isInvisible = it + binding.tvAttendanceProgress3.text = stringOf( + if (it) R.string.attendance_progress_third_tardy else R.string.attendance_progress_third_complete + ) + } + viewModel.isThirdProgressBarActive.observe(this) { + binding.ivAttendanceProgress3Empty.isInvisible = it + binding.tvAttendanceProgress3Attendance.text = stringOf( + if (it) R.string.attendance_progress_third_absent else R.string.attendance_progress_before + ) + binding.tvAttendanceProgress3Attendance.setTextColor( + if (it) colorOf(R.color.white_100) else colorOf(R.color.gray_100) + ) + } + viewModel.isThirdProgressBarBeforeAttendance.observe(this) { + binding.ivAttendanceProgress3Attendance.setImageResource( + if (it) R.drawable.ic_attendacne_check_white else R.drawable.ic_attendance_close_white + ) + } + viewModel.isThirdProgressBarActiveAndBeforeAttendance.observe(this) { + binding.tvAttendanceProgress3.isInvisible = !it + binding.tvAttendanceProgress3Attendance.isInvisible = it + } + viewModel.isAttendanceButtonEnabled.observe(this) { + binding.btnAttendance.isEnabled = it + } + viewModel.attendanceButtonText.observe(this) { + binding.btnAttendance.text = it + } + viewModel.isAttendanceButtonVisibility.observe(this) { + binding.btnAttendance.isVisible = it + } } private fun initView() { @@ -63,14 +129,7 @@ class AttendanceActivity : AppCompatActivity() { private fun initUiInteraction() { binding.icRefresh.setOnClickListener { it.startAnimation(AnimationUtils.loadAnimation(this, R.anim.anim_rotation)) - fetchData() - } - } - - private fun fetchData() { - attendanceViewModel.run { - fetchSoptEvent() - fetchAttendanceHistory() + viewModel.fetchData() } } @@ -121,7 +180,7 @@ class AttendanceActivity : AppCompatActivity() { } private fun observeSoptEvent() { - attendanceViewModel.soptEvent + viewModel.soptEvent .flowWithLifecycle(lifecycle) .onEach { when (it) { @@ -133,7 +192,7 @@ class AttendanceActivity : AppCompatActivity() { } private fun observeAttendanceHistory() { - attendanceViewModel.attendanceHistory + viewModel.attendanceHistory .flowWithLifecycle(lifecycle) .onEach { when (it) { @@ -192,7 +251,7 @@ class AttendanceActivity : AppCompatActivity() { setSpan(StyleSpan(Typeface.BOLD), 4, 4 + (soptEvent.eventName.length), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } layoutAttendanceProgress.isVisible = true - attendanceViewModel.setProgressBar(soptEvent) + viewModel.setProgressBar(soptEvent) when (soptEvent.attendances.size) { 1 -> { tvAttendanceProgress1.text = if (soptEvent.attendances[0].status == AttendanceStatus.ATTENDANCE) { diff --git a/app/src/main/java/org/sopt/official/feature/attendance/AttendanceCodeDialog.kt b/app/src/main/java/org/sopt/official/feature/attendance/AttendanceCodeDialog.kt index 0865d7885..1216394a4 100644 --- a/app/src/main/java/org/sopt/official/feature/attendance/AttendanceCodeDialog.kt +++ b/app/src/main/java/org/sopt/official/feature/attendance/AttendanceCodeDialog.kt @@ -17,8 +17,11 @@ import androidx.core.widget.addTextChangedListener import androidx.core.widget.doAfterTextChanged import androidx.fragment.app.DialogFragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.sopt.official.databinding.DialogAttendanceCodeBinding import org.sopt.official.feature.attendance.model.DialogState @@ -26,8 +29,8 @@ import org.sopt.official.feature.attendance.model.DialogState class AttendanceCodeDialog : DialogFragment() { private var _binding: DialogAttendanceCodeBinding? = null private val binding: DialogAttendanceCodeBinding get() = requireNotNull(_binding) - private val attendanceViewModel: AttendanceViewModel by activityViewModels() - private var title: String = "" + private val viewModel: AttendanceViewModel by activityViewModels() + private lateinit var dialogTitle: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -51,7 +54,6 @@ class AttendanceCodeDialog : DialogFragment() { savedInstanceState: Bundle? ): View { _binding = DialogAttendanceCodeBinding.inflate(inflater, container, false) - binding.lifecycleOwner = viewLifecycleOwner return binding.root } @@ -63,12 +65,16 @@ class AttendanceCodeDialog : DialogFragment() { } fun setTitle(title: String): AttendanceCodeDialog { - this.title = title + dialogTitle = title return this } private fun initTitle() { - binding.titleText = "${title.substring(0, 5)}하기" + viewModel.initDialogTitle(dialogTitle) + viewModel.title + .flowWithLifecycle(viewLifecycleOwner.lifecycle) + .onEach { binding.tvAttendanceCodeDialogTitle.text = "${it.substring(0, 5)}하기" } + .launchIn(viewLifecycleOwner.lifecycleScope) } private fun initListener() { @@ -178,7 +184,7 @@ class AttendanceCodeDialog : DialogFragment() { dismiss() } btnAttendanceCodeDialog.setOnClickListener { - attendanceViewModel.checkAttendanceCode( + viewModel.checkAttendanceCode( "${etAttendanceCode1.text}${etAttendanceCode2.text}${etAttendanceCode3.text}" + "${etAttendanceCode4.text}${etAttendanceCode5.text}" ) @@ -187,17 +193,17 @@ class AttendanceCodeDialog : DialogFragment() { } override fun dismiss() { - attendanceViewModel.initDialogState() + viewModel.initDialogState() super.dismiss() } private fun observeState() { viewLifecycleOwner.lifecycleScope.launch { - attendanceViewModel.dialogState.collectLatest { + viewModel.dialogState.collectLatest { when (it) { is DialogState.Close -> { dismiss() - attendanceViewModel.run { + viewModel.run { fetchSoptEvent() initDialogState() dialogErrorMessage = "" @@ -219,7 +225,7 @@ class AttendanceCodeDialog : DialogFragment() { // 에러 메시지 나타나도록 tvAttendanceCodeDialogError.visibility = View.VISIBLE - tvAttendanceCodeDialogError.text = attendanceViewModel.dialogErrorMessage + tvAttendanceCodeDialogError.text = viewModel.dialogErrorMessage // 키보드 내리기 hideKeyboard() diff --git a/app/src/main/java/org/sopt/official/feature/attendance/AttendanceViewModel.kt b/app/src/main/java/org/sopt/official/feature/attendance/AttendanceViewModel.kt index 04bcc7376..2d27ea5c4 100644 --- a/app/src/main/java/org/sopt/official/feature/attendance/AttendanceViewModel.kt +++ b/app/src/main/java/org/sopt/official/feature/attendance/AttendanceViewModel.kt @@ -1,6 +1,5 @@ package org.sopt.official.feature.attendance -import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -9,6 +8,7 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import org.sopt.official.domain.entity.attendance.AttendanceHistory import org.sopt.official.domain.entity.attendance.AttendanceRound @@ -44,13 +44,15 @@ class AttendanceViewModel @Inject constructor( private val attendanceRepository: AttendanceRepository ) : ViewModel() { private var eventId: Int = 0 - private var _soptEvent = MutableStateFlow>(AttendanceState.Init) + private val _title: MutableStateFlow = MutableStateFlow("") + val title = _title.asStateFlow() + private val _soptEvent = MutableStateFlow>(AttendanceState.Init) val soptEvent: StateFlow> get() = _soptEvent - private var _attendanceHistory = MutableStateFlow>(AttendanceState.Init) + private val _attendanceHistory = MutableStateFlow>(AttendanceState.Init) val attendanceHistory: StateFlow> get() = _attendanceHistory - private var _attendanceRound = MutableStateFlow>(AttendanceState.Init) + private val _attendanceRound = MutableStateFlow>(AttendanceState.Init) val attendanceRound: StateFlow> get() = _attendanceRound - private var _dialogState = MutableStateFlow(DialogState.Show) + private val _dialogState = MutableStateFlow(DialogState.Show) val dialogState: StateFlow get() = _dialogState private val progressBarState = MutableLiveData(ProgressBarState()) @@ -62,8 +64,11 @@ class AttendanceViewModel @Inject constructor( val isSecondToThirdLineActive: LiveData = progressBarState.map { it.isSecondToThirdLineActive } val isThirdProgressBarActive: LiveData = progressBarState.map { it.isThirdProgressBarActive } val isThirdProgressBarAttendance: LiveData = progressBarState.map { it.isThirdProgressBarAttendance } - val isThirdProgressBarTardy: LiveData = progressBarState.map { it.isThirdProgressBarTardy } + private val isThirdProgressBarTardy: LiveData = progressBarState.map { it.isThirdProgressBarTardy } val isThirdProgressBarBeforeAttendance: LiveData = progressBarState.map { it.isThirdProgressBarBeforeAttendance } + val isThirdProgressBarVisible = progressBarState.map { it.isThirdProgressBarActive && it.isThirdProgressBarTardy } + val isThirdProgressBarActiveAndBeforeAttendance = + progressBarState.map { it.isThirdProgressBarActive && it.isThirdProgressBarBeforeAttendance } private val attendanceButtonState = MutableLiveData(AttendanceButtonState()) val isAttendanceButtonEnabled: LiveData = attendanceButtonState.map { it.isAttendanceButtonEnabled } @@ -74,9 +79,17 @@ class AttendanceViewModel @Inject constructor( var dialogErrorMessage: String = "" private var attendancesSize = 0 - companion object { - private const val FIRST_ATTENDANCE_TEXT = "1차 출석" - private const val SECOND_ATTENDANCE_TEXT = "2차 출석" + init { + fetchData() + } + + fun fetchData() { + fetchSoptEvent() + fetchAttendanceHistory() + } + + fun initDialogTitle(title: String) { + _title.value = title } fun fetchSoptEvent() { @@ -125,9 +138,6 @@ class AttendanceViewModel @Inject constructor( val firstProgressText = soptEvent.attendances[0].attendedAt val secondProgressText = soptEvent.attendances[1].attendedAt - Log.d("####hj", firstProgressText) - Log.d("####hj", secondProgressText) - if (firstProgressText != FIRST_ATTENDANCE_TEXT) { // 1차 출석이 출석 setFirstProgressBar(true) @@ -229,7 +239,7 @@ class AttendanceViewModel @Inject constructor( setProgressBarState { copy(isThirdProgressBarBeforeAttendance = isBeforeAttendance) } } - fun fetchAttendanceHistory() { + private fun fetchAttendanceHistory() { viewModelScope.launch { _attendanceHistory.value = AttendanceState.Loading attendanceRepository.fetchAttendanceHistory() @@ -247,7 +257,6 @@ class AttendanceViewModel @Inject constructor( .onSuccess { _attendanceRound.value = AttendanceState.Success(it) subLectureId = it.id - Timber.tag("zzzz id").i(it.id.toString()) when (it.id) { -1L -> { setAttendanceButtonVisibility(false) @@ -272,7 +281,6 @@ class AttendanceViewModel @Inject constructor( } } }.onFailure { - Timber.tag("zzzz failure").e(it) Timber.e(it) } } @@ -295,21 +303,10 @@ class AttendanceViewModel @Inject constructor( attendanceRepository.confirmAttendanceCode(subLectureId, code) .onSuccess { when (it.subLectureId) { - -2L -> { - showDialog("코드가 일치하지 않아요!") - } - - -1L -> { - showDialog("출석 시간 전입니다.") - } - - 0L -> { - showDialog("출석이 이미 종료되었습니다.") - } - - else -> { - _dialogState.value = DialogState.Close - } + -2L -> showDialog("코드가 일치하지 않아요!") + -1L -> showDialog("출석 시간 전입니다.") + 0L -> showDialog("출석이 이미 종료되었습니다.") + else -> _dialogState.value = DialogState.Close } }.onFailure { Timber.e(it) @@ -325,4 +322,9 @@ class AttendanceViewModel @Inject constructor( dialogErrorMessage = message _dialogState.value = DialogState.Failure } + + companion object { + private const val FIRST_ATTENDANCE_TEXT = "1차 출석" + private const val SECOND_ATTENDANCE_TEXT = "2차 출석" + } } diff --git a/app/src/main/java/org/sopt/official/util/Resource.kt b/app/src/main/java/org/sopt/official/util/Resource.kt index 473101ef7..af5ddc713 100644 --- a/app/src/main/java/org/sopt/official/util/Resource.kt +++ b/app/src/main/java/org/sopt/official/util/Resource.kt @@ -1,6 +1,7 @@ package org.sopt.official.util import android.content.Context +import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.appcompat.content.res.AppCompatResources @@ -14,6 +15,10 @@ fun Context.stringOf(@StringRes id: Int, vararg args: String) = getString(id, *a fun Context.drawableOf(@DrawableRes id: Int) = AppCompatResources.getDrawable(this, id) +fun Context.colorOf(@ColorRes id: Int) = getColor(id) + fun Fragment.stringOf(@StringRes id: Int) = requireContext().stringOf(id) fun Fragment.drawableOf(@DrawableRes id: Int) = requireContext().drawableOf(id) + +fun Fragment.colorOf(@ColorRes id: Int) = requireContext().getColor(id) diff --git a/app/src/main/res/layout/activity_attendance.xml b/app/src/main/res/layout/activity_attendance.xml index eeca52330..7e397e5e7 100644 --- a/app/src/main/res/layout/activity_attendance.xml +++ b/app/src/main/res/layout/activity_attendance.xml @@ -1,371 +1,339 @@ - - + + + - + + + - - + + + android:layout_height="wrap_content" + android:layout_marginHorizontal="20dp" + android:layout_marginTop="16dp" + android:background="@drawable/rectangle_radius_16" + android:backgroundTint="@color/black_80" + android:paddingHorizontal="24dp" + android:paddingVertical="32dp" + app:layout_constraintTop_toBottomOf="@id/layout_app_bar"> - - - - - - - - - + android:src="@drawable/ic_attendance_event_date" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + - - - - - - - - - - - - - - + android:layout_marginTop="8dp" + app:layout_constraintTop_toBottomOf="@id/layout_info_event_date"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/image_info_event_location" + app:layout_constraintTop_toTopOf="parent" + tools:text="건국대학교 꽥꽥오리관" /> - - - + + + app:layout_constraintTop_toBottomOf="@+id/text_info_event_point"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + + + + + + diff --git a/app/src/main/res/layout/dialog_attendance_code.xml b/app/src/main/res/layout/dialog_attendance_code.xml index 142eaedf9..dcba5b700 100644 --- a/app/src/main/res/layout/dialog_attendance_code.xml +++ b/app/src/main/res/layout/dialog_attendance_code.xml @@ -1,182 +1,167 @@ - - - - - - - - - - + + - - + + + + + + + + - - + + - - + + - - - - - - - - - - - - - - - + + - - - - - \ No newline at end of file + android:layout_height="match_parent" + android:layout_marginStart="6dp" + android:layout_marginEnd="6dp" + android:layout_weight="1" + android:background="@drawable/selector_edittext_attendance_code" + android:cursorVisible="false" + android:ems="10" + android:gravity="center" + android:inputType="numberSigned" + android:maxLength="1" + android:textColor="@color/gray_20" /> + + + + + + + + + diff --git a/build-logic/convention/src/main/kotlin/org/sopt/official/plugin/CommonConfigs.kt b/build-logic/convention/src/main/kotlin/org/sopt/official/plugin/CommonConfigs.kt index 30324f416..c63e41314 100644 --- a/build-logic/convention/src/main/kotlin/org/sopt/official/plugin/CommonConfigs.kt +++ b/build-logic/convention/src/main/kotlin/org/sopt/official/plugin/CommonConfigs.kt @@ -16,7 +16,6 @@ internal fun Project.configureAndroidCommonPlugin() { apply() apply() with(plugins) { - apply("kotlin-kapt") apply("kotlin-parcelize") } apply() @@ -42,7 +41,6 @@ internal fun Project.configureAndroidCommonPlugin() { buildConfigField("String", "AMPLITUDE_KEY", amplitudeKey) } buildFeatures.apply { - dataBinding.enable = true viewBinding = true buildConfig = true } diff --git a/build.gradle.kts b/build.gradle.kts index 82b874826..4e5db496c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,6 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false - alias(libs.plugins.kotlin.kapt) apply false alias(libs.plugins.dagger.hilt) apply false alias(libs.plugins.google.services) apply false alias(libs.plugins.crashlytics) apply false diff --git a/core/common/src/main/java/org/sopt/official/common/lifecycle/FragmentLifecycleOwner.kt b/core/common/src/main/java/org/sopt/official/common/lifecycle/FragmentLifecycleOwner.kt new file mode 100644 index 000000000..c64a3156a --- /dev/null +++ b/core/common/src/main/java/org/sopt/official/common/lifecycle/FragmentLifecycleOwner.kt @@ -0,0 +1,11 @@ +package org.sopt.official.core.lifecycle + +import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope + +val Fragment.viewLifeCycle: Lifecycle + get() = viewLifecycleOwner.lifecycle + +val Fragment.viewLifeCycleScope + get() = viewLifecycleOwner.lifecycleScope diff --git a/core/common/src/main/java/org/sopt/official/common/lifecycle/LiveData.kt b/core/common/src/main/java/org/sopt/official/common/lifecycle/LiveData.kt new file mode 100644 index 000000000..34fc23864 --- /dev/null +++ b/core/common/src/main/java/org/sopt/official/common/lifecycle/LiveData.kt @@ -0,0 +1,18 @@ +package org.sopt.official.core.lifecycle + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData + +inline fun LiveData.combineWith( + liveData: LiveData, + crossinline block: (T?, K?) -> R +): LiveData { + val result = MediatorLiveData() + result.addSource(this) { + result.value = block(this.value, liveData.value) + } + result.addSource(liveData) { + result.value = block(this.value, liveData.value) + } + return result +} diff --git a/feature/soptamp/src/main/java/org/sopt/official/stamp/feature/mission/detail/MissionDetailViewModel.kt b/feature/soptamp/src/main/java/org/sopt/official/stamp/feature/mission/detail/MissionDetailViewModel.kt index b2fbf35dd..2d8dd8b19 100644 --- a/feature/soptamp/src/main/java/org/sopt/official/stamp/feature/mission/detail/MissionDetailViewModel.kt +++ b/feature/soptamp/src/main/java/org/sopt/official/stamp/feature/mission/detail/MissionDetailViewModel.kt @@ -192,7 +192,6 @@ class MissionDetailViewModel @Inject constructor( private suspend fun handleSubmit() { viewModelScope.launch { val currentState = uiState.value - Timber.d("MissionDetailViewModel onSubmit() $currentState") val (id, imageUri, content) = currentState uiState.update { it.copy(isError = false, error = null, isLoading = true) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6c81fd75a..9d3dea1e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -173,6 +173,7 @@ rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroi rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" } rxkotlin = { module = "io.reactivex.rxjava3:rxkotlin", version.ref = "rxkotlin" } rxbinding = { module = "com.jakewharton.rxbinding4:rxbinding", version.ref = "rxbinding" } +androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "lifecycle" } amplitude-android = { module = "com.amplitude:analytics-android", version.ref = "amplitude" } [bundles] @@ -207,7 +208,6 @@ androidx-android-test = ["androidx-test-runner", "androidx-test-rules", "android android-application = { id = "com.android.application", version.ref = "gradleplugin" } android-library = { id = "com.android.library", version.ref = "gradleplugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "dagger-hilt" } google-services = { id = "com.google.gms.google-services", version.ref = "google-services" } crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "crashlytics" }