diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiBottomSheetHost.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiBottomSheetHost.kt new file mode 100644 index 0000000..9bf9367 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiBottomSheetHost.kt @@ -0,0 +1,15 @@ +package com.aiosman.ravenow.ui.account + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState + +@Composable +fun MbtiBottomSheetHost() { + val show = MbtiSheetManager.visible.collectAsState(false).value + if (show) { + MbtiSelectBottomSheet( + onClose = { MbtiSheetManager.close() } + ) + } +} + diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt index cf49830..4e173e7 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSelectScreen.kt @@ -1,42 +1,60 @@ package com.aiosman.ravenow.ui.account +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight 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.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.Velocity +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Check import com.aiosman.ravenow.AppState import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.R -import com.aiosman.ravenow.ui.comment.NoticeScreenHeader +import com.aiosman.ravenow.ui.modifiers.noRippleClickable // MBTI类型列表 val MBTI_TYPES = listOf( @@ -46,96 +64,285 @@ val MBTI_TYPES = listOf( "ISTP", "ISFP", "ESTP", "ESFP" ) +fun getMbtiImageResId(mbti: String, isDarkMode: Boolean): Int { + return when { + isDarkMode && mbti == "ENTP" -> R.mipmap.anmbti_entp + isDarkMode && mbti == "ESTP" -> R.mipmap.anmbti_estp + isDarkMode && mbti == "ENTJ" -> R.mipmap.anmbti_entj + else -> when (mbti) { + "INTJ" -> R.mipmap.mbti_intj + "INTP" -> R.mipmap.mbti_intp + "ENTJ" -> R.mipmap.mbti_entj + "ENTP" -> R.mipmap.mbti_entp + "INFJ" -> R.mipmap.mbti_infj + "INFP" -> R.mipmap.mbti_infp + "ENFJ" -> R.mipmap.mbti_enfj + "ENFP" -> R.mipmap.mbti_enfp + "ISTJ" -> R.mipmap.mbti_istj + "ISFJ" -> R.mipmap.mbti_isfj + "ESTJ" -> R.mipmap.mbti_estj + "ESFJ" -> R.mipmap.mbti_esfj + "ISTP" -> R.mipmap.mbti_istp + "ISFP" -> R.mipmap.mbti_isfp + "ESTP" -> R.mipmap.mbti_estp + "ESFP" -> R.mipmap.mbti_esfp + else -> R.mipmap.xingzuo + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun MbtiSelectScreen() { - val navController = LocalNavController.current +fun MbtiSelectBottomSheet( + onClose: () -> Unit +) { val appColors = LocalAppTheme.current + val isDarkMode = AppState.darkMode val model = AccountEditViewModel val currentMbti = model.mbti + val sheetBackgroundColor = if (isDarkMode) { + appColors.secondaryBackground + } else { + Color(0xFFFFFFFF) + } + + val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + + // 确保弹窗展开 + LaunchedEffect(Unit) { + sheetState.expand() + } + + // 监听状态变化,确保弹窗始终展开(防止拖拽关闭和滑动) + LaunchedEffect(sheetState.currentValue, sheetState.targetValue, sheetState.isVisible) { + // 如果弹窗被拖拽关闭或位置发生变化,立即重新展开 + if (!sheetState.isVisible || sheetState.targetValue != androidx.compose.material3.SheetValue.Expanded) { + kotlinx.coroutines.delay(10) // 短暂延迟确保状态更新 + sheetState.expand() + } + } - Column( - modifier = Modifier - .fillMaxSize() - .background(appColors.profileBackground) + val statusBarPadding = WindowInsets.systemBars.asPaddingValues() + val configuration = LocalConfiguration.current + val screenHeight = configuration.screenHeightDp.dp + val offsetY = screenHeight * 0.07f - statusBarPadding.calculateTopPadding() + + ModalBottomSheet( + onDismissRequest = onClose, + sheetState = sheetState, + containerColor = sheetBackgroundColor, + dragHandle = null ) { - // 头部 Box( modifier = Modifier .fillMaxWidth() - .padding(vertical = 16.dp) - ) { - NoticeScreenHeader( - title = stringResource(R.string.choose_mbti), - moreIcon = false - ) - } - - // 列表 - LazyColumn( - modifier = Modifier.fillMaxSize(), - contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 16.dp, vertical = 8.dp) - ) { - items(MBTI_TYPES) { mbti -> - MBTIItem( - mbti = mbti, - isSelected = mbti == currentMbti, - onClick = { - model.mbti = mbti - // 立即保存到本地存储,确保选择后立即生效 - AppState.UserId?.let { uid -> - com.aiosman.ravenow.AppStore.setUserMbti(uid, mbti) - } - navController.navigateUp() - } + .fillMaxHeight(0.95f) + .offset(y = offsetY) + .padding( + start = 16.dp, + end = 16.dp, + bottom = 8.dp ) - Spacer(modifier = Modifier.height(8.dp)) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + ) { + // 头部 - 使用 Box 实现绝对居中布局 + Box( + modifier = Modifier + .fillMaxWidth() + .height(48.dp), + contentAlignment = Alignment.Center + ) { + val cancelButtonGradientColors = if (isDarkMode) { + listOf( + Color(0xFF3A3A3C), + Color(0xFF2C2C2E) + ) + } else { + listOf( + Color(0xFFFFFFFF), + Color(0xFFF8F8F8) + ) + } + val cancelButtonContentColor = if (isDarkMode) Color(0xFFFFFFFF) else Color(0xFF404040) + + // 左上角返回按钮 + Row( + modifier = Modifier + .align(Alignment.CenterStart) + .height(36.dp) + .clip(RoundedCornerShape(18.dp)) + .background( + brush = Brush.linearGradient( + colors = cancelButtonGradientColors + ) + ) + .noRippleClickable { onClose() } + .padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + // 左箭头图标 + Image( + painter = painterResource(id = R.drawable.rider_pro_back_icon), + contentDescription = null, + modifier = Modifier.size(17.dp), + colorFilter = ColorFilter.tint(cancelButtonContentColor) + ) + + // "取消" 文字 + Text( + text = "取消", + fontSize = 17.sp, + fontWeight = FontWeight.Medium, + color = cancelButtonContentColor, + textAlign = androidx.compose.ui.text.style.TextAlign.Center + ) + } + + // 中间标题 - 绝对居中 + Text( + text = stringResource(R.string.choose_mbti), + color = appColors.text, + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + textAlign = androidx.compose.ui.text.style.TextAlign.Center + ) + } + + Spacer(Modifier.height(12.dp)) + + // 创建 NestedScrollConnection 来阻止滚动事件向上传播到 ModalBottomSheet + val nestedScrollConnection = remember { + object : NestedScrollConnection { + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + // 不消费任何事件,让 LazyVerticalGrid 先处理 + return Offset.Zero + } + + override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset { + // 消费 LazyVerticalGrid 处理后的剩余滚动事件,防止传递到 ModalBottomSheet + return available + } + + override suspend fun onPreFling(available: Velocity): Velocity { + // 不消费惯性滚动,让 LazyVerticalGrid 先处理 + return Velocity.Zero + } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + // 消费 LazyVerticalGrid 处理后的剩余惯性滚动,防止传递到 ModalBottomSheet + return available + } + } + } + + // 网格列表 - 2列 + LazyVerticalGrid( + columns = GridCells.Fixed(2), + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .nestedScroll(nestedScrollConnection), + contentPadding = PaddingValues( + start = 8.dp, + top = 8.dp, + end = 8.dp, + bottom = 8.dp + ), + horizontalArrangement = Arrangement.spacedBy(10.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + itemsIndexed(MBTI_TYPES) { index, mbti -> + MbtiItem( + mbti = mbti, + isSelected = mbti == currentMbti, + onClick = { + // 保存MBTI类型 + model.mbti = mbti + onClose() + } + ) + } + } } } } } +// 保留原有的 MbtiSelectScreen 用于导航路由(如果需要) +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun MBTIItem( +fun MbtiSelectScreen() { + val navController = LocalNavController.current + MbtiSelectBottomSheet( + onClose = { + navController.navigateUp() + } + ) +} + +@Composable +fun MbtiItem( mbti: String, isSelected: Boolean, onClick: () -> Unit ) { val appColors = LocalAppTheme.current + val isDarkMode = AppState.darkMode - Box( + // 卡片背景色 + val cardBackgroundColor = if (isDarkMode) { + Color(0xFF2A2A2A) // 比 secondaryBackground (0xFF1C1C1C) 更亮的灰色 + } else { + Color(0xFFFAF9FB) + } + + Column( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .background(if (isSelected) appColors.main.copy(alpha = 0.1f) else Color.White) + .aspectRatio(1.1f) + .shadow( + elevation = if (isDarkMode) 8.dp else 2.dp, + shape = RoundedCornerShape(21.dp), + spotColor = if (isDarkMode) Color.Black.copy(alpha = 0.5f) else Color.Black.copy(alpha = 0.1f) + ) + .clip(RoundedCornerShape(21.dp)) + .background(cardBackgroundColor) .clickable( indication = null, interactionSource = remember { MutableInteractionSource() } ) { onClick() } - .padding(16.dp) + .padding(horizontal = 24.dp, vertical = 12.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center ) { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically + // MBTI图标 - 使用占位图片 + Box( + modifier = Modifier.size(100.dp), + contentAlignment = Alignment.Center ) { - Text( - text = mbti, - fontSize = 17.sp, - fontWeight = FontWeight.Normal, - color = if (isSelected) appColors.main else appColors.text, - modifier = Modifier.weight(1f) + Image( + painter = painterResource(id = getMbtiImageResId(mbti, isDarkMode)), + contentDescription = mbti, + modifier = Modifier.size(100.dp) ) - - if (isSelected) { - Icon( - imageVector = Icons.Default.Check, - contentDescription = "Selected", - modifier = Modifier.size(20.dp), - tint = appColors.main - ) - } } + + // MBTI名称 - 使用负间距让文本向上移动,与图标更靠近 + Text( + text = mbti, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = appColors.text, + textAlign = TextAlign.Center, + modifier = Modifier.offset(y = (-20).dp) + ) } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSheetManager.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSheetManager.kt new file mode 100644 index 0000000..42c9cbc --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/MbtiSheetManager.kt @@ -0,0 +1,19 @@ +package com.aiosman.ravenow.ui.account + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +object MbtiSheetManager { + private val _visible = MutableStateFlow(false) + val visible: StateFlow = _visible.asStateFlow() + + fun open() { + _visible.value = true + } + + fun close() { + _visible.value = false + } +} + diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt index 10e5e97..17290b7 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/ZodiacSelectScreen.kt @@ -293,10 +293,6 @@ fun ZodiacSelectBottomSheet( onClick = { // 保存当前语言的星座文本 model.zodiac = zodiacText - // 立即保存到本地存储,确保选择后立即生效 - AppState.UserId?.let { uid -> - com.aiosman.ravenow.AppStore.setUserZodiac(uid, zodiacText) - } onClose() } ) diff --git a/app/src/main/java/com/aiosman/ravenow/ui/account/edit2.kt b/app/src/main/java/com/aiosman/ravenow/ui/account/edit2.kt index b6d600e..913725d 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/account/edit2.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/account/edit2.kt @@ -77,6 +77,8 @@ import java.io.File import androidx.activity.compose.BackHandler import com.aiosman.ravenow.ui.account.ZodiacBottomSheetHost import com.aiosman.ravenow.ui.account.ZodiacSheetManager +import com.aiosman.ravenow.ui.account.MbtiBottomSheetHost +import com.aiosman.ravenow.ui.account.MbtiSheetManager /** * 编辑用户资料界面 @@ -194,6 +196,8 @@ fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,) ) { // 挂载星座选择弹窗 ZodiacBottomSheetHost() + // 挂载MBTI选择弹窗 + MbtiBottomSheetHost() Box( modifier = Modifier @@ -425,9 +429,7 @@ fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,) iconResDark = null, // TODO: 添加MBTI暗色模式图标 iconResLight = null, // TODO: 添加MBTI亮色模式图标 onClick = { - debouncedNavigation { - navController.navigate(NavigationRoute.MbtiSelect.route) - } + MbtiSheetManager.open() } ) diff --git a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt index 0eb4c4d..253d650 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentModal.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api @@ -31,6 +32,7 @@ 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.platform.LocalDensity import androidx.compose.ui.platform.LocalSoftwareKeyboardController @@ -79,8 +81,9 @@ class CommentModalViewModel( fun CommentModalContent( postId: Int? = null, commentCount: Int = 0, - onCommentAdded: () -> Unit = {}, - onDismiss: () -> Unit = {} + onDismiss: () -> Unit = {}, + showTitle: Boolean = true, + onCommentAdded: () -> Unit = {} ) { val model = viewModel( key = "CommentModalViewModel_$postId", @@ -161,28 +164,42 @@ fun CommentModalContent( modifier = Modifier .fillMaxSize() ) { + // 拖动手柄 Box( modifier = Modifier .fillMaxWidth() - .padding(start = 16.dp, bottom = 16.dp, end = 16.dp) - + .padding(top = 8.dp, bottom = 12.dp), + contentAlignment = Alignment.Center ) { - Text( - stringResource(R.string.comment), - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = AppColors.text, - modifier = Modifier.align(Alignment.Center) + Box( + modifier = Modifier + .width(40.dp) + .height(4.dp) + .clip(RoundedCornerShape(50)) + .background(AppColors.divider) ) } - HorizontalDivider( - color = AppColors.divider - ) + if (showTitle) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, bottom = 16.dp, end = 16.dp) + + ) { + Text( + stringResource(R.string.comment), + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = AppColors.text, + modifier = Modifier.align(Alignment.Center) + ) + } + } Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 24.dp, vertical = 16.dp), + .padding(horizontal = 20.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { diff --git a/app/src/main/java/com/aiosman/ravenow/ui/favourite/FavouriteListPage.kt b/app/src/main/java/com/aiosman/ravenow/ui/favourite/FavouriteListPage.kt index 2662bfc..7292835 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/favourite/FavouriteListPage.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/favourite/FavouriteListPage.kt @@ -17,15 +17,19 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect 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.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -155,7 +159,10 @@ fun FavouriteListPage() { .clip(RoundedCornerShape(8.dp)), context = context ) - if (momentItem.images.size > 1) { + + val isVideoMoment = momentItem.images.isEmpty() && !momentItem.videos.isNullOrEmpty() + + if (momentItem.images.size > 1 || (momentItem.videos?.size ?: 0) > 1) { Box( modifier = Modifier .padding(top = 8.dp, end = 8.dp) @@ -168,6 +175,31 @@ fun FavouriteListPage() { ) } } + + if (isVideoMoment) { + Box( + modifier = Modifier + .padding(top = 8.dp, end = 8.dp) + .align(Alignment.TopEnd) + ) { + Box( + modifier = Modifier + .size(24.dp) + .background( + color = Color.Black.copy(alpha = 0.4f), + shape = RoundedCornerShape(12.dp) + ), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Default.PlayArrow, + contentDescription = "", + tint = Color.White, + modifier = Modifier.size(16.dp) + ) + } + } + } } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt index 3270941..c66ea00 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt @@ -2,10 +2,6 @@ package com.aiosman.ravenow.ui.index import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.FastOutLinearInEasing -import androidx.compose.animation.core.LinearOutSlowInEasing -import androidx.compose.animation.core.updateTransition -import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi @@ -140,6 +136,7 @@ fun IndexScreen() { ModalNavigationDrawer( drawerState = drawerState, gesturesEnabled = drawerState.isOpen, + scrimColor = Color.Black.copy(alpha = 0.6f), drawerContent = { CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { SideMenuContent( @@ -525,8 +522,6 @@ fun SideMenuContent( } else { Color(0xFFFAF9FB) // 亮色模式:浅灰色 } - // 遮罩颜色 黑色透明度0.6 - val overlayColor = Color.Black.copy(alpha = 0.6f) // 卡片背景色 - 根据暗色模式适配 val cardBackgroundColor = if (darkModeEnabled) { appColors.background // 暗色模式:深色背景 @@ -546,24 +541,6 @@ fun SideMenuContent( modifier = Modifier .fillMaxSize() ) { - // 左侧半透明遮罩(平滑淡入淡出) - val overlayTransition = updateTransition(targetState = isDrawerOpen, label = "overlay") - val overlayAlpha by overlayTransition.animateFloat( - transitionSpec = { - if (targetState) { - tween(durationMillis = 400, easing = LinearOutSlowInEasing) - } else { - tween(durationMillis = 300, easing = FastOutLinearInEasing) - } - }, - label = "overlayAlpha" - ) { open -> if (open) 0.6f else 0f } - Box( - modifier = Modifier - .fillMaxSize() - .background(Color.Black.copy(alpha = overlayAlpha)) - ) - // 右侧菜单面板 Box( modifier = Modifier diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt index 5225b01..310fd82 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/recommend/VideoRecommendationItem.kt @@ -33,8 +33,10 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner @@ -97,6 +99,9 @@ fun VideoRecommendationItem( skipPartiallyExpanded = true ) var pauseIconVisibleState by remember { mutableStateOf(false) } + // 防抖:记录上次双击时间,防止快速重复双击 + val lastDoubleTapTime = remember { mutableStateOf(0L) } + val doubleTapDebounceTime = 500L // 500ms 防抖时间 val exoPlayer = remember(videoUrl) { ExoPlayer.Builder(context) @@ -167,18 +172,32 @@ fun VideoRecommendationItem( }, modifier = Modifier .fillMaxSize() - .noRippleClickable { - pauseIconVisibleState = true - exoPlayer.pause() - scope.launch { - delay(100) - if (exoPlayer.isPlaying) { + .pointerInput(videoUrl, moment.liked) { + detectTapGestures( + onDoubleTap = { offset -> + // 双击点赞/取消点赞 + val currentTime = System.currentTimeMillis() + if (currentTime - lastDoubleTapTime.value > doubleTapDebounceTime) { + lastDoubleTapTime.value = currentTime + // 检查当前点赞状态,如果已点赞则取消点赞,如果未点赞则点赞 + onLikeClick?.invoke(moment) + } + }, + onTap = { + // 单击播放/暂停 + pauseIconVisibleState = true exoPlayer.pause() - } else { - pauseIconVisibleState = false - exoPlayer.play() + scope.launch { + delay(100) + if (exoPlayer.isPlaying) { + exoPlayer.pause() + } else { + pauseIconVisibleState = false + exoPlayer.play() + } + } } - } + ) } ) @@ -300,7 +319,9 @@ fun VideoRecommendationItem( ModalBottomSheet( onDismissRequest = { showCommentModal = false }, containerColor = Color.White, - sheetState = sheetState + sheetState = sheetState, + dragHandle = {}, + shape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp) ) { CommentModalContent(postId = moment.id) { // 评论添加后的回调 diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/composable/GalleryItem.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/composable/GalleryItem.kt index f67f21a..241ac89 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/composable/GalleryItem.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/composable/GalleryItem.kt @@ -18,6 +18,9 @@ import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -258,6 +261,45 @@ fun GalleryGrid( ) ) } + + if (momentItem.images.size > 1 || (momentItem.videos?.size ?: 0) > 1) { + Box( + modifier = Modifier + .padding(top = 8.dp, end = 8.dp) + .align(Alignment.TopEnd) + ) { + Image( + modifier = Modifier.size(24.dp), + painter = painterResource(R.drawable.rider_pro_picture_more), + contentDescription = "", + ) + } + } + + if (isVideoMoment) { + Box( + modifier = Modifier + .padding(top = 8.dp, end = 8.dp) + .align(Alignment.TopEnd) + ) { + Box( + modifier = Modifier + .size(24.dp) + .background( + color = Color.Black.copy(alpha = 0.4f), + shape = RoundedCornerShape(12.dp) + ), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Default.PlayArrow, + contentDescription = "", + tint = Color.White, + modifier = Modifier.size(16.dp) + ) + } + } + } } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt index 39d0018..6b4c093 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/shorts/ShortViewCompose.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -56,6 +57,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver @@ -467,6 +469,9 @@ fun VideoPlayer( .clip(RectangleShape) ) { var playerView by remember { mutableStateOf(null) } + // 防抖:记录上次双击时间,防止快速重复双击 + val lastDoubleTapTime = remember { mutableStateOf(0L) } + val doubleTapDebounceTime = 500L // 500ms 防抖时间 // 使用 key 强制每个视频的 PlayerView 完全独立,避免布局状态残留 androidx.compose.runtime.key(videoUrl) { @@ -479,8 +484,24 @@ fun VideoPlayer( modifier = Modifier .fillMaxSize() .clip(RectangleShape) - .noRippleClickable { - handleVideoClick(pauseIconVisibleState, exoPlayer, scope) + .pointerInput(videoUrl, moment?.liked) { + detectTapGestures( + onDoubleTap = { offset -> + // 双击点赞/取消点赞 + val currentTime = System.currentTimeMillis() + if (currentTime - lastDoubleTapTime.value > doubleTapDebounceTime) { + lastDoubleTapTime.value = currentTime + moment?.let { + // 检查当前点赞状态,如果已点赞则取消点赞,如果未点赞则点赞 + onLikeClick?.invoke(it) + } + } + }, + onTap = { + // 单击播放/暂停 + handleVideoClick(pauseIconVisibleState, exoPlayer, scope) + } + ) } ) } @@ -660,7 +681,8 @@ fun VideoPlayer( }, containerColor = AppColors.background, sheetState = sheetState, - shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp) + dragHandle = {}, + shape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp) ) { Box( modifier = Modifier @@ -670,6 +692,7 @@ fun VideoPlayer( CommentModalContent( postId = moment.id, commentCount = moment.commentCount, + showTitle = false, onCommentAdded = { onCommentAdded?.invoke(moment) } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt b/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt index 74e148f..2ee9145 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt @@ -12,6 +12,8 @@ import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.gestures.detectTapGestures @@ -1159,14 +1161,26 @@ fun ImageViewerDialog( } } +@OptIn(ExperimentalFoundationApi::class) @Composable fun PostImageView( images: List, initialPage: Int? = 0 ) { val context = LocalContext.current + val scope = rememberCoroutineScope() var isImageViewerDialog by remember { mutableStateOf(false) } - var currentImageIndex by remember { mutableStateOf(initialPage ?: 0) } + val initialPageIndex = initialPage ?: 0 + val pagerState = rememberPagerState( + pageCount = { images.size }, + initialPage = initialPageIndex.coerceIn(0, maxOf(0, images.size - 1)) + ) + var currentImageIndex by remember { mutableStateOf(pagerState.currentPage) } + + // 同步 pagerState 的当前页面到 currentImageIndex + LaunchedEffect(pagerState.currentPage) { + currentImageIndex = pagerState.currentPage + } DisposableEffect(Unit) { onDispose { @@ -1187,23 +1201,31 @@ fun PostImageView( modifier = Modifier ) { if (images.isNotEmpty()) { - CustomAsyncImage( - context, - images[currentImageIndex].thumbnail, - contentDescription = "Image", - contentScale = ContentScale.Crop, + HorizontalPager( + state = pagerState, modifier = Modifier .weight(1f) .fillMaxWidth() - .pointerInput(Unit) { - detectTapGestures( - onTap = { - isImageViewerDialog = true - } - ) - } - .background(Color.Gray.copy(alpha = 0.1f)) - ) + ) { page -> + val image = images[page] + CustomAsyncImage( + context, + image.thumbnail, + contentDescription = "Image", + blurHash = image.blurHash, + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxSize() + .pointerInput(Unit) { + detectTapGestures( + onTap = { + isImageViewerDialog = true + } + ) + } + .background(Color.Gray.copy(alpha = 0.1f)) + ) + } } // 图片导航控件 @@ -1212,56 +1234,26 @@ fun PostImageView( modifier = Modifier .padding(8.dp) .fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, + horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { - // Previous button - Text( - text = "Previous", - modifier = Modifier - .padding(8.dp) - .noRippleClickable { - if (currentImageIndex > 0) { - currentImageIndex-- - } - }, - color = if (currentImageIndex > 0) Color.Blue else Color.Gray - ) - // Indicators - Row( - horizontalArrangement = Arrangement.Center - ) { - images.forEachIndexed { index, _ -> - Box( - modifier = Modifier - .size(4.dp) - .clip(CircleShape) - .background( - if (currentImageIndex == index) Color.Red else Color.Gray.copy( - alpha = 0.5f - ) + images.forEachIndexed { index, _ -> + Box( + modifier = Modifier + .size(4.dp) + .clip(CircleShape) + .background( + if (pagerState.currentPage == index) Color.Red else Color.Gray.copy( + alpha = 0.5f ) - .padding(4.dp) - ) - if (index < images.size - 1) { - Spacer(modifier = Modifier.width(8.dp)) - } + ) + .padding(4.dp) + ) + if (index < images.size - 1) { + Spacer(modifier = Modifier.width(8.dp)) } } - - // Next button - Text( - text = "Next", - modifier = Modifier - .padding(8.dp) - .noRippleClickable { - if (currentImageIndex < images.size - 1) { - currentImageIndex++ - } - }, - color = if (currentImageIndex < images.size - 1) Color.Blue else Color.Gray - ) } } } diff --git a/app/src/main/res/mipmap-hdpi/anmbti_entj.png b/app/src/main/res/mipmap-hdpi/anmbti_entj.png new file mode 100644 index 0000000..8e6b87d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/anmbti_entj.png differ diff --git a/app/src/main/res/mipmap-hdpi/anmbti_entp.png b/app/src/main/res/mipmap-hdpi/anmbti_entp.png new file mode 100644 index 0000000..e3996a4 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/anmbti_entp.png differ diff --git a/app/src/main/res/mipmap-hdpi/anmbti_estp.png b/app/src/main/res/mipmap-hdpi/anmbti_estp.png new file mode 100644 index 0000000..f73f67a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/anmbti_estp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_enfj.png b/app/src/main/res/mipmap-hdpi/mbti_enfj.png new file mode 100644 index 0000000..0f3d08b Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_enfj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_enfp.png b/app/src/main/res/mipmap-hdpi/mbti_enfp.png new file mode 100644 index 0000000..1ebc9f2 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_enfp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_entj.png b/app/src/main/res/mipmap-hdpi/mbti_entj.png new file mode 100644 index 0000000..c3958c7 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_entj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_entp.png b/app/src/main/res/mipmap-hdpi/mbti_entp.png new file mode 100644 index 0000000..e61a2c6 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_entp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_esfj.png b/app/src/main/res/mipmap-hdpi/mbti_esfj.png new file mode 100644 index 0000000..d5c91e4 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_esfj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_esfp.png b/app/src/main/res/mipmap-hdpi/mbti_esfp.png new file mode 100644 index 0000000..b25ad7a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_esfp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_estj.png b/app/src/main/res/mipmap-hdpi/mbti_estj.png new file mode 100644 index 0000000..4858ccb Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_estj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_estp.png b/app/src/main/res/mipmap-hdpi/mbti_estp.png new file mode 100644 index 0000000..5763678 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_estp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_infj.png b/app/src/main/res/mipmap-hdpi/mbti_infj.png new file mode 100644 index 0000000..29116f2 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_infj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_infp.png b/app/src/main/res/mipmap-hdpi/mbti_infp.png new file mode 100644 index 0000000..c604f7a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_infp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_intj.png b/app/src/main/res/mipmap-hdpi/mbti_intj.png new file mode 100644 index 0000000..a101a79 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_intj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_intp.png b/app/src/main/res/mipmap-hdpi/mbti_intp.png new file mode 100644 index 0000000..8bff41a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_intp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_isfj.png b/app/src/main/res/mipmap-hdpi/mbti_isfj.png new file mode 100644 index 0000000..252cffd Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_isfj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_isfp.png b/app/src/main/res/mipmap-hdpi/mbti_isfp.png new file mode 100644 index 0000000..baa1c8b Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_isfp.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_istj.png b/app/src/main/res/mipmap-hdpi/mbti_istj.png new file mode 100644 index 0000000..fbbbba1 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_istj.png differ diff --git a/app/src/main/res/mipmap-hdpi/mbti_istp.png b/app/src/main/res/mipmap-hdpi/mbti_istp.png new file mode 100644 index 0000000..1436647 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/mbti_istp.png differ diff --git a/app/src/main/res/mipmap-mdpi/anmbti_entj.png b/app/src/main/res/mipmap-mdpi/anmbti_entj.png new file mode 100644 index 0000000..e225009 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/anmbti_entj.png differ diff --git a/app/src/main/res/mipmap-mdpi/anmbti_entp.png b/app/src/main/res/mipmap-mdpi/anmbti_entp.png new file mode 100644 index 0000000..9ad9d56 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/anmbti_entp.png differ diff --git a/app/src/main/res/mipmap-mdpi/anmbti_estp.png b/app/src/main/res/mipmap-mdpi/anmbti_estp.png new file mode 100644 index 0000000..61a8ef6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/anmbti_estp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_enfj.png b/app/src/main/res/mipmap-mdpi/mbti_enfj.png new file mode 100644 index 0000000..6d6f3ec Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_enfj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_enfp.png b/app/src/main/res/mipmap-mdpi/mbti_enfp.png new file mode 100644 index 0000000..7b39d97 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_enfp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_entj.png b/app/src/main/res/mipmap-mdpi/mbti_entj.png new file mode 100644 index 0000000..70b353a Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_entj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_entp.png b/app/src/main/res/mipmap-mdpi/mbti_entp.png new file mode 100644 index 0000000..d17f5bc Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_entp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_esfj.png b/app/src/main/res/mipmap-mdpi/mbti_esfj.png new file mode 100644 index 0000000..b4c9457 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_esfj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_esfp.png b/app/src/main/res/mipmap-mdpi/mbti_esfp.png new file mode 100644 index 0000000..fff768e Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_esfp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_estj.png b/app/src/main/res/mipmap-mdpi/mbti_estj.png new file mode 100644 index 0000000..e1dd7f9 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_estj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_estp.png b/app/src/main/res/mipmap-mdpi/mbti_estp.png new file mode 100644 index 0000000..8fd796c Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_estp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_infj.png b/app/src/main/res/mipmap-mdpi/mbti_infj.png new file mode 100644 index 0000000..b21cf3d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_infj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_infp.png b/app/src/main/res/mipmap-mdpi/mbti_infp.png new file mode 100644 index 0000000..e220a91 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_infp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_intj.png b/app/src/main/res/mipmap-mdpi/mbti_intj.png new file mode 100644 index 0000000..e905fcf Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_intj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_intp.png b/app/src/main/res/mipmap-mdpi/mbti_intp.png new file mode 100644 index 0000000..7f6ee18 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_intp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_isfj.png b/app/src/main/res/mipmap-mdpi/mbti_isfj.png new file mode 100644 index 0000000..0514e9d Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_isfj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_isfp.png b/app/src/main/res/mipmap-mdpi/mbti_isfp.png new file mode 100644 index 0000000..29574f6 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_isfp.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_istj.png b/app/src/main/res/mipmap-mdpi/mbti_istj.png new file mode 100644 index 0000000..923cca3 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_istj.png differ diff --git a/app/src/main/res/mipmap-mdpi/mbti_istp.png b/app/src/main/res/mipmap-mdpi/mbti_istp.png new file mode 100644 index 0000000..da0bf17 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/mbti_istp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/anmbti_entj.png b/app/src/main/res/mipmap-xhdpi/anmbti_entj.png new file mode 100644 index 0000000..446676d Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/anmbti_entj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/anmbti_entp.png b/app/src/main/res/mipmap-xhdpi/anmbti_entp.png new file mode 100644 index 0000000..5356804 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/anmbti_entp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/anmbti_estp.png b/app/src/main/res/mipmap-xhdpi/anmbti_estp.png new file mode 100644 index 0000000..c86af33 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/anmbti_estp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_enfj.png b/app/src/main/res/mipmap-xhdpi/mbti_enfj.png new file mode 100644 index 0000000..3b3f622 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_enfj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_enfp.png b/app/src/main/res/mipmap-xhdpi/mbti_enfp.png new file mode 100644 index 0000000..6adb9ed Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_enfp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_entj.png b/app/src/main/res/mipmap-xhdpi/mbti_entj.png new file mode 100644 index 0000000..5864f11 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_entj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_entp.png b/app/src/main/res/mipmap-xhdpi/mbti_entp.png new file mode 100644 index 0000000..4823998 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_entp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_esfj.png b/app/src/main/res/mipmap-xhdpi/mbti_esfj.png new file mode 100644 index 0000000..64c1eb1 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_esfj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_esfp.png b/app/src/main/res/mipmap-xhdpi/mbti_esfp.png new file mode 100644 index 0000000..d0cfe57 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_esfp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_estj.png b/app/src/main/res/mipmap-xhdpi/mbti_estj.png new file mode 100644 index 0000000..caf47be Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_estj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_estp.png b/app/src/main/res/mipmap-xhdpi/mbti_estp.png new file mode 100644 index 0000000..f03b11f Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_estp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_infj.png b/app/src/main/res/mipmap-xhdpi/mbti_infj.png new file mode 100644 index 0000000..ba3c087 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_infj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_infp.png b/app/src/main/res/mipmap-xhdpi/mbti_infp.png new file mode 100644 index 0000000..612b6d1 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_infp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_intj.png b/app/src/main/res/mipmap-xhdpi/mbti_intj.png new file mode 100644 index 0000000..3baec76 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_intj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_intp.png b/app/src/main/res/mipmap-xhdpi/mbti_intp.png new file mode 100644 index 0000000..7f51f4d Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_intp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_isfj.png b/app/src/main/res/mipmap-xhdpi/mbti_isfj.png new file mode 100644 index 0000000..f49bcb9 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_isfj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_isfp.png b/app/src/main/res/mipmap-xhdpi/mbti_isfp.png new file mode 100644 index 0000000..7bb98d0 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_isfp.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_istj.png b/app/src/main/res/mipmap-xhdpi/mbti_istj.png new file mode 100644 index 0000000..3c46e8b Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_istj.png differ diff --git a/app/src/main/res/mipmap-xhdpi/mbti_istp.png b/app/src/main/res/mipmap-xhdpi/mbti_istp.png new file mode 100644 index 0000000..fb7e5f8 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/mbti_istp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/anmbti_entj.png b/app/src/main/res/mipmap-xxhdpi/anmbti_entj.png new file mode 100644 index 0000000..88236e5 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/anmbti_entj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/anmbti_entp.png b/app/src/main/res/mipmap-xxhdpi/anmbti_entp.png new file mode 100644 index 0000000..6172101 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/anmbti_entp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/anmbti_estp.png b/app/src/main/res/mipmap-xxhdpi/anmbti_estp.png new file mode 100644 index 0000000..cbbef79 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/anmbti_estp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_enfj.png b/app/src/main/res/mipmap-xxhdpi/mbti_enfj.png new file mode 100644 index 0000000..e97036b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_enfj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_enfp.png b/app/src/main/res/mipmap-xxhdpi/mbti_enfp.png new file mode 100644 index 0000000..9c26714 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_enfp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_entj.png b/app/src/main/res/mipmap-xxhdpi/mbti_entj.png new file mode 100644 index 0000000..80f5088 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_entj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_entp.png b/app/src/main/res/mipmap-xxhdpi/mbti_entp.png new file mode 100644 index 0000000..2dadd2f Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_entp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_esfj.png b/app/src/main/res/mipmap-xxhdpi/mbti_esfj.png new file mode 100644 index 0000000..cf034ca Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_esfj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_esfp.png b/app/src/main/res/mipmap-xxhdpi/mbti_esfp.png new file mode 100644 index 0000000..5f817e9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_esfp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_estj.png b/app/src/main/res/mipmap-xxhdpi/mbti_estj.png new file mode 100644 index 0000000..196dda5 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_estj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_estp.png b/app/src/main/res/mipmap-xxhdpi/mbti_estp.png new file mode 100644 index 0000000..ef0bb38 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_estp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_infj.png b/app/src/main/res/mipmap-xxhdpi/mbti_infj.png new file mode 100644 index 0000000..e96f49b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_infj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_infp.png b/app/src/main/res/mipmap-xxhdpi/mbti_infp.png new file mode 100644 index 0000000..91d7a5a Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_infp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_intj.png b/app/src/main/res/mipmap-xxhdpi/mbti_intj.png new file mode 100644 index 0000000..c0c5eca Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_intj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_intp.png b/app/src/main/res/mipmap-xxhdpi/mbti_intp.png new file mode 100644 index 0000000..9371db9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_intp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_isfj.png b/app/src/main/res/mipmap-xxhdpi/mbti_isfj.png new file mode 100644 index 0000000..4c688f3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_isfj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_isfp.png b/app/src/main/res/mipmap-xxhdpi/mbti_isfp.png new file mode 100644 index 0000000..275876f Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_isfp.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_istj.png b/app/src/main/res/mipmap-xxhdpi/mbti_istj.png new file mode 100644 index 0000000..891a455 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_istj.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/mbti_istp.png b/app/src/main/res/mipmap-xxhdpi/mbti_istp.png new file mode 100644 index 0000000..d6b95eb Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/mbti_istp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/anmbti_entj.png b/app/src/main/res/mipmap-xxxhdpi/anmbti_entj.png new file mode 100644 index 0000000..155d68e Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/anmbti_entj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/anmbti_entp.png b/app/src/main/res/mipmap-xxxhdpi/anmbti_entp.png new file mode 100644 index 0000000..a98732b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/anmbti_entp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/anmbti_estp.png b/app/src/main/res/mipmap-xxxhdpi/anmbti_estp.png new file mode 100644 index 0000000..786286f Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/anmbti_estp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_enfj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_enfj.png new file mode 100644 index 0000000..101080b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_enfj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_enfp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_enfp.png new file mode 100644 index 0000000..9261433 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_enfp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_entj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_entj.png new file mode 100644 index 0000000..72c7c53 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_entj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_entp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_entp.png new file mode 100644 index 0000000..f1163aa Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_entp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_esfj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_esfj.png new file mode 100644 index 0000000..b2a624b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_esfj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_esfp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_esfp.png new file mode 100644 index 0000000..b5b1243 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_esfp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_estj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_estj.png new file mode 100644 index 0000000..284e3b3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_estj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_estp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_estp.png new file mode 100644 index 0000000..3482aab Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_estp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_infj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_infj.png new file mode 100644 index 0000000..a16408c Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_infj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_infp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_infp.png new file mode 100644 index 0000000..107404a Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_infp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_intj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_intj.png new file mode 100644 index 0000000..144d3af Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_intj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_intp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_intp.png new file mode 100644 index 0000000..3383a1d Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_intp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_isfj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_isfj.png new file mode 100644 index 0000000..057f440 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_isfj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_isfp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_isfp.png new file mode 100644 index 0000000..f77f5b3 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_isfp.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_istj.png b/app/src/main/res/mipmap-xxxhdpi/mbti_istj.png new file mode 100644 index 0000000..c2cb0a5 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_istj.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/mbti_istp.png b/app/src/main/res/mipmap-xxxhdpi/mbti_istp.png new file mode 100644 index 0000000..ae6ae48 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/mbti_istp.png differ