Skip to content
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

[Feature]#72 홈 화면의 복사한 링크 저장하기 기능 구현 #75

Merged
merged 5 commits into from
Oct 1, 2024
26 changes: 26 additions & 0 deletions app/src/main/java/pokitmons/pokit/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package pokitmons.pokit

import android.content.ClipData
import android.content.ClipboardManager
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
Expand All @@ -22,6 +25,7 @@ import androidx.navigation.compose.rememberNavController
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import pokitmons.pokit.core.ui.theme.PokitTheme
import pokitmons.pokit.home.model.ClipboardLinkManager
import pokitmons.pokit.navigation.RootNavHost

@AndroidEntryPoint
Expand Down Expand Up @@ -55,6 +59,28 @@ class MainActivity : ComponentActivity() {
}
}
}

override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)

if (hasFocus) {
val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
clipboardManager.primaryClip?.let { clipData ->
if (clipData.itemCount == 0) return@let
val clipboardTextData = clipData.getItemAt(0).text.toString()

if (!ClipboardLinkManager.checkUrlIsValid(clipboardTextData)) return@let

ClipboardLinkManager.setClipboardLink(clipboardTextData)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clipboardManager.clearPrimaryClip()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 현재 클립된 데이터를 지우는 이유가 있나영?.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

클립보드 복사 -> 홈 화면 진입 -> 링크 추가 화면 진입 및 링크 추가 -> 다시 홈 화면 복귀 -> 홈 버튼 누른 후 앱 재진입
위 케이스에서 이미 저장한 클립 데이터가 남아있어서 다시 toast 메세지가 표시되는 현상이 있었어!

그래서 복사된 링크를 한번 설정하면 해당 링크로는 다시 toast 메세지가 발생하지 않게끔 하려는게 주 목적이었어

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 요건 그러면 파이 이상에서만 발생하는 건가?.?

Copy link
Contributor Author

@l5x5l l5x5l Sep 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어 그러네 파이 미만부분이 아예 처리가 안되어있었구나
수정완!

} else {
val emptyClip = ClipData.newPlainText("", "")
clipboardManager.setPrimaryClip(emptyClip)
}
}
}
}
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ object Home {
object AddLink {
val route: String = "addLink"
val linkIdArg = "link_id"
val routeWithArgs = "$route?$linkIdArg={$linkIdArg}"
val linkUrl = "link_url"
val routeWithArgs = "$route?$linkIdArg={$linkIdArg}&$linkUrl={$linkUrl}"
var arguments = listOf(
navArgument(linkIdArg) {
nullable = true
type = NavType.StringType
},
navArgument(linkUrl) {
nullable = true
type = NavType.StringType
}
)
}
Expand Down
8 changes: 1 addition & 7 deletions app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package pokitmons.pokit.navigation

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -93,10 +91,6 @@ fun RootNavHost(
)
}

composable(Home.route) {
Box(modifier = Modifier.fillMaxSize())
}

