Skip to content

Commit

Permalink
Merge pull request #64 from Team-Wable/feature/#63-profile-push-alarm
Browse files Browse the repository at this point in the history
[Feature/#63] : profile push alarm
  • Loading branch information
Eonji-sw authored Sep 4, 2024
2 parents 8b560a2 + 8596e51 commit a300cdf
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package com.teamwable.data.repository

import com.teamwable.model.Profile
import com.teamwable.model.profile.MemberDataModel
import com.teamwable.model.profile.MemberInfoEditModel
import java.io.File

interface ProfileRepository {
suspend fun getProfileInfo(userId: Long): Result<Profile>
suspend fun getMemberData(): Result<MemberDataModel>
suspend fun patchWithdrawal(deletedReason: List<String>): Result<Unit>
suspend fun patchProfileUriEdit(info: MemberInfoEditModel, file: String?): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package com.teamwable.data.repositoryimpl

import android.content.ContentResolver
import com.teamwable.data.mapper.toModel.toMemberDataModel
import com.teamwable.data.mapper.toModel.toProfile
import com.teamwable.data.repository.ProfileRepository
import com.teamwable.model.Profile
import com.teamwable.model.profile.MemberDataModel
import com.teamwable.model.profile.MemberInfoEditModel
import com.teamwable.network.datasource.ProfileService
import com.teamwable.network.dto.request.RequestWithdrawalDto
import com.teamwable.network.util.createImagePart
import com.teamwable.network.util.handleThrowable
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import javax.inject.Inject

class DefaultProfileRepository @Inject constructor(
private val contentResolver: ContentResolver,
private val apiService: ProfileService,
) : ProfileRepository {
override suspend fun getProfileInfo(userId: Long): Result<Profile> = runCatching {
Expand All @@ -31,4 +39,27 @@ class DefaultProfileRepository @Inject constructor(
Unit
}.onFailure { return it.handleThrowable() }
}

override suspend fun patchProfileUriEdit(info: MemberInfoEditModel, file: String?): Result<Unit> {
return runCatching {
val infoRequestBody = createContentRequestBody(info)
val filePart = contentResolver.createImagePart(file)

apiService.patchUserProfile(infoRequestBody, filePart).success
}
}

private fun createContentRequestBody(info: MemberInfoEditModel): RequestBody {
val contentJson = JSONObject().apply {
put("nickname", info.nickname)
put("isAlarmAllowed", info.isAlarmAllowed)
put("memberIntro", info.memberIntro)
put("isPushAlarmAllowed", info.isPushAlarmAllowed)
put("fcmToken", info.fcmToken)
put("memberLckYears", info.memberLckYears)
put("memberFanTeam", info.memberFanTeam)
put("memberDefaultProfileImage", info.memberDefaultProfileImage)
}.toString()
return contentJson.toRequestBody("application/json".toMediaTypeOrNull())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.teamwable.model.profile

data class MemberInfoEditModel(
val nickname: String? = "",
val isAlarmAllowed: Boolean? = false,
val memberIntro: String? = "",
val isPushAlarmAllowed: Boolean? = false,
val fcmToken: String? = "",
val memberLckYears: Int = 0,
val memberFanTeam: String? = "",
val memberDefaultProfileImage: String? = ""
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import com.teamwable.network.dto.response.ResponseProfileInfoDto
import com.teamwable.network.dto.response.profile.ResponseMemberDataDto
import com.teamwable.network.util.BaseResponse
import com.teamwable.network.util.BaseUnitResponse
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
import retrofit2.http.Part
import retrofit2.http.Path

interface ProfileService {
Expand All @@ -21,4 +24,10 @@ interface ProfileService {

@PATCH("api/v1/withdrawal")
suspend fun patchWithdrawal(@Body requestWithdrawalDto: RequestWithdrawalDto): BaseUnitResponse<Unit>

@PATCH("api/v1/user-profile2")
suspend fun patchUserProfile(
@Part("info") requestProfileEdit: RequestBody,
@Part file: MultipartBody.Part?,
): BaseUnitResponse<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.teamwable.ui.extensions

import android.content.Intent
import android.net.Uri
import android.provider.Settings
import android.view.View
import android.widget.Toast
import androidx.annotation.ColorRes
Expand Down Expand Up @@ -48,3 +51,7 @@ fun Fragment.statusBarColorOf(
) {
requireActivity().statusBarColorOf(resId)
}

fun Fragment.openUri(uri: String) {
Intent(Intent.ACTION_VIEW, Uri.parse(uri)).also { startActivity(it) }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.teamwable.news.rank

import android.content.Intent
import android.net.Uri
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
Expand All @@ -11,6 +13,7 @@ import com.teamwable.news.NewsViewModel
import com.teamwable.news.databinding.FragmentNewsRankBinding
import com.teamwable.ui.base.BindingFragment
import com.teamwable.ui.extensions.colorOf
import com.teamwable.ui.extensions.openUri
import com.teamwable.ui.extensions.viewLifeCycle
import com.teamwable.ui.extensions.viewLifeCycleScope
import dagger.hilt.android.AndroidEntryPoint
Expand Down Expand Up @@ -46,7 +49,7 @@ class NewsRankFragment : BindingFragment<FragmentNewsRankBinding>(FragmentNewsRa

private fun initOpinionBtnClickListener() {
binding.btnNewsRankOpinion.setOnClickListener {
// Todo : 나중에 추가해야 함
openUri("https://forms.gle/WWfbHXvGNgXMxgZr5")
}
}

Expand Down
2 changes: 2 additions & 0 deletions feature/profile/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ dependencies {

// Third Party
implementation(libs.glide)
implementation(libs.google.play.services)
implementation(libs.firebase.messaging.ktx)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.teamwable.profile.R
import com.teamwable.profile.databinding.BottomsheetProfileHamburgerBinding
import com.teamwable.ui.base.BindingBottomSheetFragment
import com.teamwable.ui.component.TwoButtonDialog
import com.teamwable.ui.extensions.openUri
import com.teamwable.ui.extensions.viewLifeCycleScope
import com.teamwable.ui.type.DialogType
import com.teamwable.ui.util.Arg.DIALOG_RESULT
Expand Down Expand Up @@ -42,13 +43,13 @@ class ProfileHamburgerBottomSheet : BindingBottomSheetFragment<BottomsheetProfil

private fun initFeedbackBtnClickListener() {
binding.tvProfileHamburgerFeedback.setOnClickListener {
navigateToWeb("https://forms.gle/WWfbHXvGNgXMxgZr5")
openUri("https://forms.gle/WWfbHXvGNgXMxgZr5")
}
}

private fun initCustomerServiceBtnClickListener() {
binding.tvProfileHamburgerCustomerService.setOnClickListener {
navigateToWeb("https://forms.gle/WWfbHXvGNgXMxgZr5")
openUri("https://forms.gle/WWfbHXvGNgXMxgZr5")
}
}

Expand All @@ -74,8 +75,4 @@ class ProfileHamburgerBottomSheet : BindingBottomSheetFragment<BottomsheetProfil
)
)
}

private fun navigateToWeb(uri: String) {
Intent(Intent.ACTION_VIEW, Uri.parse(uri)).also { startActivity(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import com.teamwable.common.uistate.UiState
import com.teamwable.data.repository.ProfileRepository
import com.teamwable.data.repository.UserInfoRepository
import com.teamwable.model.profile.MemberDataModel
import com.teamwable.model.profile.MemberInfoEditModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import javax.inject.Inject

@HiltViewModel
Expand All @@ -23,6 +26,9 @@ class ProfileHamburgerViewModel @Inject constructor(
private val _withdrawalUiState = MutableStateFlow<UiState<Unit>>(UiState.Loading)
val withdrawalUiState = _withdrawalUiState.asStateFlow()

private var _pushAlarmAllowedState = MutableStateFlow(false)
val pushAlarmAllowedState = _pushAlarmAllowedState.asStateFlow()

fun getMemberData() {
viewModelScope.launch {
_memberDataUiState.value = UiState.Loading
Expand Down Expand Up @@ -50,4 +56,18 @@ class ProfileHamburgerViewModel @Inject constructor(
userInfoRepository.saveAutoLogin(check)
}
}

fun patchUserProfileUri(info: MemberInfoEditModel, url: String? = null) {
viewModelScope.launch {
profileRepository.patchProfileUriEdit(info, url)
.onSuccess { info.isPushAlarmAllowed?.let { _pushAlarmAllowedState.value = it } }
.onFailure { Timber.d("fail", it.message.toString()) }
}
}

fun saveIsPushAlarmAllowed(isPushAlarmAllowed: Boolean) =
viewModelScope.launch {
userInfoRepository.saveIsPushAlarmAllowed(isPushAlarmAllowed)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.teamwable.model.profile.MemberDataModel
import com.teamwable.profile.R
import com.teamwable.profile.databinding.FragmentProfileInformationBinding
import com.teamwable.ui.base.BindingFragment
import com.teamwable.ui.extensions.openUri
import com.teamwable.ui.extensions.stringOf
import com.teamwable.ui.extensions.viewLifeCycle
import com.teamwable.ui.extensions.viewLifeCycleScope
Expand All @@ -35,14 +36,10 @@ class ProfileInformationFragment : BindingFragment<FragmentProfileInformationBin

private fun initTermsOfServiceClickListener() {
binding.tvProfileInformationTermsOfServiceContent.setOnClickListener {
navigateToWeb("https://joyous-ghost-8c7.notion.site/c6e26919055a4ff98fd73a8f9b29cb36?pvs=4")
openUri("https://joyous-ghost-8c7.notion.site/c6e26919055a4ff98fd73a8f9b29cb36?pvs=4")
}
}

private fun navigateToWeb(uri: String) {
Intent(Intent.ACTION_VIEW, Uri.parse(uri)).also { startActivity(it) }
}

private fun setupMemberDataObserve() {
viewModel.memberDataUiState.flowWithLifecycle(viewLifeCycle).onEach {
when (it) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.teamwable.profile.hamburger

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.navigation.fragment.findNavController
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.messaging.FirebaseMessaging
import com.teamwable.model.profile.MemberInfoEditModel
import com.teamwable.profile.R
import com.teamwable.profile.databinding.FragmentPushAlarmBinding
import com.teamwable.ui.base.BindingFragment
import com.teamwable.ui.extensions.navigateToAppSettings
import com.teamwable.ui.extensions.stringOf
import com.teamwable.ui.extensions.viewLifeCycle
import com.teamwable.ui.extensions.viewLifeCycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import timber.log.Timber

@AndroidEntryPoint
class PushAlarmFragment : BindingFragment<FragmentPushAlarmBinding>(FragmentPushAlarmBinding::inflate) {
private val viewModel by viewModels<ProfileHamburgerViewModel>()

override fun initView() {
setAppbarText()
setPushAlarmText()

initPushAlarmSettingClickListener()
initBackBtnClickListener()

setupUserPushAlarmInfoObserve()
}

override fun onResume() {
super.onResume()
refreshPushAlarmPermission()
}

private fun refreshPushAlarmPermission() {
setPushAlarmText()
when (checkPushAlarmAllowed()) {
true -> handlePushAlarmPermissionGranted()
false -> handlePushAlarmPermissionDenied()
}
}

private fun handlePushAlarmPermissionGranted() {
FirebaseMessaging.getInstance().token.addOnCompleteListener(
OnCompleteListener { task ->
if (task.isSuccessful) {
viewModel.patchUserProfileUri(
MemberInfoEditModel(
isPushAlarmAllowed = true,
fcmToken = task.result
)
)
Timber.tag("fcm").d("fcm token: $task.result")
} else {
Timber.d(task.exception)
return@OnCompleteListener
}
}
)
}

private fun handlePushAlarmPermissionDenied() {
viewModel.patchUserProfileUri(MemberInfoEditModel(isPushAlarmAllowed = false))
}

private fun setupUserPushAlarmInfoObserve() {
viewModel.pushAlarmAllowedState.flowWithLifecycle(viewLifeCycle).onEach {
viewModel.saveIsPushAlarmAllowed(it)
}.launchIn(viewLifeCycleScope)
}

private fun initPushAlarmSettingClickListener() {
binding.tvPushAlarmContent.setOnClickListener {
requireContext().navigateToAppSettings()
}
binding.btnPushAlarmMore.setOnClickListener {
requireContext().navigateToAppSettings()
}
}


private fun setPushAlarmText() {
binding.tvPushAlarmContent.text =
if (checkPushAlarmAllowed()) getString(R.string.tv_push_alarm_content_on)
else getString(R.string.tv_push_alarm_content_off)
}

private fun checkPushAlarmAllowed(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
} else {
NotificationManagerCompat.from(requireContext()).areNotificationsEnabled()
}
}

private fun setAppbarText() {
binding.viewPushAlarmAppbar.tvProfileAppbarTitle.text = stringOf(R.string.appbar_push_alarm_title)
}

private fun initBackBtnClickListener() {
binding.viewPushAlarmAppbar.btnProfileAppbarBack.setOnClickListener {
findNavController().popBackStack()
}
}
}

This file was deleted.

Loading

0 comments on commit a300cdf

Please sign in to comment.