Skip to content

Commit

Permalink
[Feature]#72 홈 화면의 복사한 링크 저장하기 기능 구현 (#75)
Browse files Browse the repository at this point in the history
* [FEATURE] 링크 복사 후 홈 화면 진입시 복사한 링크 추가 화면으로 이동하는 toast 표시 기능 구현 및 PokitToast의 최대 line수를 2로 설정

* [FIX] 로그인 화면에서 자동로그인 이벤트 발생시 화면 이동 이벤트가 2번 수행되는 문제 수정

* [FEATURE] 홈 화면에서 복사된 링크 추가 토스트를 통해 링크 추가화면 진입시, 해당 링크 url로 설정하는 기능 구현

* [CHORE] ktlint 적용

* [FIX] 코드리뷰 내용 반영
- url링크 유효성 검증시 조건 단순화
- SDK 27 이하일 때 클립보드 초기화 누락 수정
  • Loading branch information
l5x5l authored Oct 1, 2024
1 parent a05a8ba commit 63630e9
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 22 deletions.
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()
} 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

0 comments on commit 63630e9

Please sign in to comment.