diff --git a/app/src/main/java/com/egobook/app/ui/account/view/AccountBottomSheetFragment.kt b/app/src/main/java/com/egobook/app/ui/account/view/AccountBottomSheetFragment.kt
index 70d4940d..27a0c93a 100644
--- a/app/src/main/java/com/egobook/app/ui/account/view/AccountBottomSheetFragment.kt
+++ b/app/src/main/java/com/egobook/app/ui/account/view/AccountBottomSheetFragment.kt
@@ -13,7 +13,6 @@ import com.egobook.app.databinding.FragmentAccountBottomSheetBinding
import com.egobook.app.ui.account.viewmodel.AccountViewModel
import com.egobook.app.util.UiState
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
-import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
class AccountBottomSheetFragment : BottomSheetDialogFragment() {
@@ -55,23 +54,24 @@ class AccountBottomSheetFragment : BottomSheetDialogFragment() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
- // 연동 상태 및 이메일 관찰
+ // 연동 상태 관찰
launch {
viewModel.linkState.collect { state ->
val isLinked = state is UiState.Success
- if (isLinked) {
- binding.tvAccountEmail.apply {
- visibility = View.VISIBLE
- text = viewModel.userEmail.firstOrNull() ?: ""
- }
- binding.btnBottomGoogleLogin.apply {
- // 이메일이 있으면 표시, 없으면 기본 메시지
- text = "Google계정으로 연동되었습니다"
- isEnabled = false
- }
+ binding.tvAccountEmail.visibility = if (isLinked) View.VISIBLE else View.GONE
+ binding.btnBottomGoogleLogin.apply {
+ text = if (isLinked) "Google계정으로 연동되었습니다" else "Google계정 연동하기"
+ isEnabled = !isLinked
}
}
}
+
+ // 이메일 별도 관찰 - 연동 직후 이메일이 설정되면 UI 갱신
+ launch {
+ viewModel.userEmail.collect { email ->
+ binding.tvAccountEmail.text = email ?: ""
+ }
+ }
}
}
}
diff --git a/app/src/main/java/com/egobook/app/ui/account/view/AccountFragment.kt b/app/src/main/java/com/egobook/app/ui/account/view/AccountFragment.kt
index e7613770..6cfc1d5a 100644
--- a/app/src/main/java/com/egobook/app/ui/account/view/AccountFragment.kt
+++ b/app/src/main/java/com/egobook/app/ui/account/view/AccountFragment.kt
@@ -1,5 +1,7 @@
package com.egobook.app.ui.account.view
+import android.content.Intent
+import androidx.core.net.toUri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -27,13 +29,20 @@ import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import timber.log.Timber
-import android.util.Base64
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.egobook.app.BlurLevel
import com.egobook.app.applyScreenBlur
-import kotlinx.coroutines.flow.MutableSharedFlow
-import org.json.JSONObject
+import android.text.SpannableString
+import android.text.Spanned
+import android.text.TextPaint
+import android.text.method.LinkMovementMethod
+import android.text.style.ClickableSpan
+import android.graphics.Color
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+
@AndroidEntryPoint
class AccountFragment : Fragment() {
@@ -178,6 +187,15 @@ class AccountFragment : Fragment() {
accountDeleteDialog1Fragment.isCancelable = false
accountDeleteDialog1Fragment.show(childFragmentManager, "AccountDeleteDialog1Fragment")
}
+
+ // ✅ 고객지원 클릭
+ tvSupport.setOnClickListener {
+ copySupportEmailToClipboard()
+ }
+
+ setupPromiseText()
+
+
}
}
@@ -219,6 +237,63 @@ class AccountFragment : Fragment() {
_binding = null
}
+ private fun copySupportEmailToClipboard() {
+ val email = "egobook.official@gmail.com" // ← 여기 너네 고객지원 이메일로 바꿔
+
+ val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ val clip = ClipData.newPlainText("Support Email", email)
+ clipboard.setPrimaryClip(clip)
+
+ Toast.makeText(requireContext(), "고객지원 이메일이 복사되었습니다.", Toast.LENGTH_SHORT).show()
+ }
+
+ private fun setupPromiseText() {
+ val fullText = "이용약관 및 개인정보처리"
+ val spannable = SpannableString(fullText)
+
+ // ===== 이용약관 =====
+ val termsText = "이용약관"
+ val termsStart = fullText.indexOf(termsText)
+ val termsEnd = termsStart + termsText.length
+
+ spannable.setSpan(object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ val intent = Intent(
+ Intent.ACTION_VIEW,
+ "https://bevel-beetle-a49.notion.site/2f638a539ac5801aa872e99ec4282f28".toUri() // ← 약관 URL
+ )
+ startActivity(intent)
+ }
+
+ override fun updateDrawState(ds: TextPaint) {
+ ds.isUnderlineText = false
+ }
+ }, termsStart, termsEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+
+ // ===== 개인정보처리 =====
+ val privacyText = "개인정보처리"
+ val privacyStart = fullText.indexOf(privacyText)
+ val privacyEnd = privacyStart + privacyText.length
+
+ spannable.setSpan(object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ val intent = Intent(
+ Intent.ACTION_VIEW,
+ "https://bevel-beetle-a49.notion.site/2f638a539ac58059b9a1c883ad7d7164".toUri() // ← 개인정보 URL
+ )
+ startActivity(intent)
+ }
+
+ override fun updateDrawState(ds: TextPaint) {
+ ds.isUnderlineText = false
+ }
+ }, privacyStart, privacyEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+
+ binding.tvPromise.text = spannable
+ binding.tvPromise.movementMethod = LinkMovementMethod.getInstance()
+ binding.tvPromise.highlightColor = Color.TRANSPARENT
+ }
+
//=============다이알로그 출력용 블러뷰 세팅====================
private fun setupBlur() {
diff --git a/app/src/main/java/com/egobook/app/ui/login/view/LoginActivity.kt b/app/src/main/java/com/egobook/app/ui/login/view/LoginActivity.kt
index e36fae06..a79200c0 100644
--- a/app/src/main/java/com/egobook/app/ui/login/view/LoginActivity.kt
+++ b/app/src/main/java/com/egobook/app/ui/login/view/LoginActivity.kt
@@ -36,6 +36,10 @@ import com.google.android.libraries.identity.googleid.GetGoogleIdOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import com.egobook.app.ui.onboarding.view.OnboardingActivity
import timber.log.Timber
+import androidx.core.net.toUri
+import android.text.method.LinkMovementMethod
+import android.text.style.ClickableSpan
+import android.graphics.Color
@AndroidEntryPoint
class LoginActivity : AppCompatActivity() {
@@ -131,6 +135,12 @@ class LoginActivity : AppCompatActivity() {
}
}
+
+ //약관
+ binding.tvStartGuide.setOnClickListener {
+ val intent = Intent(Intent.ACTION_VIEW, "https://bevel-beetle-a49.notion.site/2f638a539ac58059b9a1c883ad7d7164".toUri())
+ startActivity(intent)
+ }
}
private fun getGoogleRequest(): GetCredentialRequest {
@@ -241,33 +251,71 @@ class LoginActivity : AppCompatActivity() {
//========================================특정 char 폰트 커스텀===========================================================
- private fun setupGuideText() {
- val fullText = "시작 시 이용약관 및\n개인정보 수집 및 이용에 동의하게 됩니다"
- val spannableString = SpannableString(fullText)
-
- // 폰트 리소스를 Typeface 객체로 불러옴.
- val semiBoldTypeface = ResourcesCompat.getFont(this, R.font.arita_semibold) ?: return
-
- // 폰트를 적용할 텍스트 ("이용약관")
- val target1 = "이용약관"
- val start1 = fullText.indexOf(target1)
- if (start1 >= 0) {
- val end1 = start1 + target1.length
- spannableString.setSpan(CustomTypefaceSpan(semiBoldTypeface), start1, end1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
- }
+private fun setupGuideText() {
+ val fullText = "시작 시 이용약관 및\n개인정보 수집 및 이용에 동의하게 됩니다"
+ val spannableString = SpannableString(fullText)
+
+ val semiBoldTypeface = ResourcesCompat.getFont(this, R.font.arita_semibold) ?: return
+
+ // ================= 이용약관 =================
+ val termText = "이용약관"
+ val termStart = fullText.indexOf(termText)
+ if (termStart >= 0) {
+ val termEnd = termStart + termText.length
+
+ spannableString.setSpan(
+ CustomTypefaceSpan(semiBoldTypeface),
+ termStart, termEnd,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+
+ spannableString.setSpan(object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ val intent = Intent(
+ Intent.ACTION_VIEW,
+ "https://bevel-beetle-a49.notion.site/2f638a539ac5801aa872e99ec4282f28".toUri() // ← 약관 URL
+ )
+ startActivity(intent)
+ }
- // 폰트를 적용할 텍스트 ("개인정보 수집 및 이용")
- val target2 = "개인정보 수집 및 이용"
- val start2 = fullText.indexOf(target2)
- if (start2 >= 0) {
- val end2 = start2 + target2.length
- spannableString.setSpan(CustomTypefaceSpan(semiBoldTypeface), start2, end2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
- }
+ override fun updateDrawState(ds: TextPaint) {
+ ds.isUnderlineText = false
+ }
+ }, termStart, termEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ }
+
+ // ================= 개인정보 =================
+ val privacyText = "개인정보 수집 및 이용"
+ val privacyStart = fullText.indexOf(privacyText)
+ if (privacyStart >= 0) {
+ val privacyEnd = privacyStart + privacyText.length
+
+ spannableString.setSpan(
+ CustomTypefaceSpan(semiBoldTypeface),
+ privacyStart, privacyEnd,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+
+ spannableString.setSpan(object : ClickableSpan() {
+ override fun onClick(widget: View) {
+ val intent = Intent(
+ Intent.ACTION_VIEW,
+ "https://bevel-beetle-a49.notion.site/2f638a539ac58059b9a1c883ad7d7164".toUri() // ← 개인정보 URL
+ )
+ startActivity(intent)
+ }
- // 완성된 SpannableString을 TextView에 적용
- binding.tvStartGuide.text = spannableString
+ override fun updateDrawState(ds: TextPaint) {
+ ds.isUnderlineText = false
+ }
+ }, privacyStart, privacyEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
+ binding.tvStartGuide.text = spannableString
+ binding.tvStartGuide.movementMethod = LinkMovementMethod.getInstance()
+ binding.tvStartGuide.highlightColor = Color.TRANSPARENT
+}
+
//모든 API 레벨에서 커스텀 폰트를 적용하기 위한 Span 클래스
private class CustomTypefaceSpan(private val typeface: Typeface) : MetricAffectingSpan() {
override fun updateDrawState(ds: TextPaint) {
diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml
index ce48ed7e..131bef7f 100644
--- a/app/src/main/res/layout/fragment_account.xml
+++ b/app/src/main/res/layout/fragment_account.xml
@@ -408,6 +408,7 @@
app:layout_constraintEnd_toEndOf="@id/gd_end">