diff --git a/app/src/main/java/com/egobook/app/di/module/RepositoryModule.kt b/app/src/main/java/com/egobook/app/di/module/RepositoryModule.kt index 7f8b0850..6bc50469 100644 --- a/app/src/main/java/com/egobook/app/di/module/RepositoryModule.kt +++ b/app/src/main/java/com/egobook/app/di/module/RepositoryModule.kt @@ -19,11 +19,13 @@ import dagger.Binds import com.egobook.app.domain.repository.QuestionRepository import com.egobook.app.domain.repository.account.AccountRepository import com.egobook.app.domain.repository.diary.DiaryRepository +import com.egobook.app.ui.home.repository.NetworkPsychologyService import com.egobook.app.ui.home.repository.HomeNotificationRepository import com.egobook.app.ui.home.repository.NetworkHomeNotificationRepository import com.egobook.app.ui.home.repository.NetworkTendencyLevelService import com.egobook.app.ui.home.repository.NetworkUserRepository import com.egobook.app.ui.home.repository.UserActivityRepository +import com.egobook.app.ui.home.repository.UserPsychologyRepository import com.egobook.app.ui.home.repository.UserRepository import com.egobook.app.ui.home.repository.UserTendencyRepository import dagger.Module @@ -82,6 +84,10 @@ abstract class RepositoryModule { @Singleton abstract fun bindActivityRecordRepository(impl: NetworkUserRepository): UserActivityRepository + @Binds + @Singleton + abstract fun bindPsychologyRepository(impl: NetworkUserRepository): UserPsychologyRepository + @Binds @Singleton abstract fun bindHomeNotificationRepository(impl: NetworkHomeNotificationRepository): HomeNotificationRepository diff --git a/app/src/main/java/com/egobook/app/ui/home/HomeViewModel.kt b/app/src/main/java/com/egobook/app/ui/home/HomeViewModel.kt index 508f3b21..feddde9d 100644 --- a/app/src/main/java/com/egobook/app/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/egobook/app/ui/home/HomeViewModel.kt @@ -3,6 +3,7 @@ package com.egobook.app.ui.home import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.egobook.app.ui.home.repository.UserPsychologyRepository import com.egobook.app.ui.home.repository.UserRepository import com.egobook.app.ui.home.user.Ink import com.egobook.app.ui.home.user.Level @@ -19,18 +20,21 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( private val userRepository: UserRepository, - private val storeRepository: StoreRepository + private val storeRepository: StoreRepository, + private val psychologyRepository: UserPsychologyRepository ) : ViewModel() { - private val _uiState = MutableStateFlow(User(Level(1), Ink(0))) - val uiState: StateFlow = _uiState.asStateFlow() - - private val _equippedItems = MutableStateFlow>(emptyList()) - val equippedItems: StateFlow> = _equippedItems init { fetchUser() fetchEquipItems() + fetchDailyPhycologyReadState() } + private val _uiState = MutableStateFlow(User(Level(1), Ink(0))) + val uiState: StateFlow = _uiState.asStateFlow() + private val _dailyPhycologyReadState = MutableStateFlow(false) + val dailyPhycologyReadState = _dailyPhycologyReadState.asStateFlow() + private val _equippedItems = MutableStateFlow>(emptyList()) + val equippedItems: StateFlow> = _equippedItems fun fetchEquipItems() { viewModelScope.launch { @@ -38,6 +42,12 @@ class HomeViewModel @Inject constructor( } } + fun fetchDailyPhycologyReadState() { + viewModelScope.launch { + _dailyPhycologyReadState.value = psychologyRepository.isReadDailyPsychology() + } + } + fun fetchUser() { viewModelScope.launch { try { diff --git a/app/src/main/java/com/egobook/app/ui/home/PsychologyViewModel.kt b/app/src/main/java/com/egobook/app/ui/home/PsychologyViewModel.kt new file mode 100644 index 00000000..af18932a --- /dev/null +++ b/app/src/main/java/com/egobook/app/ui/home/PsychologyViewModel.kt @@ -0,0 +1,55 @@ +package com.egobook.app.ui.home + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.egobook.app.ui.home.repository.DailyPsychologyDto +import com.egobook.app.ui.home.repository.PsychologyKnowledge +import com.egobook.app.ui.home.repository.PsychologyReward +import com.egobook.app.ui.home.repository.UserPsychologyRepository +import com.egobook.app.ui.home.repository.UserRepository +import com.egobook.app.ui.home.user.Ink +import com.egobook.app.ui.home.user.Level +import com.egobook.app.ui.home.user.User +import com.egobook.app.ui.shop.CustomItem +import com.egobook.app.ui.shop.StoreRepository +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 javax.inject.Inject + +@HiltViewModel +class PsychologyViewModel @Inject constructor( + private val psychologyRepository: UserPsychologyRepository +) : ViewModel() { + + private val _dailyPhycologyDto = MutableStateFlow( + DailyPsychologyDto( + date = "0000-00-00", + knowledge = PsychologyKnowledge( + knowledgeId = 0, + title = "", + content = "", + source = "" + ), + reward = PsychologyReward( + granted = false, + inkGranted = 0, + inkBalance = 0, + toastMessage = "" + ), + isBookmarked = false + ) + ) + + val dailyPhycologyDto: StateFlow = _dailyPhycologyDto.asStateFlow() + + fun loadDailyPsychology() { + viewModelScope.launch { + _dailyPhycologyDto.value = psychologyRepository.loadDailyPsychology() + } + + } +} diff --git a/app/src/main/java/com/egobook/app/ui/home/repository/UserRepository.kt b/app/src/main/java/com/egobook/app/ui/home/repository/UserRepository.kt index 397d4765..f99ceb37 100644 --- a/app/src/main/java/com/egobook/app/ui/home/repository/UserRepository.kt +++ b/app/src/main/java/com/egobook/app/ui/home/repository/UserRepository.kt @@ -1,5 +1,6 @@ package com.egobook.app.ui.home.repository +import android.util.Log import com.egobook.app.di.qualifier.BackendApi import com.egobook.app.ui.home.user.Tendency import com.egobook.app.ui.home.user.User @@ -16,6 +17,11 @@ interface UserTendencyRepository { suspend fun loadTendencies(): List } +interface UserPsychologyRepository { + suspend fun isReadDailyPsychology(): Boolean + suspend fun loadDailyPsychology(): DailyPsychologyDto +} + interface NetworkUserService { @GET("/home") suspend fun loadBasicUserInformation(): BaseResponse @@ -26,14 +32,49 @@ interface NetworkTendencyLevelService { suspend fun loadTendencyLevels(): BaseResponse } +data class PsychologyStateDto( + val isBottleVisible: Boolean +) + +data class PsychologyKnowledge( + val knowledgeId: Int, + val title: String, + val content: String, + val source: String +) + +data class PsychologyReward( + val granted: Boolean, + val inkGranted: Int, + val inkBalance: Int, + val toastMessage: String +) +data class DailyPsychologyDto( + val date: String, + val knowledge: PsychologyKnowledge, + val reward: PsychologyReward?, + val isBookmarked: Boolean + +) + +interface NetworkPsychologyService { + @GET("/psychology/daily/status") + suspend fun isReadDailyPsychology(): BaseResponse + + @GET("/psychology/daily") + suspend fun loadDailyPsychology(): BaseResponse +} + @Singleton class NetworkUserRepository @Inject constructor( @BackendApi private val retrofit: Retrofit -) : UserRepository, UserTendencyRepository, UserActivityRepository { +) : UserRepository, UserTendencyRepository, UserActivityRepository, UserPsychologyRepository { private val userService by lazy { retrofit.create(NetworkUserService::class.java) } private val tendencyLevelService by lazy { retrofit.create(NetworkTendencyLevelService::class.java) } private val activityRecordService by lazy { retrofit.create(NetworkActivityRecordService::class.java) } + private val psychologyService by lazy { retrofit.create(NetworkPsychologyService::class.java) } + override suspend fun load(): User { val userServiceResponse: BaseResponse = userService.loadBasicUserInformation() return userServiceResponse.data.toDomain() @@ -50,4 +91,17 @@ class NetworkUserRepository @Inject constructor( activityRecordService.loadUserActivityRecord() return activityRecordResponse.data.toDomain() } + + override suspend fun isReadDailyPsychology(): Boolean { + val psychologyResponse: BaseResponse = + psychologyService.isReadDailyPsychology() + Log.d("jang", "isReadDailyPsychology: ${psychologyResponse.data.isBottleVisible}") + return psychologyResponse.data.isBottleVisible + } + + override suspend fun loadDailyPsychology(): DailyPsychologyDto { + val psychologyResponse: BaseResponse = + psychologyService.loadDailyPsychology() + return psychologyResponse.data + } } diff --git a/app/src/main/java/com/egobook/app/ui/home/ui/HomeFragment.kt b/app/src/main/java/com/egobook/app/ui/home/ui/HomeFragment.kt index 990485bc..ccd3362e 100644 --- a/app/src/main/java/com/egobook/app/ui/home/ui/HomeFragment.kt +++ b/app/src/main/java/com/egobook/app/ui/home/ui/HomeFragment.kt @@ -1,6 +1,7 @@ package com.egobook.app.ui.home.ui import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -43,12 +44,10 @@ class HomeFragment(): Fragment() { super.onViewCreated(view, savedInstanceState) val viewModel: HomeViewModel by viewModels() lifecycleScope.launch { - viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.uiState.collect { userState -> - binding.tvLevel.text = "Lv ${userState.level.number}" - binding.ivLevelType.setImageResource(userState.level.type.getResId()) - binding.tvInk.text = "${userState.ink.value}" - } + viewModel.uiState.collect { userState -> + binding.tvLevel.text = "Lv ${userState.level.number}" + binding.ivLevelType.setImageResource(userState.level.type.getResId()) + binding.tvInk.text = "${userState.ink.value}" } } @@ -60,10 +59,48 @@ class HomeFragment(): Fragment() { } } + viewLifecycleOwner.lifecycleScope.launch { + viewModel.dailyPhycologyReadState.collect { phycologyReadState -> + if(phycologyReadState) { + binding.ivDailyBottle.visibility = View.VISIBLE + } else { + binding.ivDailyBottle.visibility = View.INVISIBLE + } + } + } + binding.ivStore.setOnClickListener { findNavController().navigate(R.id.action_homeFragment_to_storeFragment) } + binding.ivDailyBottle.setOnClickListener { + applyScreenBlur(BlurLevel.BASE) + val dialog = PsychologyDialog() + dialog.isCancelable = false + dialog.show(parentFragmentManager, "DailyPsychologyDialog") + binding.ivDailyBottle.visibility = View.INVISIBLE + + parentFragmentManager.setFragmentResultListener("psychology_key", viewLifecycleOwner) { _, _ -> + Log.d("jang", "다이얼로그 닫힘 감지 - 데이터 갱신") + viewModel.fetchUser() + viewModel.fetchDailyPhycologyReadState() + } + } + + binding.ivBottle.setOnClickListener { + applyScreenBlur(BlurLevel.BASE) + val dialog = PsychologyDialog() + dialog.isCancelable = false + dialog.show(parentFragmentManager, "DailyPsychologyDialog") + binding.ivDailyBottle.visibility = View.INVISIBLE + + parentFragmentManager.setFragmentResultListener("psychology_key", viewLifecycleOwner) { _, _ -> + Log.d("jang", "다이얼로그 닫힘 감지 - 데이터 갱신") + viewModel.fetchUser() + viewModel.fetchDailyPhycologyReadState() + } + } + binding.ivAd.setOnClickListener { applyScreenBlur(BlurLevel.BASE) val dialog = AdDialog() diff --git a/app/src/main/java/com/egobook/app/ui/home/ui/PsychologyDialog.kt b/app/src/main/java/com/egobook/app/ui/home/ui/PsychologyDialog.kt new file mode 100644 index 00000000..21626819 --- /dev/null +++ b/app/src/main/java/com/egobook/app/ui/home/ui/PsychologyDialog.kt @@ -0,0 +1,72 @@ +package com.egobook.app.ui.home.ui + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.setFragmentResult +import androidx.lifecycle.lifecycleScope +import com.egobook.app.databinding.DialogAdBinding +import com.egobook.app.databinding.DialogPsychologyBinding +import com.egobook.app.removeScreenBlur +import com.egobook.app.ui.home.HomeViewModel +import com.egobook.app.ui.home.PsychologyViewModel +import kotlinx.coroutines.launch + +class PsychologyDialog() : DialogFragment() { + + private var _binding: DialogPsychologyBinding? = null + private val binding get() = checkNotNull(_binding) { "Fragment가 제거되었습니다." } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + _binding = DialogPsychologyBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val viewModel: PsychologyViewModel by activityViewModels() + + viewModel.loadDailyPsychology() + + viewLifecycleOwner.lifecycleScope.launch { + viewModel.dailyPhycologyDto.collect { dailyPhycologyDto -> + binding.tvPsychologyContent.text = dailyPhycologyDto.knowledge.content + binding.tvPsychologySource.text = dailyPhycologyDto.knowledge.source + binding.tvPsychologyDate.text = dailyPhycologyDto.date + if(dailyPhycologyDto.reward == null) { + binding.btnReward.text = "메인으로 돌아가기" + } else { + binding.btnReward.text = "잉크 ${dailyPhycologyDto.reward.inkGranted}개 획득!" + } + + } + } + + binding.btnReward.setOnClickListener { + removeScreenBlur() + dismiss() + } + } + + override fun dismiss() { + super.dismiss() + setFragmentResult("psychology_key", bundleOf("isUpdated" to true)) + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/res/drawable/ic_bookmark_unclicked.xml b/app/src/main/res/drawable/ic_bookmark_unclicked.xml new file mode 100644 index 00000000..0db0c216 --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark_unclicked.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_bottle.png b/app/src/main/res/drawable/ic_bottle.png new file mode 100644 index 00000000..59fbd897 Binary files /dev/null and b/app/src/main/res/drawable/ic_bottle.png differ diff --git a/app/src/main/res/layout/dialog_psychology.xml b/app/src/main/res/layout/dialog_psychology.xml new file mode 100644 index 00000000..0474e327 --- /dev/null +++ b/app/src/main/res/layout/dialog_psychology.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 29072679..d5ff2292 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -1,5 +1,6 @@ + + + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent"/>