composable(
route = AddLink.routeWithArgs,
arguments = AddLink.arguments
Expand Down Expand Up @@ -187,7 +181,7 @@ fun RootNavHost(
"${PokitDetail.route}/$pokitId?${PokitDetail.pokitCountQuery}=$linkCount"
)
},
onNavigateAddLink = { navHostController.navigate(AddLink.route) },
onNavigateAddLink = { navHostController.navigate("${AddLink.route}?${AddLink.linkUrl}=$it") },
onNavigateAddPokit = { navHostController.navigate(AddPokit.route) },
onNavigateToLinkModify = { navHostController.navigate("${AddLink.route}?${AddLink.linkIdArg}=$it") },
onNavigateToPokitModify = { navHostController.navigate("${AddPokit.route}?${AddPokit.pokitIdArg}=$it") },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import pokitmons.pokit.core.ui.R
import pokitmons.pokit.core.ui.theme.PokitTheme
Expand All @@ -41,6 +42,8 @@ fun PokitToast(
Text(
text = text,
style = PokitTheme.typography.body3Medium.copy(color = PokitTheme.colors.inverseWh),
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class AddLinkViewModel @Inject constructor(
val memo: StateFlow<String> = _memo.asStateFlow()

val currentLinkId: Int? = savedStateHandle.get<String>("link_id")?.toIntOrNull()
private val copiedLinkUrl: String? = savedStateHandle.get<String>("link_url")

// 수정 이전 pokit과 수정 이후 pokit이 다른 경우를 체크하기 위해서만 사용
private var prevPokitId: Int? = null
Expand All @@ -97,6 +98,10 @@ class AddLinkViewModel @Inject constructor(
} else {
loadUncategorizedPokit()
}

copiedLinkUrl?.let { url ->
inputLinkUrl(url)
}
}

private fun initPokitAddEventDetector() {
Expand Down
22 changes: 19 additions & 3 deletions feature/home/src/main/java/pokitmons/pokit/home/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fun HomeScreen(
onNavigateToPokitDetail: (String, Int) -> Unit,
onNavigateToSearch: () -> Unit,
onNavigateToSetting: () -> Unit,
onNavigateAddLink: () -> Unit,
onNavigateAddLink: (String?) -> Unit,
onNavigateAddPokit: () -> Unit,
onNavigateToLinkModify: (String) -> Unit,
onNavigateToPokitModify: (String) -> Unit,
Expand All @@ -63,6 +63,7 @@ fun HomeScreen(
var showBottomSheet by remember { mutableStateOf(false) }

val toastMessage by viewModel.toastMessage.collectAsState()
val copiedLinkToastMessage by viewModel.copiedLinkUrl.collectAsState()

viewModel.sideEffect.collectAsEffect { homeSideEffect: HomeSideEffect ->
when (homeSideEffect) {
Expand Down Expand Up @@ -102,7 +103,7 @@ fun HomeScreen(
scope.launch {
sheetState.hide()
showBottomSheet = false
onNavigateAddLink()
onNavigateAddLink(null)
}
},
verticalArrangement = Arrangement.Center,
Expand Down Expand Up @@ -171,7 +172,7 @@ fun HomeScreen(
onNavigateToAlarm = onNavigateToAlarm
)
Scaffold(
bottomBar = { BottomNavigationBar() }
bottomBar = { BottomNavigationBar(viewModel) }
) { padding ->
Box {
when (viewModel.screenType.value) {
Expand Down Expand Up @@ -203,6 +204,21 @@ fun HomeScreen(
onClickClose = viewModel::closeToastMessage
)
}

copiedLinkToastMessage?.linkUrl?.let { linkUrl ->
PokitToast(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(padding)
.padding(start = 12.dp, end = 12.dp, bottom = 48.dp),
text = stringResource(id = pokitmons.pokit.home.R.string.toast_add_copied_link, linkUrl),
onClickClose = viewModel::closeLinkAddToastMessage,
onClick = {
viewModel.closeLinkAddToastMessage()
onNavigateAddLink(linkUrl)
}
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package pokitmons.pokit.home.model

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch

object ClipboardLinkManager {
private val _clipboardLinkUrl: MutableSharedFlow<String> = MutableSharedFlow()
val clipboardLinkUrl: SharedFlow<String> = _clipboardLinkUrl.asSharedFlow()

fun setClipboardLink(linkUrl: String) {
CoroutineScope(Dispatchers.IO).launch {
_clipboardLinkUrl.emit(linkUrl)
}
}

fun checkUrlIsValid(url: String): Boolean {
val isValidUrl = url.startsWith("http://") || url.startsWith("https://")
return isValidUrl
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package pokitmons.pokit.home.model

data class LinkAddToastMessage(val linkUrl: String)
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ import pokitmons.pokit.domain.usecase.link.SetBookmarkUseCase
import pokitmons.pokit.domain.usecase.pokit.DeletePokitUseCase
import pokitmons.pokit.domain.usecase.pokit.GetPokitCountUseCase
import pokitmons.pokit.domain.usecase.pokit.GetPokitsUseCase
import pokitmons.pokit.home.model.ClipboardLinkManager
import pokitmons.pokit.home.model.HomeSideEffect
import pokitmons.pokit.home.model.HomeToastMessage
import pokitmons.pokit.home.model.LinkAddToastMessage
import javax.inject.Inject
import kotlin.math.max
import com.strayalpaca.pokitdetail.model.Link as DetailLink
Expand All @@ -54,6 +56,9 @@ class PokitViewModel @Inject constructor(
private val _toastMessage = MutableStateFlow<HomeToastMessage?>(null)
val toastMessage = _toastMessage.asStateFlow()

private val _copiedLinkUrlToastMessage = MutableStateFlow<LinkAddToastMessage?>(null)
val copiedLinkUrl = _copiedLinkUrlToastMessage.asStateFlow()

private fun initLinkUpdateEventDetector() {
viewModelScope.launch {
LinkUpdateEvent.updatedLink.collectLatest { updatedLink ->
Expand Down Expand Up @@ -94,6 +99,14 @@ class PokitViewModel @Inject constructor(
}
}

private fun initClipboardLinkUrlDetector() {
viewModelScope.launch {
ClipboardLinkManager.clipboardLinkUrl.collectLatest { linkUrl ->
_copiedLinkUrlToastMessage.update { LinkAddToastMessage(linkUrl) }
}
}
}

private fun initPokitUpdateEventDetector() {
viewModelScope.launch {
PokitUpdateEvent.updatedPokit.collectLatest { updatedPokit ->
Expand Down Expand Up @@ -225,6 +238,7 @@ class PokitViewModel @Inject constructor(
initLinkAddEventDetector()
initPokitAddEventDetector()
initLinkRemoveEventDetector()
initClipboardLinkUrlDetector()

loadUnCategoryLinks()
loadPokits()
Expand Down Expand Up @@ -309,6 +323,10 @@ class PokitViewModel @Inject constructor(
_toastMessage.update { null }
}

fun closeLinkAddToastMessage() {
_copiedLinkUrlToastMessage.update { null }
}

fun showLinkOptionBottomSheet(link: DetailLink) {
_linkOptionBottomSheetType.update { BottomSheetType.MODIFY }
_currentSelectedLink.update { link }
Expand Down
1 change: 1 addition & 0 deletions feature/home/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
<string name="app_name">home</string>

<string name="toast_cannot_create_pokit">최대 30개의 포킷을 생성할 수 있습니다.\n포킷을 삭제한 뒤에 추가해주세요.</string>
<string name="toast_add_copied_link">복사한 링크 저장하기\n%s</string>
</resources>
25 changes: 14 additions & 11 deletions feature/login/src/main/java/pokitmons/pokit/login/LoginScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
Expand Down Expand Up @@ -47,18 +48,20 @@ fun LoginScreen(
val coroutineScope = rememberCoroutineScope()

// TODO 리팩토링
when (loginState) {
is LoginState.Init -> Unit
is LoginState.Login -> {
loginViewModel.changeState()
onNavigateToTermsOfServiceScreen()
LaunchedEffect(loginState) {
when (loginState) {
is LoginState.Init -> Unit
is LoginState.Login -> {
loginViewModel.changeState()
onNavigateToTermsOfServiceScreen()
}
is LoginState.Registered -> {
loginViewModel.changeState()
onNavigateToHomeScreen()
}
is LoginState.Failed -> loginViewModel.setVisible(true)
is LoginState.AutoLogin -> onNavigateToHomeScreen()
}
is LoginState.Registered -> {
loginViewModel.changeState()
onNavigateToHomeScreen()
}
is LoginState.Failed -> loginViewModel.setVisible(true)
is LoginState.AutoLogin -> onNavigateToHomeScreen()
}

Box(
Expand Down
Loading