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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions app/src/presentation/navigation/AppNavContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ import com.github.yumeyucca.yumebox.presentation.component.Navigator
import com.github.yumeyucca.yumebox.screen.settings.MoeWallpaperCropScreen
import kotlinx.coroutines.launch

internal fun <C : Any, T : Any> yumeStackAnimation(): StackAnimation<C, T> =
stackAnimation(fade(tween(300)) + slide(tween(400)) + scale(tween(500)))

@OptIn(ExperimentalDecomposeApi::class)
private fun <T : Any> yumeAnimation(
backHandler: BackHandler,
Expand All @@ -48,8 +51,7 @@ private fun <T : Any> yumeAnimation(
predictiveBackAnimation(
backHandler = backHandler,
onBack = onBack,
fallbackAnimation =
stackAnimation(fade(tween(300)) + slide(tween(400)) + scale(tween(500))),
fallbackAnimation = yumeStackAnimation(),
selector = { event, _, _ -> androidPredictiveBackAnimatableV1(event) },
)

Expand Down Expand Up @@ -154,7 +156,7 @@ fun AppNavContainer(component: AppNavigationComponent) {
if (predictiveBackEnabled) {
yumeAnimation(componentContext.backHandler, commitBack)
} else {
stackAnimation(fade(tween(300)) + slide(tween(400)) + scale(tween(500)))
yumeStackAnimation()
}
}
Children(
Expand Down
6 changes: 1 addition & 5 deletions app/src/presentation/navigation/SecondaryDetailHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

package com.github.yumeyucca.yumebox.presentation.navigation

import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
Expand Down Expand Up @@ -76,10 +75,7 @@ internal fun rememberSecondaryDetailStack(navigator: Navigator): SecondaryDetail
@Composable
internal fun SecondaryDetailHost(stack: SecondaryDetailStack) {
val childStack by stack.value.subscribeAsState()
val animation: StackAnimation<Any, DetailRouteChild> =
remember {
stackAnimation(fade(tween(300)) + slide(tween(400)) + scale(tween(500)))
}
val animation: StackAnimation<Any, DetailRouteChild> = remember { yumeStackAnimation() }
Children(
stack = childStack,
modifier = Modifier.fillMaxSize(),
Expand Down
12 changes: 6 additions & 6 deletions app/src/screen/profiles/ProfileAddFormState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ package com.github.yumeyucca.yumebox.screen.profiles

import androidx.compose.runtime.*
import androidx.compose.ui.text.input.TextFieldValue
import com.github.yumeyucca.yumebox.presentation.util.PROFILE_IMPORT_TYPE_FILE
import com.github.yumeyucca.yumebox.presentation.util.PROFILE_IMPORT_TYPE_URL
import com.github.yumeyucca.yumebox.presentation.util.ProfileImportType

@Stable
internal class ProfileAddFormState {
val typeIndex = mutableIntStateOf(0)
val importType = mutableStateOf(ProfileImportType.Url)
val name = mutableStateOf(TextFieldValue())
val url = mutableStateOf(TextFieldValue())
val filePath = mutableStateOf("")
Expand All @@ -50,12 +49,13 @@ internal class ProfileAddFormState {
}

fun clearTypeInput() {
when (typeIndex.intValue) {
PROFILE_IMPORT_TYPE_URL -> url.value = textValueAtEnd("")
PROFILE_IMPORT_TYPE_FILE -> {
when (importType.value) {
ProfileImportType.Url -> url.value = textValueAtEnd("")
ProfileImportType.LocalFile -> {
filePath.value = ""
fileName.value = textValueAtEnd("")
}
ProfileImportType.Qr -> Unit
}
error.value = ""
}
Expand Down
30 changes: 15 additions & 15 deletions app/src/screen/profiles/ProfileAddSheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ internal fun AddProfileSheet(
val context = LocalContext.current
val keyboardController = LocalSoftwareKeyboardController.current
val form = rememberProfileAddFormState()
var selectedTypeIndex by form.typeIndex
var selectedImportType by form.importType
var nameTextFieldValue by form.name
var urlTextFieldValue by form.url
var filePath by form.filePath
Expand Down Expand Up @@ -111,21 +111,21 @@ internal fun AddProfileSheet(
hasCameraPermission = isGranted
if (!isGranted) {
context.toast(YumeTxt.ProfilesPage.QrScanner.NeedCamera, Toast.LENGTH_LONG)
selectedTypeIndex = PROFILE_IMPORT_TYPE_URL
selectedImportType = ProfileImportType.Url
}
}

LaunchedEffect(selectedTypeIndex) {
if (selectedTypeIndex == PROFILE_IMPORT_TYPE_QR && !hasCameraPermission) {
LaunchedEffect(selectedImportType) {
if (selectedImportType == ProfileImportType.Qr && !hasCameraPermission) {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}

val showCameraPreview by
remember(show.value, selectedTypeIndex, isDownloading, hasCameraPermission) {
remember(show.value, selectedImportType, isDownloading, hasCameraPermission) {
derivedStateOf {
show.value &&
selectedTypeIndex == PROFILE_IMPORT_TYPE_QR &&
selectedImportType == ProfileImportType.Qr &&
!isDownloading &&
hasCameraPermission
}
Expand All @@ -137,18 +137,18 @@ internal fun AddProfileSheet(
if (profileToEdit != null) {
applyNameText(profileToEdit.name)
if (profileToEdit.type == Profile.Type.Url) {
selectedTypeIndex = PROFILE_IMPORT_TYPE_URL
selectedImportType = ProfileImportType.Url
applyUrlText(profileToEdit.source)
} else {
selectedTypeIndex = importTypeIndexFor(profileToEdit.type)
selectedImportType = ProfileImportType.fromProfile(profileToEdit.type)
filePath = profileToEdit.source
applyFileNameText(sourceFileName(profileToEdit.source))
}
} else if (!importUrl.isNullOrBlank()) {
selectedTypeIndex = PROFILE_IMPORT_TYPE_URL
selectedImportType = ProfileImportType.Url
applyUrlText(importUrl)
} else {
selectedTypeIndex = PROFILE_IMPORT_TYPE_URL
selectedImportType = ProfileImportType.Url
readClipboardSubscriptionUrl(context)?.let(applyUrlText)
}
}
Expand Down Expand Up @@ -207,7 +207,7 @@ internal fun AddProfileSheet(
onUnsupportedFile = { error = YumeTxt.ProfilesPage.Validation.YamlOnly },
onQrDecoded = { url ->
applyUrlText(url)
selectedTypeIndex = PROFILE_IMPORT_TYPE_URL
selectedImportType = ProfileImportType.Url
},
)

Expand All @@ -219,7 +219,7 @@ internal fun AddProfileSheet(
submit = {
val draft =
ProfileDraft(
typeIndex = selectedTypeIndex,
importType = selectedImportType,
name = nameTextFieldValue.text,
url = urlTextFieldValue.text,
filePath = filePath,
Expand All @@ -244,7 +244,7 @@ internal fun AddProfileSheet(
}
},
selectType = {
selectedTypeIndex = it
selectedImportType = it
clearCurrentTypeState()
},
changeName = { value ->
Expand All @@ -261,15 +261,15 @@ internal fun AddProfileSheet(
selectQrImage = launchers.selectQrImage,
qrScanned = { url ->
applyUrlText(url)
selectedTypeIndex = PROFILE_IMPORT_TYPE_URL
selectedImportType = ProfileImportType.Url
},
)
with(actions) {
ProfileAddSheetContent(
show = show.value,
isEditing = profileToEdit != null,
isDownloading = isDownloading,
selectedTypeIndex = selectedTypeIndex,
selectedImportType = selectedImportType,
nameValue = nameTextFieldValue,
urlValue = urlTextFieldValue,
fileNameValue = fileNameTextFieldValue,
Expand Down
50 changes: 27 additions & 23 deletions app/src/screen/profiles/ProfileAddSheetContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ import com.github.yumeyucca.yumebox.presentation.component.OemTextField
import com.github.yumeyucca.yumebox.presentation.icon.Yume
import com.github.yumeyucca.yumebox.presentation.icon.yume.PackageCheck
import com.github.yumeyucca.yumebox.presentation.theme.UiDp
import com.github.yumeyucca.yumebox.presentation.util.PROFILE_IMPORT_TYPE_QR
import com.github.yumeyucca.yumebox.presentation.util.PROFILE_IMPORT_TYPE_URL
import com.github.yumeyucca.yumebox.presentation.util.ProfileImportType
import tf.gal.yumebox.locale.YumeTxt
import top.yukonga.miuix.kmp.basic.*
import top.yukonga.miuix.kmp.preference.WindowSpinnerPreference
Expand Down Expand Up @@ -132,7 +131,7 @@ internal fun DownloadProgressContent(

@Composable
internal fun ProfileFormContent(
selectedTypeIndex: Int,
selectedImportType: ProfileImportType,
profileLocked: Boolean,
nameTextFieldValue: TextFieldValue,
urlTextFieldValue: TextFieldValue,
Expand All @@ -142,7 +141,7 @@ internal fun ProfileFormContent(
hasCameraPermission: Boolean,
showCameraPreview: Boolean,
onContainerMeasured: (IntSize) -> Unit,
onTypeSelected: (Int) -> Unit,
onTypeSelected: (ProfileImportType) -> Unit,
onNameChange: (TextFieldValue) -> Unit,
onUrlChange: (TextFieldValue) -> Unit,
onAgeSecretKeyChange: (TextFieldValue) -> Unit,
Expand All @@ -157,28 +156,29 @@ internal fun ProfileFormContent(
verticalArrangement = Arrangement.spacedBy(UiDp.dp16),
) {
ProfileTypeSelectorCard(
selectedTypeIndex = selectedTypeIndex,
selectedImportType = selectedImportType,
profileLocked = profileLocked,
onTypeSelected = onTypeSelected,
)

Crossfade(
targetState = selectedTypeIndex,
targetState = selectedImportType,
animationSpec = tween(200),
label = "ProfileTypeContent",
) { typeIndex ->
when (typeIndex) {
PROFILE_IMPORT_TYPE_QR ->
) { importType ->
when (importType) {
ProfileImportType.Qr ->
QrScannerContent(
hasCameraPermission = hasCameraPermission,
showCameraPreview = showCameraPreview,
onSelectQrImage = onSelectQrImage,
onQrScanned = onQrScanned,
)

else ->
ProfileImportType.Url,
ProfileImportType.LocalFile ->
ManualProfileContent(
typeIndex = typeIndex,
importType = importType,
profileLocked = profileLocked,
nameTextFieldValue = nameTextFieldValue,
urlTextFieldValue = urlTextFieldValue,
Expand All @@ -197,9 +197,9 @@ internal fun ProfileFormContent(

@Composable
private fun ProfileTypeSelectorCard(
selectedTypeIndex: Int,
selectedImportType: ProfileImportType,
profileLocked: Boolean,
onTypeSelected: (Int) -> Unit,
onTypeSelected: (ProfileImportType) -> Unit,
) {
AppCard(applyHorizontalPadding = false) {
Box(
Expand All @@ -215,14 +215,11 @@ private fun ProfileTypeSelectorCard(
) {
WindowSpinnerPreference(
title = YumeTxt.ProfilesPage.Type.Title,
items =
listOf(
DropdownItem(title = YumeTxt.ProfilesPage.Type.Subscription),
DropdownItem(title = YumeTxt.ProfilesPage.Type.LocalFile),
DropdownItem(title = YumeTxt.ProfilesPage.Type.QrScan),
),
selectedIndex = selectedTypeIndex,
onSelectedIndexChange = onTypeSelected,
items = ProfileImportType.entries.map { type -> DropdownItem(title = type.spinnerTitle()) },
selectedIndex = selectedImportType.ordinal,
onSelectedIndexChange = { index ->
onTypeSelected(ProfileImportType.fromSpinnerIndex(index))
},
)
}
}
Expand Down Expand Up @@ -268,7 +265,7 @@ private fun QrScannerContent(

@Composable
private fun ManualProfileContent(
typeIndex: Int,
importType: ProfileImportType,
profileLocked: Boolean,
nameTextFieldValue: TextFieldValue,
urlTextFieldValue: TextFieldValue,
Expand All @@ -292,7 +289,7 @@ private fun ManualProfileContent(
modifier = Modifier.fillMaxWidth(),
)

if (typeIndex == PROFILE_IMPORT_TYPE_URL) {
if (importType == ProfileImportType.Url) {
OemTextField(
value = urlTextFieldValue,
onValueChange = onUrlChange,
Expand Down Expand Up @@ -342,3 +339,10 @@ private fun ManualProfileContent(
}
}
}

private fun ProfileImportType.spinnerTitle(): String =
when (this) {
ProfileImportType.Url -> YumeTxt.ProfilesPage.Type.Subscription
ProfileImportType.LocalFile -> YumeTxt.ProfilesPage.Type.LocalFile
ProfileImportType.Qr -> YumeTxt.ProfilesPage.Type.QrScan
}
12 changes: 6 additions & 6 deletions app/src/screen/profiles/ProfileAddSheetLayout.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ import com.github.yumeyucca.yumebox.presentation.component.AppActionBottomSheet
import com.github.yumeyucca.yumebox.presentation.component.AppBottomSheetCloseAction
import com.github.yumeyucca.yumebox.presentation.component.AppBottomSheetConfirmAction
import com.github.yumeyucca.yumebox.presentation.theme.UiDp
import com.github.yumeyucca.yumebox.presentation.util.PROFILE_IMPORT_TYPE_QR
import com.github.yumeyucca.yumebox.presentation.util.ProfileImportType
import tf.gal.yumebox.locale.YumeTxt

internal class ProfileAddSheetActions(
val dismiss: () -> Unit,
val submit: () -> Unit,
val selectType: (Int) -> Unit,
val selectType: (ProfileImportType) -> Unit,
val changeName: (TextFieldValue) -> Unit,
val changeUrl: (TextFieldValue) -> Unit,
val changeAgeSecretKey: (TextFieldValue) -> Unit,
Expand All @@ -63,7 +63,7 @@ internal fun ProfileAddSheetContent(
show: Boolean,
isEditing: Boolean,
isDownloading: Boolean,
selectedTypeIndex: Int,
selectedImportType: ProfileImportType,
nameValue: TextFieldValue,
urlValue: TextFieldValue,
fileNameValue: TextFieldValue,
Expand All @@ -86,7 +86,7 @@ internal fun ProfileAddSheetContent(
// overlay-hosted action row can be re-rendered from a stale composable after the app returns
// from background, and only a state read there keeps it subscribed to updates.
val downloading by rememberUpdatedState(isDownloading)
val typeIndex by rememberUpdatedState(selectedTypeIndex)
val importType by rememberUpdatedState(selectedImportType)

AppActionBottomSheet(
show = show,
Expand All @@ -102,7 +102,7 @@ internal fun ProfileAddSheetContent(
}
},
endAction = {
if (!downloading && typeIndex != PROFILE_IMPORT_TYPE_QR) {
if (!downloading && importType != ProfileImportType.Qr) {
AppBottomSheetConfirmAction(
contentDescription = YumeTxt.Component.Button.Confirm,
onClick = actions.submit,
Expand Down Expand Up @@ -152,7 +152,7 @@ internal fun ProfileAddSheetContent(
)
} else {
ProfileFormContent(
selectedTypeIndex = selectedTypeIndex,
selectedImportType = selectedImportType,
profileLocked = isEditing,
nameTextFieldValue = nameValue,
urlTextFieldValue = urlValue,
Expand Down
Loading
Loading