diff --git a/design/src/main/java/com/example/design/modifier/InnerRingShadow.kt b/design/src/main/java/com/example/design/modifier/InnerRingShadow.kt new file mode 100644 index 00000000..1e2e6353 --- /dev/null +++ b/design/src/main/java/com/example/design/modifier/InnerRingShadow.kt @@ -0,0 +1,119 @@ +package com.example.design.modifier + +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.geometry.center +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +/** + * 컴포넌트의 안쪽 테두리를 따라 부드러운 원형 그림자(Inner Ring Shadow) 효과를 적용합니다. + * + * 이 함수는 [Brush.radialGradient]를 사용하여 컴포넌트의 중심부터 가장자리까지 그레이디언트를 생성하며, + * 지정된 두께([edgeThickness]) 영역에만 [shadowColor]를 노출시켜 입체감을 부여합니다. + * + * @param shadowColor 가장자리 끝부분에 적용될 그림자의 색상 및 투명도입니다. 기본값은 10% 불투명도의 검정색입니다. + * @param edgeThickness 그림자가 그려질 가장자리의 두께입니다. 기본값은 2.dp입니다. + * @return 안쪽 그림자 효과가 적용된 [Modifier] 객체를 반환합니다. + * + * @see androidx.compose.ui.draw.drawWithCache + * @see androidx.compose.ui.graphics.Brush.Companion.radialGradient + * + * @sample + * Box( + * modifier = Modifier + * .size(100.dp) + * .clip(CircleShape) + * .innerRingShadow(shadowColor = Color.Black.copy(alpha = 0.2f), edgeThickness = 4.dp) + * ) + */ +fun Modifier.innerRingShadow( + shadowColor: Color = Color.Black.copy(alpha = 0.10f), + edgeThickness: Dp = 2.dp +): Modifier = this.drawWithCache { + + // ───────────────────────────────────────────────────────────── + // 1) 원형 반지름 계산 + // ───────────────────────────────────────────────────────────── + // size: 이 Modifier가 적용되는 컴포넌트의 실제 픽셀 크기 (Size(widthPx, heightPx)) + // minDimension: width/height 중 더 짧은 변 (원형 그림자 만들 때 "지름"으로 삼기 좋음) + // + // r: radialGradient의 반지름(px) + // - minDimension / 2: "짧은 변" 기준으로 원의 반지름을 잡음 + // - coerceAtLeast(1f): 너무 작은 값(0에 가까운 값)으로 인해 0으로 나눔/이상 계산을 피함 + val r = (size.minDimension / 2f).coerceAtLeast(1f) + + // ───────────────────────────────────────────────────────────── + // 2) 테두리 쪽에만 그림자를 남기기 위한 "내부 링 두께"를 px로 변환 + // ───────────────────────────────────────────────────────────── + // edgeThickness(Dp): 사용자 입력 두께(논리 단위) → toPx()로 "픽셀" 변환 + // + // t: 테두리 내부 그림자가 차지할 두께(px) + // - coerceIn(0f, r): 두께가 음수가 되거나 반지름보다 커지면 계산이 깨질 수 있어서 범위 제한 + // * 0f: 그림자 없음 + // * r: 반지름 전체(즉, 거의 전체가 그림자)까지 허용 + val t = edgeThickness.toPx().coerceIn(0f, r) + + // ───────────────────────────────────────────────────────────── + // 3) Gradient에서 "투명 → 그림자"로 바뀌는 경계 비율 계산 + // ───────────────────────────────────────────────────────────── + // radialGradient의 colorStops는 (0.0 ~ 1.0) 범위의 비율로 정의됨. + // + // (r - t) / r 의 의미: + // - r: 전체 반지름 + // - r - t: "그림자가 시작되기 전"까지의 반지름(= 내부는 투명하게 두고 싶은 영역) + // + // 예) r=50px, t=5px 라면 + // - (r - t) / r = 45/50 = 0.9 + // - 즉, 중심~0.9 구간은 투명, 0.9~1.0 구간에서만 그림자로 변화 + // + // coerceIn(0f, 1f): 비율이 범위를 벗어나면 gradient가 비정상 동작할 수 있어 제한 + val stop = ((r - t) / r).coerceIn(0f, 1f) + + // ───────────────────────────────────────────────────────────── + // 4) 중심은 투명, 가장자리로 갈수록 shadowColor가 되는 Radial Gradient 생성 + // ───────────────────────────────────────────────────────────── + // Brush.radialGradient: + // - center: 그라디언트 중심점 (여기서는 컴포넌트 중앙) + // - radius: 반지름(px) + // + // colorStops: + // - 0.0f : 중심점(반지름 0) 위치 + // - stop : "여기까지는 투명" 위치 (내부 영역) + // - 1.0f : 반지름 끝(가장자리) 위치 + // + // 0.0f to Transparent + stop to Transparent: + // - 내부 영역(0~stop)을 완전히 투명하게 고정해 "테두리만" 그림자가 남게 함 + // + // 1.0f to shadowColor: + // - 가장자리에서만 shadowColor가 적용되도록 하여, + // 두 번째 사진처럼 "희미한 내부 테두리 그림자" 느낌을 만들 수 있음 + val brush = Brush.radialGradient( + colorStops = arrayOf( + 0.0f to Color.Transparent, // 중심은 완전 투명 + stop to Color.Transparent, // stop 지점까지도 완전 투명(= 내부 깨끗) + 1.0f to shadowColor // 가장자리에만 그림자 색이 나타남 + ), + center = size.center, // 컴포넌트 중앙 기준으로 퍼짐 + radius = r // 위에서 계산한 반지름(px) + ) + + // ───────────────────────────────────────────────────────────── + // 5) 실제 그리기: 기존 컨텐츠를 그리고, 그 위에 그라디언트를 덮어씌움 + // ───────────────────────────────────────────────────────────── + onDrawWithContent { + + // (1) 원래 컴포넌트 내용(배경, 텍스트 등) 먼저 그림 + drawContent() + + // (2) 위에서 만든 brush를 사각형 전체에 칠함 + // - 원형으로만 보이게 하려면 반드시 바깥에서 clip(CircleShape) 같은 클립이 필요함! + // - clip이 없다면 "사각형 영역" 전체에 radialGradient가 적용됨. + // + // clip(CircleShape)가 이미 적용된 상태라면: + // - drawRect로 칠해도 원 밖은 잘려서 결국 "원 테두리 내부"에만 그림자가 남음 + drawRect(brush = brush) + } +} \ No newline at end of file diff --git a/design/src/main/java/com/example/design/top/search/SearchBarTopSheet.kt b/design/src/main/java/com/example/design/top/search/SearchBarTopSheet.kt index 0e06fad9..da8cb6e7 100644 --- a/design/src/main/java/com/example/design/top/search/SearchBarTopSheet.kt +++ b/design/src/main/java/com/example/design/top/search/SearchBarTopSheet.kt @@ -146,7 +146,7 @@ fun SearchBarTopSheet( * - 350ms 디바운스 * - 동일 값 중복 호출 방지 */ - LaunchedEffect(text) { + LaunchedEffect(Unit) { snapshotFlow { text } .map { it.trim() } .filter { it.length >= 2 } diff --git a/feature/curation/src/main/java/com/example/curation/ui/CurationScreen.kt b/feature/curation/src/main/java/com/example/curation/ui/CurationScreen.kt index 1626fb18..72db2f38 100644 --- a/feature/curation/src/main/java/com/example/curation/ui/CurationScreen.kt +++ b/feature/curation/src/main/java/com/example/curation/ui/CurationScreen.kt @@ -4,17 +4,14 @@ package com.example.curation.ui import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -27,9 +24,7 @@ import com.example.curation.R import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.width import androidx.compose.material3.Scaffold @@ -37,7 +32,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp @@ -46,8 +40,6 @@ import com.example.curation.CurationViewModel import com.example.curation.ui.list_card.LikedCurationCard import com.example.curation.Paperlogy import com.example.design.theme.LocalColorTheme -import com.example.design.theme.color.Basic -import com.example.design.R as Res import java.time.LocalDate import java.time.format.DateTimeFormatter import java.util.Locale diff --git a/feature/file/build.gradle.kts b/feature/file/build.gradle.kts index 7355fce8..7be8d8f5 100644 --- a/feature/file/build.gradle.kts +++ b/feature/file/build.gradle.kts @@ -53,7 +53,7 @@ dependencies { implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) implementation(libs.androidx.navigation.compose) - implementation(libs.androidx.compose.foundation.layout) + implementation(libs.androidx.compose.foundation) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/feature/file/src/main/java/com/example/file/FileViewModel.kt b/feature/file/src/main/java/com/example/file/FileViewModel.kt index dd2c75fb..ec807fc4 100644 --- a/feature/file/src/main/java/com/example/file/FileViewModel.kt +++ b/feature/file/src/main/java/com/example/file/FileViewModel.kt @@ -511,6 +511,8 @@ class FileViewModel @Inject constructor( onGetLinks = { list -> _notCategorizationLinks.value = list.map { it.copy() } } ) + Log.d("FileViewModel", "getNotCategorizationLinks try result: ${_subFolders.value}") + Log.d("FileViewModel", "getNotCategorizationLinks try result: ${_notCategorizationLinks.value}") } catch (e: Exception) { @@ -1055,24 +1057,25 @@ class FileViewModel @Inject constructor( } Log.d("FileViewModel", "receiveSharedFolder return") } - - // 공개/비공개 전환 - fun changeSharing(folder: FolderSimpleInfo){ - Log.d("FileViewModel", "changeSharing") + // 공개 전환 + fun folderToShare(folder: FolderSimpleInfo){ + Log.d("FileViewModel", "folderToShare") viewModelScope.launch { - Log.d("FileViewModel", "changeSharing launch") + Log.d("FileViewModel", "folderToShare launch") startLoading() _errorMessage.value = null - try{ - Log.d("FileViewModel", "changeSharing try") + try { + Log.d("FileViewModel", "folderToShare try") - val isSharing = folder.isSharing == "share" + val isPrivate = folder.isSharing == "private" + + if (isPrivate) { + Log.d("FileViewModel", "folderToShare isPrivate true") - if(!isSharing){ - folderRepository.setFolderViewerPermission(folder.folderId) + //folderRepository.setFolderPublicPermission(folder.folderId) _subFolders.update { list -> list.map { @@ -1083,8 +1086,39 @@ class FileViewModel @Inject constructor( } } } + } + Log.d("FileViewModel", "folderToShare try result") + } catch (e: Exception) { + Log.d("FileViewModel", "folderToShare catch: $e.message") + + _errorMessage.value = e.message + } finally { + Log.d("FileViewModel", "folderToShare finally") + + stopLoading() + } + } + Log.d("FileViewModel", "folderToShare return") + + } + // 비공개 전환 + fun folderToPrivate(folder: FolderSimpleInfo){ + Log.d("FileViewModel", "folderToPrivate") + + viewModelScope.launch { + Log.d("FileViewModel", "folderToPrivate launch") + + startLoading() + _errorMessage.value = null + + try{ + Log.d("FileViewModel", "folderToPrivate try") + + val isSharing = folder.isSharing == "share" + + if(isSharing){ + Log.d("FileViewModel", "folderToPrivate isSharing true") - }else{ folderRepository.setFolderPrivatePermission(folder.folderId) _subFolders.update { list -> @@ -1098,18 +1132,18 @@ class FileViewModel @Inject constructor( } } - Log.d("FileViewModel", "changeSharing try result") + Log.d("FileViewModel", "folderToPrivate try result") }catch (e: Exception){ - Log.d("FileViewModel", "changeSharing catch: $e.message") + Log.d("FileViewModel", "folderToPrivate catch: $e.message") _errorMessage.value = e.message }finally { - Log.d("FileViewModel", "changeSharing finally") + Log.d("FileViewModel", "folderToPrivate finally") stopLoading() } } - Log.d("FileViewModel", "changeSharing return") + Log.d("FileViewModel", "folderToPrivate return") } // ---------- share method ---------- diff --git a/feature/file/src/main/java/com/example/file/ui/bottom/sheet/FileBottomSheet.kt b/feature/file/src/main/java/com/example/file/ui/bottom/sheet/FileBottomSheet.kt index 97b93cee..1cc305bc 100644 --- a/feature/file/src/main/java/com/example/file/ui/bottom/sheet/FileBottomSheet.kt +++ b/feature/file/src/main/java/com/example/file/ui/bottom/sheet/FileBottomSheet.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -38,9 +37,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.file.R import com.example.design.modifier.noRippleClickable import com.example.design.theme.color.Basic +import com.example.file.R import com.example.file.ui.theme.Black import com.example.file.ui.theme.DefaultFont import com.example.file.ui.theme.Gray300 @@ -73,6 +72,9 @@ fun FileBottomSheet( color = Basic.gray[300] ) }, + + // 딤 효과 수치 + scrimColor = Basic.black.copy(alpha = 0.5f), sheetState = sheetState, onDismissRequest = onDismiss, tonalElevation = 8.dp, @@ -85,26 +87,29 @@ fun FileBottomSheet( .padding(bottom = 20.dp) .padding(horizontal = 20.dp), ) { + Text( modifier = Modifier .padding(start = 10.dp), text = title, fontSize = 18.sp, - lineHeight = 22.sp, fontFamily = DefaultFont, fontWeight = FontWeight(500), color = Black, ) + + Spacer(modifier = Modifier.height(11.dp)) + Text( modifier = Modifier - .padding(start = 10.dp, top = 14.dp), + .padding(start = 10.dp), text = body, fontSize = 15.sp, - lineHeight = 22.sp, fontFamily = DefaultFont, fontWeight = FontWeight.Normal, color = Gray600, ) + Spacer(modifier = Modifier.height(24.dp)) content() diff --git a/feature/file/src/main/java/com/example/file/ui/bottom/sheet/LinkCategorizationBottomSheet.kt b/feature/file/src/main/java/com/example/file/ui/bottom/sheet/LinkCategorizationBottomSheet.kt index ffe51487..5d044054 100644 --- a/feature/file/src/main/java/com/example/file/ui/bottom/sheet/LinkCategorizationBottomSheet.kt +++ b/feature/file/src/main/java/com/example/file/ui/bottom/sheet/LinkCategorizationBottomSheet.kt @@ -12,7 +12,7 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -25,6 +25,7 @@ import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -45,6 +46,7 @@ import com.example.core.model.LinkItemInfo import com.example.file.FileViewModel import com.example.file.R import com.example.design.modifier.noRippleClickable +import com.example.design.theme.color.Basic import com.example.file.ui.theme.Black import com.example.file.ui.theme.DefaultFont import com.example.file.ui.theme.Gray100 @@ -62,9 +64,9 @@ fun LinkCategorizationBottomSheet( ) { val links by fileViewModel.notCategorizationLinks.collectAsStateWithLifecycle() - var link by remember { mutableStateOf(null) } + //var link by remember { mutableStateOf(null) } - var selectedLinks = mutableListOf() + val selectedLinks = remember { mutableStateListOf() } val scope = rememberCoroutineScope() @@ -75,15 +77,17 @@ fun LinkCategorizationBottomSheet( title = "${folderStateViewModel.selectedTopFolder?.folderName?:""} 폴더의 미분류 링크 목록", body = "하위폴더에 추가하실 링크를 선택해주세요!", buttonText = "추가", + isReady = selectedLinks.isNotEmpty(), visible = folderStateViewModel.linkCategorizationBottomSheetVisible, onOkay = { scope.launch{ - selectedLinks.map { - fileViewModel.updateLinkFolder( - it, - folderStateViewModel.selectedBottomFolder?.folderId!! - ) + val folderId = requireNotNull(folderStateViewModel.selectedBottomFolder?.folderId) + + selectedLinks.forEach { + fileViewModel.updateLinkFolder(it, folderId) } + + selectedLinks.clear() } }, onDismiss = { folderStateViewModel.updateLinkCategorizationBottomSheetVisible(false) } @@ -95,7 +99,7 @@ fun LinkCategorizationBottomSheet( verticalArrangement = Arrangement.spacedBy(10.dp) ) { items(links) { - val l = it + val link = it val title = it.title val url = it.url val icon = domainLogoPainterOrNull(it.url)?:painterResource(R.drawable.link_categorization_default) @@ -104,64 +108,71 @@ fun LinkCategorizationBottomSheet( var checked by remember { mutableStateOf(false)} Row( modifier = Modifier - //.height(60.dp) + .height(60.dp) + .offset(x = (-20).dp) .noRippleClickable{ if(checked){ Log.d("LinkCategorizationBottomSheet", "checked: $it") - selectedLinks.remove(l) - checked = selectedLinks.contains(l) + selectedLinks.remove(link) + checked = selectedLinks.contains(link) } else { Log.d("LinkCategorizationBottomSheet", "checked: $it") - selectedLinks.add(l) - checked = selectedLinks.contains(l) + selectedLinks.add(link) + checked = selectedLinks.contains(link) } }, - horizontalArrangement = Arrangement.spacedBy(14.dp) + horizontalArrangement = Arrangement.spacedBy(10.dp), + verticalAlignment = Alignment.CenterVertically ) { Checkbox( - modifier = Modifier - .clip(RoundedCornerShape(18.dp)), checked = checked, onCheckedChange = { if(checked){ Log.d("LinkCategorizationBottomSheet", "checked: $it") - selectedLinks.remove(l) - checked = selectedLinks.contains(l) + selectedLinks.remove(link) + checked = selectedLinks.contains(link) } else { Log.d("LinkCategorizationBottomSheet", "checked: $it") - selectedLinks.add(l) - checked = selectedLinks.contains(l) + selectedLinks.add(link) + checked = selectedLinks.contains(link) } }, colors = CheckboxDefaults.colors( checkedColor = Purple200, + uncheckedColor = Basic.gray[200], ) ) Box( modifier = Modifier - .height(60.dp) - .background(Gray100), + //.height(60.dp) + .background( + color = Gray100, + shape = RoundedCornerShape(18.dp) + ) + /*.clip(RoundedCornerShape(18.dp))*/, contentAlignment = Alignment.Center ) { Image( modifier = Modifier - .fillMaxHeight() - .clip(RoundedCornerShape(18.dp)), + .fillMaxHeight(), painter = img, contentDescription = null ) } + Column( - modifier = Modifier - .fillMaxHeight() - .padding(vertical = 8.dp), + modifier = Modifier.fillMaxHeight(), + //verticalArrangement = Arrangement.SpaceBetween + ) { + // 링크 상단 패딩 + Spacer(modifier = Modifier.height(7.dp)) + Text( text = title, fontSize = 15.sp, - lineHeight = 22.sp, fontFamily = DefaultFont, fontWeight = FontWeight(500), color = Black, @@ -194,7 +205,6 @@ fun LinkCategorizationBottomSheet( Text( text = url, fontSize = 12.sp, - lineHeight = 14.sp, fontFamily = DefaultFont, fontWeight = FontWeight(400), color = Gray800, @@ -202,7 +212,10 @@ fun LinkCategorizationBottomSheet( overflow = TextOverflow.Ellipsis ) } + // 링크 하단 패딩 + Spacer(modifier = Modifier.height(7.dp)) } + } } } diff --git a/feature/file/src/main/java/com/example/file/ui/bottom/sheet/TextFieldFileBottomSheet.kt b/feature/file/src/main/java/com/example/file/ui/bottom/sheet/TextFieldFileBottomSheet.kt index 81c74d28..ff546f45 100644 --- a/feature/file/src/main/java/com/example/file/ui/bottom/sheet/TextFieldFileBottomSheet.kt +++ b/feature/file/src/main/java/com/example/file/ui/bottom/sheet/TextFieldFileBottomSheet.kt @@ -185,7 +185,10 @@ fun TextFieldFileBottomSheet( ) } - val rotation by animateFloatAsState(if (expanded) 180f else 0f, label = "") + val rotation by animateFloatAsState( + targetValue = if (expanded) 180f else 0f, + label = "화살표 회전 애니메이션" + ) val modifier = if(expanded) Modifier .padding(start = 10.dp) diff --git a/feature/file/src/main/java/com/example/file/ui/content/BottomFolderGrid.kt b/feature/file/src/main/java/com/example/file/ui/content/BottomFolderGrid.kt index 6481aa89..c17820e6 100644 --- a/feature/file/src/main/java/com/example/file/ui/content/BottomFolderGrid.kt +++ b/feature/file/src/main/java/com/example/file/ui/content/BottomFolderGrid.kt @@ -144,7 +144,7 @@ fun BottomFolderGrid( folderStateViewModel.updateBottomFolderEditBottomSheetVisible(true) }, onChangeSharing = { - fileViewModel.changeSharing(folder) + fileViewModel.folderToPrivate(folder) } ) } diff --git a/feature/file/src/main/java/com/example/file/ui/content/FolderIcons.kt b/feature/file/src/main/java/com/example/file/ui/content/FolderIcons.kt index 5cd753a6..65b6cd0b 100644 --- a/feature/file/src/main/java/com/example/file/ui/content/FolderIcons.kt +++ b/feature/file/src/main/java/com/example/file/ui/content/FolderIcons.kt @@ -19,7 +19,7 @@ import com.example.file.ui.theme.White // 공유 폴더 사람 아이콘 @Composable -fun ShareFolderIcon( +internal fun ShareFolderIcon( tint: Color ) { Icon( @@ -31,7 +31,7 @@ fun ShareFolderIcon( // 잠금 폴더 자물쇠 아이콘 @Composable -fun LockFolderIcon( +internal fun LockFolderIcon( tint: Color ) { Icon( @@ -43,7 +43,7 @@ fun LockFolderIcon( // 수정 연필 아이콘 @Composable -fun PencilIcon( +internal fun PencilIcon( tint: Color ) { Icon( @@ -55,7 +55,7 @@ fun PencilIcon( // 북마크 별 아이콘 @Composable -fun BookMarkStar( +internal fun BookMarkStar( isBookmarked: Boolean ) { val modifier = if(isBookmarked) Modifier diff --git a/feature/file/src/main/java/com/example/file/ui/content/LinksGrid.kt b/feature/file/src/main/java/com/example/file/ui/content/LinksGrid.kt index 179d2436..91591ab1 100644 --- a/feature/file/src/main/java/com/example/file/ui/content/LinksGrid.kt +++ b/feature/file/src/main/java/com/example/file/ui/content/LinksGrid.kt @@ -1,6 +1,5 @@ package com.example.file.ui.content -import androidx.lifecycle.lifecycleScope import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement @@ -12,7 +11,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -28,16 +26,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.cheonjaeung.compose.grid.SimpleGridCells import com.cheonjaeung.compose.grid.VerticalGrid +import com.example.design.modifier.noRippleClickable import com.example.file.FileViewModel import com.example.file.R -import com.example.design.modifier.noRippleClickable import com.example.file.ui.item.LinkItemLayout import com.example.file.ui.modal.FileModalWindow -import com.example.file.viewmodel.folder.state.FolderStateViewModel import com.example.file.ui.theme.Black import com.example.file.ui.theme.DefaultFont import com.example.file.ui.theme.Gray600 -import kotlinx.coroutines.launch +import com.example.file.viewmodel.folder.state.FolderStateViewModel @Composable fun LinksGrid( @@ -164,8 +161,8 @@ fun LinksGrid( }, onDismiss = { deleteModalWindowVisible = false }, title = "해당 링크를 삭제하시겠습니까?", - positiveText = "삭제", - negativeText = "취소" + positiveText = "삭제하기", + negativeText = "취소하기" ) { Text( text = "삭제 시 해당 링크가 영구적으로 제거되며\n복구가 불가능합니다.", diff --git a/feature/file/src/main/java/com/example/file/ui/item/FolderItemLayout.kt b/feature/file/src/main/java/com/example/file/ui/item/FolderItemLayout.kt index f7c2ca26..60d45d76 100644 --- a/feature/file/src/main/java/com/example/file/ui/item/FolderItemLayout.kt +++ b/feature/file/src/main/java/com/example/file/ui/item/FolderItemLayout.kt @@ -4,7 +4,6 @@ package com.example.file.ui.item import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints @@ -17,11 +16,9 @@ import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface @@ -49,21 +46,22 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import com.example.core.model.FolderSimpleInfo -import com.example.file.R import com.example.design.modifier.noRippleClickable +import com.example.design.modifier.innerRingShadow +import com.example.design.theme.color.CategoryColorStyle +import com.example.file.R import com.example.file.ui.content.BookMarkStar import com.example.file.ui.content.LockFolderIcon import com.example.file.ui.content.PencilIcon import com.example.file.ui.content.ShareFolderIcon -import com.example.file.viewmodel.edit.state.EditStateViewModel import com.example.file.ui.theme.Black -import com.example.design.theme.color.CategoryColorStyle import com.example.file.ui.theme.DefaultFont import com.example.file.ui.theme.Gray100 import com.example.file.ui.theme.Gray200 import com.example.file.ui.theme.Gray300 import com.example.file.ui.theme.Gray500 import com.example.file.ui.theme.White +import com.example.file.viewmodel.edit.state.EditStateViewModel @Composable fun FolderItemLayout( @@ -94,6 +92,10 @@ fun FolderItemLayout( shadowElevation = 3.8.dp ) { BoxWithConstraints(Modifier.fillMaxSize()) { + + // 에러 경고 제거용 변수 + val tmp = this + // 현재 실제 너비/높이에 맞춰 스케일 계산 val scaleW = maxWidth / baseW val scaleH = maxHeight / baseH @@ -218,8 +220,12 @@ fun FolderItemLayout( Box( modifier = Modifier .size(s(29.1745.dp)) - .clip(CircleShape) - .background(color = textBackgroundColor), + .clip(shape = CircleShape) + .background(color = textBackgroundColor) + .innerRingShadow( + shadowColor = Color.Black.copy(alpha = 0.10f), + edgeThickness = 8.dp + ), contentAlignment = Alignment.Center ) { Text( @@ -250,354 +256,6 @@ fun FolderItemLayout( } } -//@Composable -//fun FolderItemLayout( -// modifier: Modifier = Modifier, -// backgroundColor: Color, -// color1: Color, -// color2: Color, -// color3: Color, -// folderMaskBrush: Brush, -// leftIcon: @Composable () -> Unit, -// rightIcon: @Composable () -> Unit, -// textBackgroundColor: Color, -// folderName: String = "", -//) { -// -// @Composable -// fun FolderLayerBox( -// color: Color, -// size: Dp, -// height: Dp = size, -// padding: PaddingValues = PaddingValues(0.dp), -// rotation: Float = 0f, -// ) { -// Surface( -// modifier = Modifier -// .padding(padding) -// .rotate(rotation) -// .width(size) -// .height(height) -// .shadow( -// elevation = 4.dp, -// ambientColor = Color.Black.copy(alpha = 0.5f), // 그림자 강도 조절! -// spotColor = Color.Black.copy(alpha = 0.5f), -// shape = RoundedCornerShape(18.dp) -// ), -// shape = RoundedCornerShape(18.dp), -// color = color, -// ) {} -// } -// -// Surface( -// modifier = Modifier -// .width(165.3.dp) -// .height(145.8535.dp), -// shape = RoundedCornerShape(28.5.dp), -// color = backgroundColor, -// shadowElevation = 3.8.dp -// ) { -// Box( -// Modifier.fillMaxSize(), -// contentAlignment = Alignment.Center -// ) { -// FolderLayerBox( -// color = color1, -// size = 105.45.dp, -// padding = PaddingValues(bottom = 5.7.dp), -// rotation = -7.39f -// ) -// FolderLayerBox( -// color = color2, -// size = 105.45.dp, -// padding = PaddingValues(bottom = 3.1825.dp), -// rotation = 4.86f -// ) -// FolderLayerBox( -// color = color3, -// size = 126.407.dp, -// height = 107.9605.dp, -// padding = PaddingValues(top = 7.6.dp), -// rotation = 0f -// ) -// -// Box( -// Modifier -// .fillMaxWidth() -// .align(Alignment.BottomCenter) -// ) { -// Image( -// painter = painterResource(R.drawable.folder_mask), -// contentDescription = null, -// modifier = Modifier -// .fillMaxWidth() -// .align(Alignment.BottomCenter) -// .graphicsLayer(alpha = 0.99f) -// .drawWithCache { -// onDrawWithContent { -// drawContent() -// drawRect(folderMaskBrush, blendMode = BlendMode.SrcAtop) -// } -// } -// .shadow( -// elevation = 9.5.dp, -// ambientColor = Color.Black.copy(alpha = 0.5f), -// spotColor = Color.Black.copy(alpha = 0.5f), -// ) -// ) -// -// Box( -// modifier = Modifier -// .align(Alignment.TopStart) -// .padding(top = 12.5495.dp, start = 19.95.dp) -// ) { -// leftIcon() -// } -// -// Box( -// modifier = Modifier -// .align(Alignment.TopEnd) -// .padding(top = 25.8685.dp, end = 19.dp) -// ) { -// rightIcon() -// } -// -// if(folderName.isNotEmpty()){ -// Row( -// modifier = Modifier -// .padding(end = 5.dp) -// .align(Alignment.BottomStart) -// .offset(x = 17.499.dp, y = (-17.499).dp), -// verticalAlignment = Alignment.CenterVertically, -// horizontalArrangement = Arrangement.spacedBy(7.7805.dp) -// ) { -// Box( -// modifier = Modifier -// .size(29.1745.dp) -// .clip(CircleShape) -// .background(color = textBackgroundColor), -// contentAlignment = Alignment.Center -// ) { -// Text( -// text = folderName.first().toString(), -// fontSize = 15.sp, -// fontFamily = DefaultFont, -// fontWeight = FontWeight.Bold, -// color = White, -// ) -// } -// -// Text( -// text = folderName, -// fontSize = 15.sp, -// fontFamily = DefaultFont, -// fontWeight = FontWeight.Medium, -// color = Black, -// maxLines = 1, // 최대 1줄 -// overflow = TextOverflow.Ellipsis // 잘리면 ... 표시 -// ) -// } -// } -// } -// } -// } -//} - -//@Composable -//fun FolderItemLayout( -// backgroundColor: Color, -// color1: Color, -// color2: Color, -// color3: Color, -// folderMaskBrush: Brush, -// leftIcon: @Composable () -> Unit, -// rightIcon: @Composable () -> Unit, -// textBackgroundColor: Color, -// folderName: String = "", -// modifier: Modifier = Modifier, // ⬅️ weight를 바깥에서 주입할 수 있게 열어둠 -//) { -// // 설계 기준(원본) 크기: 165.3 x 145.8535 (dp) -// val designW = 165.3.dp -// val designH = 145.8535.dp -// val aspect = 165.3f / 145.8535f // ≈ 1.13333 -// -// // 내부 박스/카드 조각 -// @Composable -// fun FolderLayerBox( -// color: Color, -// size: Dp, -// height: Dp = size, -// padding: PaddingValues = PaddingValues(0.dp), -// rotation: Float = 0f, -// corner: Dp, -// shadow: Dp, -// ) { -// Surface( -// modifier = Modifier -// .padding(padding) -// .rotate(rotation) -// .width(size) -// .height(height) -// .shadow( -// elevation = shadow, -// ambientColor = Color.Black.copy(alpha = 0.5f), -// spotColor = Color.Black.copy(alpha = 0.5f), -// shape = RoundedCornerShape(corner) -// ), -// shape = RoundedCornerShape(corner), -// color = color, -// ) {} -// } -// -// // 외곽 Surface는 고정 dp를 없애고, 비율만 고정 (가로 기준) -// Surface( -// modifier = modifier -// .fillMaxWidth() // 바깥(Row/Column)에서 weight로 폭을 결정하게 함 -// .aspectRatio(aspect), // 세로는 비율로 자동 결정 -// // 코너/섀도는 내부에서 스케일된 값으로 다시 지정 (아래 BoxWithConstraints 안에서) -// color = Color.Transparent, -// ) { -// // 부모가 준 실제 width로 스케일 팩터 계산 -// BoxWithConstraints(Modifier.fillMaxSize()) { -// val s = (maxWidth / designW) // 스케일(폭 기준). Dp/Dp -> Float -// -// // 자주 쓰는 헬퍼 -// fun Dp.scaled() = this * s -// -// // 라운드/섀도 값도 스케일 (룩 유지) -// val cornerOuter = 28.5.dp.scaled() -// val cornerInner = 18.dp.scaled() -// val shadowCard = 3.8.dp//.scaled() -// val shadowLayer = 4.dp.scaled() -// val imgShadow = 9.5.dp.scaled() -// -// // 겉 Surface에 최종 모양/섀도 적용 -// Surface( -// modifier = Modifier.fillMaxSize(), -// shape = RoundedCornerShape(cornerOuter), -// color = backgroundColor, -// shadowElevation = shadowCard -// ) { -// Box( -// Modifier.fillMaxSize(), -// contentAlignment = Alignment.Center -// ) { -// // 1층 -// FolderLayerBox( -// color = color1, -// size = 105.45.dp.scaled(), -// padding = PaddingValues(bottom = 5.7.dp.scaled()), -// rotation = -7.39f, -// corner = cornerInner, -// shadow = shadowLayer -// ) -// // 2층 -// FolderLayerBox( -// color = color2, -// size = 105.45.dp.scaled(), -// padding = PaddingValues(bottom = 3.1825.dp.scaled()), -// rotation = 4.86f, -// corner = cornerInner, -// shadow = shadowLayer -// ) -// // 3층 -// FolderLayerBox( -// color = color3, -// size = 126.407.dp.scaled(), -// height = 107.9605.dp.scaled(), -// padding = PaddingValues(top = 7.6.dp.scaled()), -// rotation = 0f, -// corner = cornerInner, -// shadow = shadowLayer -// ) -// -// Box( -// Modifier -// .fillMaxWidth() -// .align(Alignment.BottomCenter) -// ) { -// Image( -// painter = painterResource(R.drawable.folder_mask), -// contentDescription = null, -// contentScale = ContentScale.FillWidth, -// modifier = Modifier -// .fillMaxWidth() -// .align(Alignment.BottomCenter) -// .graphicsLayer(alpha = 0.99f) -// .drawWithCache { -// onDrawWithContent { -// drawContent() -// drawRect(folderMaskBrush, blendMode = BlendMode.SrcAtop) -// } -// } -// .shadow( -// elevation = imgShadow, -// ambientColor = Color.Black.copy(alpha = 0.5f), -// spotColor = Color.Black.copy(alpha = 0.5f), -// ) -// ) -// -// Box( -// modifier = Modifier -// .align(Alignment.TopStart) -// .padding(top = 12.5495.dp.scaled(), start = 19.95.dp.scaled()) -// ) { -// leftIcon() -// } -// -// Box( -// modifier = Modifier -// .align(Alignment.TopEnd) -// .padding(top = 25.8685.dp.scaled(), end = 19.dp.scaled()) -// ) { -// rightIcon() -// } -// -// if (folderName.isNotEmpty()) { -// Row( -// modifier = Modifier -// .align(Alignment.BottomStart) -// .offset( -// x = 17.499.dp.scaled(), -// y = (-17.499).dp.scaled() -// ), -// verticalAlignment = Alignment.CenterVertically, -// horizontalArrangement = Arrangement.spacedBy(7.7805.dp.scaled()) -// ) { -// Box( -// modifier = Modifier -// .size(29.1745.dp.scaled()) -// .clip(CircleShape) -// .background(color = textBackgroundColor), -// contentAlignment = Alignment.Center -// ) { -// Text( -// text = folderName.first().toString(), -// fontSize = 15.sp, // 폰트는 보통 px 고정 권장, 필요하면 스케일링도 가능 -// fontFamily = DefaultFont, -// fontWeight = FontWeight.Bold, -// color = White, -// ) -// } -// -// Text( -// text = folderName, -// fontSize = 15.sp, -// fontFamily = DefaultFont, -// fontWeight = FontWeight.Medium, -// color = Black, -// maxLines = 1, -// overflow = TextOverflow.Ellipsis -// ) -// } -// } -// } -// } -// } -// } -// } -//} - val topFolderMaskBrush = Brush.verticalGradient( colorStops = arrayOf( 1.0f to Gray100.copy(alpha = 0.7f), @@ -629,6 +287,7 @@ fun TopFolderItemLayout( modifier: Modifier = Modifier, colorStyle: CategoryColorStyle, folderName: String = "", + visibleBookmarked: Boolean = true, isBookmarked: Boolean = false, editStateViewModel: EditStateViewModel, onBookmark: () -> Unit @@ -641,20 +300,22 @@ fun TopFolderItemLayout( folderMaskBrush = topFolderMaskBrush, leftIcon = {}, rightIcon = { - if(editStateViewModel.isEditMode){ - Box( - modifier = Modifier - ) { - PencilIcon(colorStyle.color2) - } - }else { - Box( - modifier = Modifier - .noRippleClickable { - onBookmark() - } - ) { - BookMarkStar(isBookmarked) + if(visibleBookmarked){ + if (editStateViewModel.isEditMode) { + Box( + modifier = Modifier + ) { + PencilIcon(colorStyle.color2) + } + } else { + Box( + modifier = Modifier + .noRippleClickable { + onBookmark() + } + ) { + BookMarkStar(isBookmarked) + } } } }, @@ -669,6 +330,7 @@ fun BottomFolderItemLayout( modifier: Modifier = Modifier, colorStyle: CategoryColorStyle, folder: FolderSimpleInfo, + visibleBookmarked: Boolean = true, editStateViewModel: EditStateViewModel, onEdit: ()-> Unit = {}, onChangeSharing: () -> Unit = {} @@ -687,11 +349,11 @@ fun BottomFolderItemLayout( } } ){ - folder.isSharing?.let{ sharing -> - if(sharing=="share"){ - ShareFolderIcon(colorStyle.color1) - } else { - LockFolderIcon(colorStyle.color1) + folder.isSharing?.let{ + when(it){ + "share" -> ShareFolderIcon(colorStyle.color2) + "personal" -> LockFolderIcon(colorStyle.color2) + else -> {} } } } diff --git a/feature/file/src/main/java/com/example/file/ui/item/LinkItemLayout.kt b/feature/file/src/main/java/com/example/file/ui/item/LinkItemLayout.kt index 306ae4ee..8bc9fb37 100644 --- a/feature/file/src/main/java/com/example/file/ui/item/LinkItemLayout.kt +++ b/feature/file/src/main/java/com/example/file/ui/item/LinkItemLayout.kt @@ -6,6 +6,8 @@ import android.util.Log import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -18,7 +20,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape @@ -28,25 +29,24 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.ExperimentalTextApi +import androidx.compose.ui.text.PlatformTextStyle +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.lifecycle.viewmodel.compose.viewModel -import androidx.navigation.compose.rememberNavController import coil3.compose.AsyncImage import coil3.request.ImageRequest import coil3.request.crossfade @@ -54,8 +54,6 @@ import coil3.request.error import coil3.request.fallback import coil3.request.placeholder import com.example.core.model.LinkItemInfo -import com.example.design.modifier.noRippleClickable -import com.example.file.FileViewModel import com.example.file.R import com.example.file.ui.theme.Black import com.example.file.ui.theme.DefaultFont @@ -66,11 +64,12 @@ import com.example.file.ui.theme.Gray600 import com.example.file.ui.theme.Gray800 import com.example.file.ui.theme.White import com.example.file.ui.theme.domainLogoPainterOrNull -import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import java.time.OffsetDateTime -@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) +@OptIn( + ExperimentalMaterial3Api::class, + ExperimentalFoundationApi::class, + ExperimentalTextApi::class +) @Composable fun LinkItemLayout( link: LinkItemInfo? = null, @@ -78,7 +77,6 @@ fun LinkItemLayout( onLongClick: (Long) -> Unit = {}, ) { val tags = link?.tags?:emptyList() - var showDialog by remember { mutableStateOf(false) } val domainIcon = link?.let{ domainLogoPainterOrNull(it.url) } @@ -99,28 +97,38 @@ fun LinkItemLayout( Box ( // 태그 배경: 크기 wrap, 둥근 모서리(6dp), Gray100 배경색 modifier = Modifier - .wrapContentSize() .background( shape = RoundedCornerShape(size = 6.dp), color = Gray100 - ), + ) + .padding(horizontal = 6.dp, vertical = 1.dp), + contentAlignment = Alignment.Center ) { + // 태그 텍스트 Text( - // 태그 텍스트를 Box 중앙에 정렬, 내부 여백(가로 6dp, 세로 3dp) + // 태그 텍스트를 Box 중앙에 정렬, 내부 여백(가로 1dp, 세로 2dp) modifier = Modifier - .align(Alignment.Center) - .padding(horizontal = 6.dp, vertical = 1.dp), + .padding(horizontal = 1.dp, vertical = 2.dp), text = tag, - // 폰트 크기(10sp) - fontSize = 10.sp, + // 폰트 크기(12sp) + fontSize = 12.sp, // 폰트 fontFamily = DefaultFont, // 폰트 굵기(Normal) fontWeight = FontWeight.Normal, // 글자색(Gray600) color = Gray600, + + textAlign = TextAlign.Center, + + style = TextStyle( + platformStyle = PlatformTextStyle( + includeFontPadding = false + ) + ) ) + } } @@ -128,7 +136,7 @@ fun LinkItemLayout( indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = { - link?.linkuId?.let { + link.linkuId.let { Log.d("LinkItemLayout", "아이템 클릭: \"savelinkresult/${it}\"") onClick(link) } @@ -144,21 +152,17 @@ fun LinkItemLayout( // 카드 크기: 가로 181dp, 세로 267dp modifier = Modifier .width(181.dp) - //.height(267.dp) - then(modifier) - /*.pointerInput(Unit) { - detectTapGestures( - onLongPress = { - showDialog = true // 꾹 누르면 Dialog 띄우기 - } - ) - }*/, + .then(modifier) + .shadow( + elevation = 4.dp, + shape = RoundedCornerShape(18.dp) + ), // 모서리 둥글게(18dp) - shape = RoundedCornerShape(18.dp), + //shape = RoundedCornerShape(18.dp), // 카드 배경색(White) color = White, // 그림자(입체감) 효과(20dp) - shadowElevation = 5.dp//(if(painter == null) 0 else 5).dp, + //shadowElevation = 5.dp//(if(painter == null) 0 else 5).dp, ) { // 내용 전체를 세로로 배치하는 Column Column ( @@ -197,11 +201,13 @@ fun LinkItemLayout( } } + // 링크 메인 이미지, 제목 사이 간격 + Spacer(modifier = Modifier.height(10.dp)) + // (2) 링크 제목 Text( // 위쪽 여백(10dp) - modifier = Modifier - .padding(top = 10.dp), + modifier = Modifier, text = link?.title?:"제목", // 폰트 크기(15sp) fontSize = 15.sp, @@ -215,12 +221,14 @@ fun LinkItemLayout( overflow = TextOverflow.Ellipsis // 잘리면 ... 표시 ) + // 링크 제목, 태그 사이 간격 + Spacer(modifier = Modifier.height(1.dp)) + // (3) 링크 분류 태그(여러 개를 Row에 배치) LazyRow( // 가로 전체 채우기, 위쪽 여백(8dp) modifier = Modifier - .height(30.dp) - .padding(top = 8.dp), + .height(30.dp), // 태그 간 5dp 간격, 왼쪽 정렬 horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.Start), // 세로 중앙 정렬 @@ -232,8 +240,8 @@ fun LinkItemLayout( } } - // (4) 남은 공간 모두 차지하는 Spacer (아래로 밀어내기) - Spacer(modifier = Modifier.height(8.dp)) + // 링크 태그, 설명 프레임 사이 간격 + Spacer(modifier = Modifier.height(5.dp)) // (5) 링크 설명 프레임 (도메인, 아이콘 등) Row( @@ -300,7 +308,7 @@ private fun LinkItemTest() { contentAlignment = Alignment.TopCenter ){ Box( - modifier = Modifier.alpha(0.35f), + //modifier = Modifier.alpha(0.35f), ){ LinkItemLayout( link = null @@ -323,5 +331,6 @@ private fun LinkItemTest() { textAlign = TextAlign.Center, ) } -} + LinkItemLayout { } +} \ No newline at end of file diff --git a/feature/file/src/main/java/com/example/file/ui/top/bar/component/BottomFolderListMenu.kt b/feature/file/src/main/java/com/example/file/ui/top/bar/component/BottomFolderListMenu.kt index 4d9b57d1..98b20112 100644 --- a/feature/file/src/main/java/com/example/file/ui/top/bar/component/BottomFolderListMenu.kt +++ b/feature/file/src/main/java/com/example/file/ui/top/bar/component/BottomFolderListMenu.kt @@ -1,37 +1,58 @@ package com.example.file.ui.top.bar.component +import android.util.Log import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import com.example.file.FileViewModel -import com.example.file.viewmodel.folder.state.FolderStateViewModel +import com.example.core.model.FolderSimpleInfo +import com.example.design.modifier.noRippleClickable +import com.example.design.theme.color.Basic import com.example.design.theme.color.CategoryColorStyle +import com.example.file.FileViewModel import com.example.file.ui.theme.DefaultFont import com.example.file.ui.theme.Gray800 import com.example.file.ui.theme.White import com.example.file.viewmodel.folder.state.FolderState +import com.example.file.viewmodel.folder.state.FolderStateViewModel @Composable fun BottomFolderListMenu( + modifier: Modifier = Modifier, fileViewModel: FileViewModel, folderStateViewModel: FolderStateViewModel, onChangeFolder: () -> Unit @@ -42,88 +63,390 @@ fun BottomFolderListMenu( val colorStyles = fileViewModel.categoryColorMap.collectAsStateWithLifecycle().value + BottomFolderListMenuLayout( + modifier = modifier, + isLinks = isLinks, + bottomMenuExpanded = folderStateViewModel.bottomMenuExpanded, + onDismissRequest = { folderStateViewModel.updateBottomMenuExpanded(false) }, + parentFolders = parentFolders, + parentFolderSelected = { it.folderId == folderStateViewModel.selectedTopFolder?.folderId }, + parentFolderName = { it.folderName }, + parentFolderColor = { folder -> colorStyles[folder.folderName]?: CategoryColorStyle.DEFAULT }, + onParentFolderClick = { folder -> + if(folder.folderId!=folderStateViewModel.selectedTopFolder?.folderId){ + fileViewModel.getFoldersAndNotCategorizationLinks(folder.folderId) + folderStateViewModel.updateSelectedTopFolder(folder) + folderStateViewModel.updateFolderState(FolderState.BOTTOM) + folderStateViewModel.updateBottomMenuExpanded(false) + onChangeFolder() + } + }, + subFolders = subFolders, + subFolderSelected = { it.folderId == folderStateViewModel.selectedBottomFolder?.folderId }, + subFolderName = { it.folderName }, + onSubFolderClick = { folder -> + if(folder.folderId!=folderStateViewModel.selectedBottomFolder?.folderId){ + fileViewModel.getLinks(folder.folderId) + folderStateViewModel.updateSelectedBottomFolder(folder) + folderStateViewModel.updateFolderState(FolderState.LINKS) + folderStateViewModel.updateBottomMenuExpanded(false) + onChangeFolder() + } + } + ) +} + +// 전체 메뉴 : 스크롤 바 = 205 : 4 +// private const val BOTTOM_FOLDER_LIST_MENU_WIDTH = 205f +// private const val BOTTOM_FOLDER_LIST_MENU_HEIGHT = 264F + +@Composable +private fun BottomFolderListMenuLayout( + modifier: Modifier = Modifier, + isLinks: Boolean, + bottomMenuExpanded: Boolean, + onDismissRequest: () -> Unit, + parentFolders: List, + parentFolderSelected: (FolderSimpleInfo) -> Boolean, + parentFolderName: (FolderSimpleInfo) -> String, + parentFolderColor: @Composable (FolderSimpleInfo) -> CategoryColorStyle, + onParentFolderClick: (FolderSimpleInfo) -> Unit, + subFolders: List, + subFolderSelected: (FolderSimpleInfo) -> Boolean, + subFolderName: (FolderSimpleInfo) -> String, + onSubFolderClick: (FolderSimpleInfo) -> Unit +){ + // ----------------------------스크롤 바 추후 수정---------------------------- + val menuHeight = 264f + val menuWidth = 205f + + // 스크롤 바 너비비 = 스크롤 바 너비 / 메뉴 너비 + val scrollBarWidthWeight = 4f / menuWidth + + // 스크롤 바 길이비 = 메뉴 길이 / 전체 아이템 총 길이 + val scrollBarHeightWeight = menuHeight / (subFolders.size * MENU_ITEM_HEIGHT) + + // 트랙(스크롤바가 움직이는 레일) 높이 + var trackHeight by remember { mutableIntStateOf(0) } + + + val menuScrollState = rememberScrollState() + + LaunchedEffect(bottomMenuExpanded) { + if(bottomMenuExpanded) + menuScrollState.scrollTo(0) + } + + val scrollable by remember { + derivedStateOf { menuScrollState.maxValue > 0 } + } + + val currentScrollValue = menuScrollState.value + val maxScrollValue = menuScrollState.maxValue + + // thumb(움직이는 막대) 높이/오프셋을 계산 + val thumbHeight by remember(trackHeight, maxScrollValue) { + derivedStateOf { + if (trackHeight <= 0) 0f + else if (maxScrollValue <= 0) 0f // 스크롤 불가면 전체(사실상 숨겨도 됨) + else { + val contentHeightPx = trackHeight + maxScrollValue + val ratio = trackHeight.toFloat() / contentHeightPx.toFloat() + // UX용 최소 높이(너무 작아지면 안 보임 방지) - 필요 없으면 삭제 가능 + /*val minThumbPx = (18.dp.value * (trackHeight / 264f)).roundToInt() + max((trackHeight * ratio).roundToInt(), minThumbPx)*/ + //(trackHeight * ratio).roundToInt() + //ratio + menuHeight * ratio + } + } + } + + val thumbTopPadding by remember(trackHeight, maxScrollValue, currentScrollValue, thumbHeight) { + derivedStateOf { + if (trackHeight <= 0) 0f + else if (maxScrollValue <= 0) 0f + else { + val movableRange = (trackHeight - thumbHeight).coerceAtLeast(0F) + val ratio = currentScrollValue.toFloat() / maxScrollValue.toFloat() + val contentHeightPx = trackHeight + maxScrollValue + val thumbRatio = trackHeight.toFloat() / contentHeightPx.toFloat() + val r = (1 - thumbRatio) * ratio + //(movableRange * ratio).roundToInt() + //(trackHeight * ratio).roundToInt() + r + } + } + } + + @Composable + fun ScrollBar(modifier: Modifier) { + Log.d("SB", "value=${menuScrollState.value}, max=${menuScrollState.maxValue}, track=$trackHeight, thumb=$thumbHeight, off=$thumbTopPadding") + Log.d("SB", "thumbTopPadding=$thumbTopPadding, thumbHeight=$thumbHeight") + Log.d("SB", "scrollable=$scrollable") + + // 스크롤이 가능한 경우에만 표시(원하면 항상 표시로 바꿀 수 있음) + if (/*maxScrollValue > 0 && trackHeight > 0 && */thumbHeight > 0f) { + Column( + modifier = modifier + .onSizeChanged { + Log.d("SB", "onSizeChanged") + + trackHeight = it.height + } + ) { + Spacer(modifier = Modifier + .fillMaxHeight(thumbTopPadding) + + .fillMaxWidth() + /*.background( + shape = RoundedCornerShape(18.dp), + color = Basic.blue[200].copy(alpha = 0.5f) + )*/ + ) + + // thumb + Box( + modifier = Modifier + .fillMaxWidth() + .height(thumbHeight.dp) + .clip(RoundedCornerShape(18.dp)) + .background(Basic.gray[500]) + ) + } + } else { + // 트랙 높이 측정은 해야 하니까(첫 프레임), 투명 트랙만 깔아둠 + Box( + modifier = modifier + .onSizeChanged { trackHeight = it.height } + ) + } + } + // ----------------------------스크롤 바 추후 수정---------------------------- + DropdownMenu( - modifier = Modifier - .heightIn(max = 264.dp) - .width(205.dp), + modifier = modifier + .width(menuWidth.dp) + .padding(vertical = 8.dp), shape = RoundedCornerShape(18.dp), offset = DpOffset(0.dp, 10.dp), - expanded = folderStateViewModel.bottomMenuExpanded, - onDismissRequest = { folderStateViewModel.updateBottomMenuExpanded(false) }, - containerColor = White + expanded = bottomMenuExpanded, + onDismissRequest = onDismissRequest, + containerColor = White, ) { - if(!isLinks){ - for ((i, folder) in parentFolders.withIndex()) { - val colorStyle = colorStyles[folder.folderName]?: CategoryColorStyle.DEFAULT - - DropdownMenuItem( - leadingIcon = { - Box( - modifier = Modifier - .size(25.dp) - .clip(CircleShape) - .background(color = colorStyle.color4) - ) - }, - text = { - Text( - text = folder.folderName, - fontSize = 15.sp, - lineHeight = 22.sp, - fontFamily = DefaultFont, - fontWeight = FontWeight(400), - color = Gray800, - maxLines = 1, // 한 줄만 보여주고 - overflow = TextOverflow.Ellipsis // 넘치면 ...으로 대체 + + // 링크 목록 위 스크롤 바를 띄우는 박스 + Box{ + if (!isLinks) { + Column( + modifier = Modifier + .heightIn(max = 264.dp) + .verticalScroll(menuScrollState), + verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically), + ) { + parentFolders.forEachIndexed { index, folder -> + val selected = parentFolderSelected(folder) + val colorStyle = parentFolderColor(folder) + + BottomFolderListMenuRow( + leadingColor = colorStyle.color4, + text = parentFolderName(folder), + enabled = !selected, + onClick = { onParentFolderClick(folder) } ) - }, - onClick = { - if(folder.folderId!=folderStateViewModel.selectedTopFolder?.folderId){ - fileViewModel.getFoldersAndNotCategorizationLinks(folder.folderId) - folderStateViewModel.updateSelectedTopFolder(folder) - folderStateViewModel.updateFolderState(FolderState.BOTTOM) - folderStateViewModel.updateBottomMenuExpanded(false) - } } - ) - } - }else{ - for ((i, folder) in subFolders.withIndex()) { - DropdownMenuItem( - text = { - Text( - text = folder.folderName, - fontSize = 15.sp, - lineHeight = 22.sp, - fontFamily = DefaultFont, - fontWeight = FontWeight(400), - color = Gray800, - maxLines = 1, // 한 줄만 보여주고 - overflow = TextOverflow.Ellipsis // 넘치면 ...으로 대체 + } + } else { + Column( + modifier = Modifier + .heightIn(max = 264.dp) + .verticalScroll(menuScrollState), + verticalArrangement = Arrangement.spacedBy(18.dp, Alignment.CenterVertically), + ) { + subFolders.forEach { folder -> + val selected = subFolderSelected(folder) + + BottomFolderListMenuRow( + leadingColor = null, + text = subFolderName(folder), + enabled = !selected, + onClick = { onSubFolderClick(folder) } ) - }, - onClick = { - if(folder.folderId!=folderStateViewModel.selectedBottomFolder?.folderId){ - fileViewModel.getLinks(folder.folderId) - folderStateViewModel.updateSelectedBottomFolder(folder) - folderStateViewModel.updateFolderState(FolderState.LINKS) - folderStateViewModel.updateBottomMenuExpanded(false) - } } - ) + } } + /*if(scrollable){ + ScrollBar( + modifier = Modifier + //.fillMaxWidth(SCROLL_BAR_WIDTH_WEIGHT) + //.fillMaxHeight() + .align(Alignment.TopEnd) + .height(264.dp) + .width(4.dp) + ) + }*/ + } + } +} + +private const val MENU_ITEM_HEIGHT = 25 + +@Composable +private fun BottomFolderListMenuRow( + modifier: Modifier = Modifier, + leadingColor: Color?, + text: String, + enabled: Boolean, + onClick: () -> Unit +){ + Row( + modifier = modifier + .fillMaxWidth() + .noRippleClickable(enabled = enabled, onClick = onClick) + .padding(horizontal = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + if (leadingColor != null) { + Box( + modifier = Modifier + .size(MENU_ITEM_HEIGHT.dp) + .clip(CircleShape) + .background(color = leadingColor) + ) + Spacer(modifier = Modifier.width(8.dp)) } + + Text( + text = text, + fontSize = 15.sp, + lineHeight = 22.sp, + fontFamily = DefaultFont, + fontWeight = FontWeight(400), + color = Gray800, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) } } -@Preview() +private val folderSimpleInfoList = listOf( + FolderSimpleInfo( + folderId = 1L, + folderName = "Folder 1", + parentFolderId = 0L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 2L, + folderName = "Folder 2", + parentFolderId = 0L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 3L, + folderName = "Folder 3", + parentFolderId = 1L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 4L, + folderName = "Folder 4", + parentFolderId = 1L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 5L, + folderName = "Folder 5", + parentFolderId = 2L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 6L, + folderName = "Folder 6", + parentFolderId = 2L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 7L, + folderName = "Folder 7", + parentFolderId = 3L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 8L, + folderName = "Folder 8", + parentFolderId = 3L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 9L, + folderName = "Folder 9", + parentFolderId = 4L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 10L, + folderName = "Folder 10", + parentFolderId = 4L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 11L, + folderName = "Folder 11", + parentFolderId = 5L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 12L, + folderName = "Folder 12", + parentFolderId = 5L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 13L, + folderName = "Folder 13", + parentFolderId = 6L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 14L, + folderName = "Folder 14", + parentFolderId = 6L, + isBookmarked = true + ), + FolderSimpleInfo( + folderId = 15L, + folderName = "Folder 15", + parentFolderId = 7L, + isBookmarked = false + ), + FolderSimpleInfo( + folderId = 16L, + folderName = "Folder 16", + parentFolderId = 7L, + isBookmarked = true + ) +) + +@Preview(heightDp = 1000) @Composable -fun BottomFolderListMenuTest(){ - val folderStateViewModel: FolderStateViewModel = viewModel() - BottomFolderListMenu( - fileViewModel = hiltViewModel(), - folderStateViewModel = folderStateViewModel, - onChangeFolder = {} +private fun BottomFolderListMenuLayoutTest(){ + + BottomFolderListMenuLayout( + isLinks = false, + bottomMenuExpanded = true, + onDismissRequest = {}, + parentFolders = folderSimpleInfoList, + parentFolderSelected = { false }, + parentFolderName = { "parentFolderName" }, + parentFolderColor = { + CategoryColorStyle.categoryStyleList[it.folderId.toInt() % CategoryColorStyle.categoryStyleList.size] + }, + onParentFolderClick = {}, + subFolders = folderSimpleInfoList, + subFolderSelected = { false }, + subFolderName = { "subFolderName" }, + onSubFolderClick = {} ) -} \ No newline at end of file +} diff --git a/feature/home/src/main/java/com/example/home/screen/HomeScreen.kt b/feature/home/src/main/java/com/example/home/screen/HomeScreen.kt index c0d46394..ee4db036 100644 --- a/feature/home/src/main/java/com/example/home/screen/HomeScreen.kt +++ b/feature/home/src/main/java/com/example/home/screen/HomeScreen.kt @@ -1,8 +1,5 @@ package com.example.home.screen -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.expandVertically -import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -16,8 +13,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -25,7 +20,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -38,18 +32,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.zIndex @@ -57,20 +47,16 @@ import coil3.compose.AsyncImage import com.example.core.model.LinkSimpleInfo import com.example.design.BrushText import com.example.design.top.search.SearchBarTopSheet -import com.example.design.modifier.noRippleClickable import com.example.design.theme.LocalColorTheme import com.example.design.theme.LocalFontTheme import com.example.design.theme.color.Basic import com.example.design.util.DesignSystemBars -import com.example.file.ui.theme.FileTopBarLinkUFont -import com.example.file.ui.theme.MainColor import com.example.home.HomeViewModel import com.example.home.R import com.example.home.component.ClipboardLinkPasteBanner import com.example.home.component.rememberClipboardUrl import com.example.home.ui.top.bar.HomeTopBar import kotlinx.coroutines.launch -import com.example.design.R as Res data class LinkItem( val imageResId: Int?, // 링크 대표 이미지 diff --git a/feature/login/src/main/java/com/example/login/ui/screen/EmailLoginScreen.kt b/feature/login/src/main/java/com/example/login/ui/screen/EmailLoginScreen.kt index 16e41c8a..9c36140f 100644 --- a/feature/login/src/main/java/com/example/login/ui/screen/EmailLoginScreen.kt +++ b/feature/login/src/main/java/com/example/login/ui/screen/EmailLoginScreen.kt @@ -237,28 +237,26 @@ fun EmailLoginScreen( val dividerStartPos = (220.scaler) // | 시작점 val signUpStartPos = (247.scaler) // 회원가입 시작점 - Box( + Row( modifier = Modifier + .align(Alignment.CenterHorizontally) .fillMaxWidth() .height((30.scaler)), // 클릭 영역 확보를 위한 높이 - contentAlignment = Alignment.CenterStart //세로 중앙 정렬 - ) { - // 1. 비밀번호 재설정 + horizontalArrangement = Arrangement.spacedBy(25.dp, alignment = Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically + ){ Text( text = "비밀번호 재설정", fontSize = 15.sp, fontFamily = Paperlogy.font, color = Color(0xFF87898F), modifier = Modifier - .offset(x = resetStartPos) // 항상 101/412 지점 .noRippleClickable { //if (loginState !is LoginState.Loading) { -> 혹시 나중에 로딩중이 길어지면 사용해주세요. navigator.navigate("resetPassword") //} } ) - - // 2. 구분선 (|) // TODO : 비밀번호 재설정, 회원가입 대비 내려가서 부득이하게 약간 위로 올림. 다현이랑 조절해보기. Text( text = "|", fontSize = 14.sp, @@ -266,30 +264,23 @@ fun EmailLoginScreen( color = Color(0xFF87898F), style = TextStyle( baselineShift = BaselineShift(0.3f) // 약간 위로 올림 - ), - //style = TextStyle(baselineShift = BaselineShift(0.15f)), - modifier = Modifier - .offset(x = dividerStartPos) // 항상 220/412 지점 + ) ) - - // 3. 회원가입 Text( text = "회원가입", fontSize = 15.sp, fontFamily = Paperlogy.font, color = Color(0xFF87898F), modifier = Modifier - .offset(x = signUpStartPos) // 항상 247/412 지점 .noRippleClickable { focusManager.clearFocus() onSignUpClick() } ) } - - } } } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e56ea5bd..f315805b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,8 +34,6 @@ foundation = "1.9.5" composeTesting = "1.0.0-alpha09" toolsCore = "1.0.0-alpha14" foundationVersion = "1.10.1" -foundationLayout = "1.10.0" - [libraries] @@ -86,8 +84,6 @@ androidx-compose-foundation = { group = "androidx.compose.foundation", name = "f androidx-compose-testing = { group = "androidx.xr.compose", name = "compose-testing", version.ref = "composeTesting" } androidx-tools-core = { group = "androidx.privacysandbox.tools", name = "tools-core", version.ref = "toolsCore" } androidx-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundationVersion" } -androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout", version.ref = "foundationLayout" } -