-
Notifications
You must be signed in to change notification settings - Fork 0
[Feat] mypage UI #75
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
[Feat] mypage UI #75
Changes from all commits
09a7bc5
37a835a
1309bb4
57d728e
798b12d
f5a9125
a12c184
cf17be9
7e11d98
7188274
b767cfa
e286c3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,33 @@ | ||
| package com.example.findu.presentation.ui.my | ||
|
|
||
| import android.Manifest | ||
| import android.content.ActivityNotFoundException | ||
| import android.content.Intent | ||
| import android.net.Uri | ||
| import android.os.Bundle | ||
| import android.util.Log | ||
| import android.view.LayoutInflater | ||
| import android.view.View | ||
| import android.view.ViewGroup | ||
| import android.widget.Toast | ||
| import androidx.activity.result.ActivityResultLauncher | ||
| import androidx.activity.result.PickVisualMediaRequest | ||
| import androidx.activity.result.contract.ActivityResultContracts | ||
| import androidx.core.view.isVisible | ||
| import androidx.core.widget.addTextChangedListener | ||
| import androidx.fragment.app.Fragment | ||
| import androidx.fragment.app.viewModels | ||
| import androidx.lifecycle.Lifecycle | ||
| import androidx.lifecycle.lifecycleScope | ||
| import androidx.lifecycle.repeatOnLifecycle | ||
| import androidx.navigation.fragment.findNavController | ||
| import com.example.findu.BuildConfig | ||
| import com.example.findu.R | ||
| import com.example.findu.databinding.FragmentMyBinding | ||
| import com.example.findu.presentation.ui.login.LoginActivity | ||
| import com.example.findu.presentation.ui.my.dialog.MyLogoutDialog | ||
| import com.example.findu.presentation.ui.my.dialog.MyNicknameDialog | ||
| import com.example.findu.presentation.ui.my.dialog.MyProfileImageDialog | ||
| import com.example.findu.presentation.ui.my.dialog.MyWithdrawalDialog | ||
| import com.example.findu.presentation.util.PermissionUtils.hasCameraPermission | ||
| import com.example.findu.presentation.util.PermissionUtils.hasLocationPermission | ||
| import com.example.findu.presentation.util.PermissionUtils.requestLocationPermission | ||
| import dagger.hilt.android.AndroidEntryPoint | ||
| import kotlinx.coroutines.launch | ||
|
|
||
|
|
@@ -34,25 +37,27 @@ class MyFragment : Fragment() { | |
| private val binding get() = _binding!! | ||
| private val myViewModel by viewModels<MyViewModel>() | ||
|
|
||
| private lateinit var requestPermissionLauncher: ActivityResultLauncher<String> | ||
| private lateinit var pickMedia: ActivityResultLauncher<PickVisualMediaRequest> | ||
| private var myProfileImageDialog: MyProfileImageDialog? = null | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
|
|
||
| requestPermissionLauncher = | ||
| registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> | ||
| if (isGranted) { | ||
| Toast.makeText(requireContext(), "๊ถํ์ด ํ์ฉ๋์์ต๋๋ค.", Toast.LENGTH_SHORT).show() | ||
| } else { | ||
| findNavController().popBackStack() | ||
| } | ||
| pickMedia = registerForActivityResult( | ||
| ActivityResultContracts.PickVisualMedia() | ||
| ) { uri: Uri? -> | ||
| if (uri != null) { | ||
| myProfileImageDialog?.setGalleryImage(uri) | ||
| } else { | ||
| Toast.makeText(requireContext(), "์ด๋ฏธ์ง๊ฐ ์ ํ๋์ง ์์์ด์.", Toast.LENGTH_SHORT).show() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| override fun onCreateView( | ||
| inflater: LayoutInflater, | ||
| container: ViewGroup?, | ||
| savedInstanceState: Bundle? | ||
| savedInstanceState: Bundle?, | ||
| ): View { | ||
| _binding = FragmentMyBinding.inflate(inflater, container, false) | ||
|
|
||
|
|
@@ -63,18 +68,32 @@ class MyFragment : Fragment() { | |
| } | ||
|
|
||
| private fun initListener() { | ||
|
|
||
| with(binding) { | ||
| llMyNickname.setOnClickListener { | ||
| llMyNickname.visibility = View.INVISIBLE | ||
| llMyEditNickname.visibility = View.VISIBLE | ||
| MyNicknameDialog( | ||
| context = requireContext(), | ||
| onNicknameChange = { newNickname -> | ||
| myViewModel.updateNickName(newNickname) | ||
| } | ||
| ).show() | ||
| } | ||
|
|
||
| btnMyDoneEdit.setOnClickListener { | ||
| llMyNickname.visibility = View.VISIBLE | ||
| llMyEditNickname.visibility = View.INVISIBLE | ||
|
|
||
| myViewModel.updateNickName(etMyNickname.text.toString()) | ||
| clMyProflieImage.setOnClickListener { | ||
| myProfileImageDialog = MyProfileImageDialog( | ||
| context = requireContext(), | ||
| onDrawableSelected = { resId -> | ||
| myViewModel.updateProfileImage(resId) | ||
| }, | ||
| onGallerySelected = { uri -> | ||
| myViewModel.updateProfileImageFromGallery(uri) | ||
| }, | ||
| launchGallery = { | ||
| pickMedia.launch( | ||
| PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) | ||
| ) | ||
| } | ||
| ) | ||
| myProfileImageDialog?.show() | ||
| } | ||
|
|
||
| etMyNickname.addTextChangedListener { text -> | ||
|
|
@@ -93,35 +112,40 @@ class MyFragment : Fragment() { | |
| findNavController().navigate(R.id.action_fragment_my_to_fragment_my_keep_animals) | ||
| } | ||
|
|
||
| clMyCameraPermission.setOnClickListener { | ||
| if (hasCameraPermission(requireContext())) { | ||
| Toast.makeText(requireContext(), "์นด๋ฉ๋ผ ๊ถํ์ด ์ด๋ฏธ ํ์ฉ๋์์ต๋๋ค.", Toast.LENGTH_SHORT) | ||
| .show() | ||
| } else { | ||
| requestPermissionLauncher.launch(Manifest.permission.CAMERA) | ||
| } | ||
| clMyInquire.setOnClickListener { | ||
| findNavController().navigate(R.id.action_fragment_my_to_fragment_inquire) | ||
| } | ||
|
|
||
| clMyLocationPermission.setOnClickListener { | ||
| if (hasLocationPermission(requireContext())) { | ||
| Toast.makeText(requireContext(), "์์น ๊ถํ์ด ์ด๋ฏธ ํ์ฉ๋์์ต๋๋ค.", Toast.LENGTH_SHORT) | ||
| .show() | ||
| } else { | ||
| requestLocationPermission(requireActivity()) | ||
| } | ||
| } | ||
|
|
||
| clMyLogout.setOnClickListener { | ||
| val logoutClickListener = View.OnClickListener { | ||
| MyLogoutDialog( | ||
| context = requireContext(), | ||
| onLogoutClick = { | ||
| with(requireActivity()) { | ||
| startActivity( | ||
| Intent(requireContext(), LoginActivity::class.java) | ||
| ) | ||
| startActivity(Intent(requireContext(), LoginActivity::class.java)) | ||
| finish() | ||
| } | ||
| }).show() | ||
| } | ||
| ).show() | ||
| } | ||
|
|
||
| clMyLogout.setOnClickListener(logoutClickListener) | ||
| tvMyVersionInfo.setOnClickListener(logoutClickListener) | ||
| chipMyVersion.setOnClickListener(logoutClickListener) | ||
|
|
||
| clMyGotoUpdate.setOnClickListener { | ||
| val pkg = requireContext().packageName | ||
| try { | ||
| startActivity( | ||
| Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkg")) | ||
| ) | ||
| } catch (e: ActivityNotFoundException) { | ||
| startActivity( | ||
| Intent( | ||
| Intent.ACTION_VIEW, | ||
| Uri.parse("https://play.google.com/store/apps/details?id=$pkg") | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| clMyWithdrawal.setOnClickListener { | ||
|
|
@@ -137,9 +161,25 @@ class MyFragment : Fragment() { | |
| } | ||
| }).show() | ||
| } | ||
|
|
||
| clMyAlarmSetting.setOnClickListener { | ||
| myViewModel.toggleAlarmSetting() | ||
| } | ||
|
|
||
| setupVersion() | ||
| } | ||
| } | ||
|
|
||
| private fun setupVersion() = with(binding) { | ||
| val currentVersion = BuildConfig.VERSION_NAME | ||
| val latest = "1.0" | ||
| tvMyVersionInfo.text = "๋ฒ์ ์ ๋ณด $currentVersion" | ||
|
|
||
| val isLatest = currentVersion.replace(".", "").toInt() >= latest.replace(".", "").toInt() | ||
| clMyVersionChip.isVisible = isLatest | ||
| clMyGotoUpdate.isVisible = !isLatest | ||
| } | ||
|
Comment on lines
+173
to
+181
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion ๋ฒ์ ๋น๊ต ๋ก์ง์ด ์ทจ์ฝํฉ๋๋ค (๋ฌธ์ ํฌํจ/์ธ๊ทธ๋จผํธ ์ ๋ถ์ผ์น ์ NFE ์ํ) "." ์ ๊ฑฐ ํ toInt ๋น๊ต๋ "1.0.0-alpha" ๊ฐ์ ๋ฒ์ ์์ NumberFormatException์ ์ ๋ฐํ ์ ์์ต๋๋ค. ์ธ๊ทธ๋จผํธ ๋จ์ ๋น๊ต๋ก ๊ต์ฒดํด์ฃผ์ธ์. private fun setupVersion() = with(binding) {
val currentVersion = BuildConfig.VERSION_NAME
val latest = "1.0"
tvMyVersionInfo.text = "๋ฒ์ ์ ๋ณด $currentVersion"
- val isLatest = currentVersion.replace(".", "").toInt() >= latest.replace(".", "").toInt()
+ val isLatest = compareVersionNames(currentVersion, latest) >= 0
clMyVersionChip.isVisible = isLatest
clMyGotoUpdate.isVisible = !isLatest
}์๋ ์ ํธ ํจ์๋ฅผ ๋ณธ ํ์ผ ํ๋จ(ํด๋์ค ์) ์ด๋๊ฐ์ ์ถ๊ฐํด ์ฃผ์ธ์: private fun compareVersionNames(a: String, b: String): Int {
fun parse(v: String): List<Int> =
v.split('.', '-', '_')
.map { seg -> seg.filter { it.isDigit() } }
.filter { it.isNotEmpty() }
.map { it.toIntOrNull() ?: 0 }
val av = parse(a)
val bv = parse(b)
val max = maxOf(av.size, bv.size)
for (i in 0 until max) {
val ai = av.getOrElse(i) { 0 }
val bi = bv.getOrElse(i) { 0 }
if (ai != bi) return ai.compareTo(bi)
}
return 0
}๋ํ, latest๋ฅผ ํ๋์ฝ๋ฉํ๊ธฐ๋ณด๋ค ์๊ฒฉ ๊ตฌ์ฑ(Remote Config) ๋๋ ๋ฐฑ์๋์์ ์ต์ ๋ฒ์ ์ ๋ด๋ ค๋ฐ๋ ๊ตฌ์กฐ๋ก ๋ฐ๊พธ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๐ค Prompt for AI Agents |
||
|
|
||
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| super.onViewCreated(view, savedInstanceState) | ||
|
|
||
|
|
@@ -171,6 +211,27 @@ class MyFragment : Fragment() { | |
| } | ||
| } | ||
| } | ||
| launch { | ||
| myViewModel.selectedImageResId.collect { resId -> | ||
| resId?.let { | ||
| binding.ivMyIllust.setImageResource(it) | ||
| } | ||
| } | ||
| } | ||
| launch { | ||
| myViewModel.selectedProfileImageUri.collect { uri -> | ||
| uri?.let { | ||
| binding.ivMyIllust.setImageURI(it) | ||
| } | ||
| } | ||
| } | ||
| launch { | ||
| myViewModel.alarmEnabled.collect { enabled -> | ||
| binding.ivMyAlarmIcon.setImageResource( | ||
| if (enabled) R.drawable.img_my_alarm_on else R.drawable.img_my_alarm_off | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -179,4 +240,4 @@ class MyFragment : Fragment() { | |
| super.onDestroyView() | ||
| _binding = null | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐ ๏ธ Refactor suggestion
๋ฒ์ ์ ๋ณด/์นฉ์ด '๋ก๊ทธ์์'์ผ๋ก ์ฐ๊ฒฐ๋๋ ๋ฒ๊ทธ ์์ ํ์
tvMyVersionInfo, chipMyVersion์ logoutClickListener๊ฐ ์ฐ๊ฒฐ๋์ด ์์ด, ์ฌ์ฉ์๊ฐ ๋ฒ์ ๊ด๋ จ UI๋ฅผ ํญํ๋ฉด ๋ก๊ทธ์์ ํ์ ์ด ๋ ๋ฒ๋ฆฝ๋๋ค. clMyGotoUpdate์ ์ด๋ฏธ ์ ๋ฐ์ดํธ ์ด๋ ๋ก์ง์ด ์์ผ๋ฏ๋ก ๋ ์ปดํฌ๋ํธ์ ํด๋ฆญ ๋ฆฌ์ค๋๋ ์ ๊ฑฐํ๋ ๊ฒ์ด ๋ง์ต๋๋ค.
์๋์ฒ๋ผ ์ ๋ฆฌํด ์ฃผ์ธ์:
๐ Committable suggestion
๐ค Prompt for AI Agents