Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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 ?: ""
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -178,6 +187,15 @@ class AccountFragment : Fragment() {
accountDeleteDialog1Fragment.isCancelable = false
accountDeleteDialog1Fragment.show(childFragmentManager, "AccountDeleteDialog1Fragment")
}

// ✅ 고객지원 클릭
tvSupport.setOnClickListener {
copySupportEmailToClipboard()
}

setupPromiseText()


}

}
Expand Down Expand Up @@ -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() {
Expand Down
94 changes: 71 additions & 23 deletions app/src/main/java/com/egobook/app/ui/login/view/LoginActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/layout/fragment_account.xml
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@
app:layout_constraintEnd_toEndOf="@id/gd_end">

<TextView
android:id="@+id/tv_support"
android:layout_width="match_parent"
android:layout_height="48dp"
android:padding="10dp"
Expand All @@ -429,6 +430,7 @@
android:fontFamily="@font/arita_semibold"/>

<TextView
android:id="@+id/tv_promise"
android:layout_width="match_parent"
android:layout_height="48dp"
android:padding="10dp"
Expand Down