implement Material You

This commit is contained in:
X1nto 2021-11-07 19:35:03 +04:00
parent 760c9639e2
commit eb4751f953
55 changed files with 1456 additions and 872 deletions

View File

@ -90,7 +90,7 @@ dependencies {
implementation("androidx.compose.material:material-icons-core:$composeVersion") implementation("androidx.compose.material:material-icons-core:$composeVersion")
implementation("androidx.compose.material:material-icons-extended:$composeVersion") implementation("androidx.compose.material:material-icons-extended:$composeVersion")
implementation("androidx.compose.material:material:$composeVersion") implementation("androidx.compose.material:material:$composeVersion")
implementation("androidx.compose.material:material:$composeVersion") implementation("androidx.compose.material3:material3:1.0.0-alpha01")
implementation("androidx.compose.runtime:runtime-livedata:$composeVersion") implementation("androidx.compose.runtime:runtime-livedata:$composeVersion")
implementation("androidx.compose.ui:ui-tooling:$composeVersion") implementation("androidx.compose.ui:ui-tooling:$composeVersion")
implementation("androidx.compose.ui:ui-util:$composeVersion") implementation("androidx.compose.ui:ui-util:$composeVersion")

View File

@ -7,27 +7,17 @@ import android.content.IntentFilter
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.*
import androidx.compose.foundation.background import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.material.* import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material.icons.Icons import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.material.icons.filled.ArrowBackIos import androidx.compose.runtime.SideEffect
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.github.zsoltk.compose.backpress.BackPressHandler import com.github.zsoltk.compose.backpress.BackPressHandler
import com.github.zsoltk.compose.backpress.LocalBackPressHandler import com.github.zsoltk.compose.backpress.LocalBackPressHandler
import com.github.zsoltk.compose.router.Router import com.github.zsoltk.compose.router.Router
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.vanced.manager.core.installer.service.AppInstallService import com.vanced.manager.core.installer.service.AppInstallService
import com.vanced.manager.ui.component.color.managerAnimatedColor
import com.vanced.manager.ui.component.color.managerSurfaceColor import com.vanced.manager.ui.component.color.managerSurfaceColor
import com.vanced.manager.ui.component.color.managerTextColor
import com.vanced.manager.ui.component.menu.ManagerDropdownMenuItem
import com.vanced.manager.ui.component.text.ToolbarTitleText
import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.screens.* import com.vanced.manager.ui.screens.*
import com.vanced.manager.ui.theme.ManagerTheme import com.vanced.manager.ui.theme.ManagerTheme
import com.vanced.manager.ui.theme.isDark import com.vanced.manager.ui.theme.isDark
@ -53,14 +43,15 @@ class MainActivity : ComponentActivity() {
} }
} }
@OptIn(ExperimentalAnimationApi::class) @OptIn(
ExperimentalAnimationApi::class,
ExperimentalMaterial3Api::class,
ExperimentalFoundationApi::class
)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
ManagerTheme { ManagerTheme {
var isMenuExpanded by remember { mutableStateOf(false) }
var currentScreen by remember { mutableStateOf<Screen>(Screen.Home) }
val surfaceColor = managerSurfaceColor() val surfaceColor = managerSurfaceColor()
val isDark = isDark() val isDark = isDark()
@ -78,98 +69,62 @@ class MainActivity : ComponentActivity() {
LocalBackPressHandler provides backPressHandler LocalBackPressHandler provides backPressHandler
) { ) {
Router<Screen>("VancedManager", Screen.Home) { backStack -> Router<Screen>("VancedManager", Screen.Home) { backStack ->
val screen = backStack.last() when (val screen = backStack.last()) {
currentScreen = screen is Screen.Home -> {
HomeLayout(
onToolbarScreenSelected = {
backStack.push(it)
},
onAppInstallPress = { appName, appVersions, installationOptions ->
if (installationOptions != null) {
backStack.push(
Screen.InstallPreferences(
appName,
appVersions,
installationOptions
)
)
} else {
backStack.push(Screen.Install(appName, appVersions))
}
}
)
}
is Screen.Settings -> {
SettingsLayout(
onToolbarBackButtonClick = {
backStack.pop()
}
)
}
is Screen.About -> {
AboutLayout(
onToolbarBackButtonClick = {
backStack.pop()
}
)
}
is Screen.Logs -> {
Scaffold( }
topBar = { is Screen.InstallPreferences -> {
TopAppBar( InstallPreferencesScreen(
title = { installationOptions = screen.appInstallationOptions,
ToolbarTitleText( onToolbarBackButtonClick = {
text = managerString( backStack.pop()
stringId = currentScreen.displayName },
onDoneClick = {
backStack.push(
Screen.Install(
screen.appName,
screen.appVersions
) )
) )
}, }
backgroundColor = managerAnimatedColor(color = MaterialTheme.colors.surface),
actions = {
if (currentScreen is Screen.Home) {
IconButton(
onClick = { isMenuExpanded = true }
) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = null,
tint = managerTextColor()
)
}
DropdownMenu(
expanded = isMenuExpanded,
onDismissRequest = {
isMenuExpanded = false
},
modifier = Modifier.background(MaterialTheme.colors.surface),
) {
ManagerDropdownMenuItem(
title = stringResource(id = Screen.Settings.displayName)
) {
isMenuExpanded = false
backStack.push(Screen.Settings)
}
}
}
},
navigationIcon = if (currentScreen !is Screen.Home) {
{
IconButton(onClick = {
backStack.pop()
}) {
Icon(
imageVector = Icons.Default.ArrowBackIos,
contentDescription = null,
tint = managerTextColor()
)
}
}
} else null,
elevation = 0.dp
) )
}, }
backgroundColor = surfaceColor is Screen.Install -> {
) { InstallScreen(screen.appName, screen.appVersions)
when (screen) {
is Screen.Home -> {
HomeLayout(
onAppInstallPress = { appName, appVersions, installationOptions ->
if (installationOptions != null) {
backStack.push(Screen.InstallPreferences(appName, appVersions, installationOptions))
} else {
backStack.push(Screen.Install(appName, appVersions))
}
}
)
}
is Screen.Settings -> {
SettingsLayout()
}
is Screen.About -> {
AboutLayout()
}
is Screen.Logs -> {
}
is Screen.InstallPreferences -> {
InstallPreferencesScreen(
installationOptions = screen.appInstallationOptions,
onDoneClick = {
backStack.push(Screen.Install(screen.appName, screen.appVersions))
}
)
}
is Screen.Install -> {
InstallScreen(screen.appName, screen.appVersions)
}
} }
} }
} }

View File

@ -4,8 +4,8 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -15,7 +15,7 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@Composable @Composable
fun IconButton( fun ManagerIconButton(
icon: ImageVector, icon: ImageVector,
contentDescription: String, contentDescription: String,
onClick: () -> Unit onClick: () -> Unit

View File

@ -2,15 +2,15 @@ package com.vanced.manager.ui.component.button
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Button import androidx.compose.material3.Button
import androidx.compose.material.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.component.color.managerAccentColor import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.theme.MediumShape
@Composable @Composable
fun ManagerThemedButton( fun ManagerThemedButton(
@ -22,16 +22,16 @@ fun ManagerThemedButton(
Button( Button(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
onClick = onClick, onClick = onClick,
shape = MaterialTheme.shapes.medium, shape = MediumShape,
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
backgroundColor = backgroundColor, containerColor = backgroundColor,
contentColor = contentColor =
if (backgroundColor.luminance() > 0.7) if (backgroundColor.luminance() > 0.7)
Color.Black Color.Black
else else
Color.White Color.White
), ),
elevation = ButtonDefaults.elevation(0.dp, 0.dp, 0.dp) elevation = ButtonDefaults.elevatedButtonElevation(0.dp, 0.dp, 0.dp, 0.dp)
) { ) {
content() content()
} }

View File

@ -1,26 +1,31 @@
package com.vanced.manager.ui.component.card package com.vanced.manager.ui.component.card
import androidx.compose.material.Card
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.theme.MediumShape
@Composable @Composable
fun ManagerCard( fun ManagerCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
backgroundColor: Color = MaterialTheme.colors.surface, backgroundColor: Color = MaterialTheme.colorScheme.surface,
tonalElevation: Dp = 0.dp,
shadowElevation: Dp = 0.dp,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
Card( Surface(
modifier = modifier, modifier = modifier,
shape = shape, shape = shape,
backgroundColor = backgroundColor, color = backgroundColor,
elevation = 0.dp, shadowElevation = shadowElevation,
tonalElevation = tonalElevation,
content = content content = content
) )
} }
@ -29,17 +34,20 @@ fun ManagerCard(
@Composable @Composable
fun ManagerCard( fun ManagerCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
backgroundColor: Color = MaterialTheme.colors.surface, backgroundColor: Color = MaterialTheme.colorScheme.surface,
tonalElevation: Dp = 0.dp,
shadowElevation: Dp = 0.dp,
onClick: () -> Unit, onClick: () -> Unit,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
Card( Surface(
modifier = modifier, modifier = modifier,
shape = shape, shape = shape,
backgroundColor = backgroundColor, color = backgroundColor,
elevation = 0.dp, shadowElevation = shadowElevation,
content = content, tonalElevation = tonalElevation,
onClick = onClick onClick = onClick,
content = content
) )
} }

View File

@ -1,25 +1,22 @@
package com.vanced.manager.ui.component.card package com.vanced.manager.ui.component.card
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon import androidx.compose.material3.Icon
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import com.github.zsoltk.compose.backpress.LocalBackPressHandler
import com.vanced.manager.ui.component.color.ThemedItemContentColorProvider import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.component.color.managerAccentColor import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical
private val cardModifier = Modifier.sizeIn( private val cardModifier = Modifier.sizeIn(
minHeight = 95.dp, minHeight = 100.dp,
minWidth = 95.dp minWidth = 100.dp
) )
@Composable @Composable
@ -27,7 +24,8 @@ fun ManagerItemCard(
title: String, title: String,
@DrawableRes icon: Int? = null @DrawableRes icon: Int? = null
) { ) {
ManagerThemedCard( LocalBackPressHandler.current.handle()
ManagerCard(
modifier = cardModifier, modifier = cardModifier,
) { ) {
ManagerItemCardContent(title, icon) ManagerItemCardContent(title, icon)
@ -35,12 +33,12 @@ fun ManagerItemCard(
} }
@Composable @Composable
fun ManagerClickableItemCard( fun ManagerItemCard(
title: String, title: String,
@DrawableRes icon: Int? = null, @DrawableRes icon: Int? = null,
onClick: () -> Unit onClick: () -> Unit
) { ) {
ManagerClickableThemedCard( ManagerTonalCard(
modifier = cardModifier, modifier = cardModifier,
onClick = onClick onClick = onClick
) { ) {
@ -53,34 +51,25 @@ private fun ManagerItemCardContent(
title: String, title: String,
@DrawableRes icon: Int? = null, @DrawableRes icon: Int? = null,
) { ) {
val accentColor = managerAccentColor() Column(
val circleOffset = 32.dp.value modifier = Modifier.padding(
Canvas(modifier = Modifier.requiredSize(72.dp)) { horizontal = DefaultContentPaddingHorizontal,
drawCircle( vertical = DefaultContentPaddingVertical
color = accentColor, ),
center = Offset(circleOffset, circleOffset) horizontalAlignment = Alignment.Start,
) verticalArrangement = Arrangement.SpaceBetween
}
Box(
modifier = Modifier.padding(12.dp)
) { ) {
if (icon != null) { if (icon != null) {
ThemedItemContentColorProvider { Icon(
Icon( modifier = Modifier
modifier = Modifier .size(36.dp),
.size(28.dp) painter = painterResource(id = icon),
.align(Alignment.TopStart), contentDescription = title,
painter = painterResource(id = icon), )
contentDescription = title
)
}
} }
Text( ManagerText(
modifier = Modifier.align(Alignment.BottomStart),
text = title, text = title,
fontSize = 12.sp, textStyle = MaterialTheme.typography.labelLarge
fontWeight = FontWeight.Medium,
color = MaterialTheme.colors.onSurface
) )
} }
} }

View File

@ -20,7 +20,7 @@ fun ManagerLinkCard(
val uri = remember { Uri.parse(link) } val uri = remember { Uri.parse(link) }
val intent = remember { Intent(Intent.ACTION_VIEW, uri) } val intent = remember { Intent(Intent.ACTION_VIEW, uri) }
val useCustomTabs by useCustomTabsPref val useCustomTabs by useCustomTabsPref
ManagerClickableItemCard( ManagerItemCard(
title = title, title = title,
icon = icon icon = icon
) { ) {

View File

@ -1,38 +1,37 @@
package com.vanced.manager.ui.component.card package com.vanced.manager.ui.component.card
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import com.vanced.manager.ui.component.color.managerThemedCardColor import com.vanced.manager.ui.theme.MediumShape
@Composable @Composable
fun ManagerThemedCard( fun ManagerContainerCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
ManagerCard( ManagerCard(
modifier = modifier, modifier = modifier,
shape = shape, shape = shape,
backgroundColor = managerThemedCardColor(), backgroundColor = MaterialTheme.colorScheme.primaryContainer,
content = content content = content
) )
} }
@Composable @Composable
fun ManagerClickableThemedCard( fun ManagerContainerCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
onClick: () -> Unit, onClick: () -> Unit,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
ManagerCard( ManagerCard(
modifier = modifier, modifier = modifier,
shape = shape, shape = shape,
backgroundColor = managerThemedCardColor(), backgroundColor = MaterialTheme.colorScheme.primaryContainer,
onClick = onClick, onClick = onClick,
) { content = content,
content() )
}
} }

View File

@ -0,0 +1,37 @@
package com.vanced.manager.ui.component.card
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.theme.MediumShape
@Composable
fun ManagerTonalCard(
modifier: Modifier = Modifier,
shape: Shape = MediumShape,
content: @Composable () -> Unit,
) {
ManagerCard(
modifier = modifier,
shape = shape,
tonalElevation = 4.dp,
content = content
)
}
@Composable
fun ManagerTonalCard(
modifier: Modifier = Modifier,
shape: Shape = MediumShape,
onClick: () -> Unit,
content: @Composable () -> Unit,
) {
ManagerCard(
modifier = modifier,
shape = shape,
tonalElevation = 4.dp,
onClick = onClick,
content = content
)
}

View File

@ -3,33 +3,37 @@ package com.vanced.manager.ui.component.checkbox
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.requiredSizeIn import androidx.compose.foundation.layout.requiredSizeIn
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.Done import androidx.compose.material.icons.rounded.Done
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import com.vanced.manager.ui.component.card.ManagerCard import com.vanced.manager.ui.component.card.ManagerCard
import com.vanced.manager.ui.component.color.contentColorForColor
import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.component.color.managerAnimatedColor import com.vanced.manager.ui.component.color.managerAnimatedColor
import com.vanced.manager.ui.component.color.managerThemedCardColor import com.vanced.manager.ui.theme.MediumShape
@SuppressLint("UnusedTransitionTargetStateParameter") @SuppressLint("UnusedTransitionTargetStateParameter")
@Composable @Composable
fun ManagerCheckbox( fun ManagerCheckbox(
modifier: Modifier, modifier: Modifier,
isChecked: Boolean, isChecked: Boolean,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
onCheckedChange: (isChecked: Boolean) -> Unit onCheckedChange: (isChecked: Boolean) -> Unit
) { ) {
val cardColor = val cardColor =
managerAnimatedColor(if (isChecked) managerAccentColor() else managerThemedCardColor()) managerAnimatedColor(if (isChecked) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primaryContainer)
val iconTint = val iconTint =
managerAnimatedColor(if (isChecked) contentColorForColor(cardColor) else managerAccentColor()) managerAnimatedColor(
if (isChecked)
contentColorFor(MaterialTheme.colorScheme.primary)
else
contentColorFor(MaterialTheme.colorScheme.primaryContainer)
)
ManagerCard( ManagerCard(
modifier = modifier, modifier = modifier,

View File

@ -1,6 +1,6 @@
package com.vanced.manager.ui.component.color package com.vanced.manager.ui.component.color
import androidx.compose.material.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider

View File

@ -2,7 +2,7 @@ package com.vanced.manager.ui.component.color
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.luminance
@ -25,10 +25,10 @@ fun managerAccentColor(): Color {
fun managerThemedCardColor() = managerAccentColor().copy(alpha = 0.27f) fun managerThemedCardColor() = managerAccentColor().copy(alpha = 0.27f)
@Composable @Composable
fun managerTextColor(): Color = managerAnimatedColor(color = MaterialTheme.colors.onSurface) fun managerTextColor(): Color = managerAnimatedColor(color = MaterialTheme.colorScheme.onSurface)
@Composable @Composable
fun managerSurfaceColor(): Color = managerAnimatedColor(color = MaterialTheme.colors.surface) fun managerSurfaceColor(): Color = managerAnimatedColor(color = MaterialTheme.colorScheme.surface)
@Composable @Composable
fun managerAnimatedColor( fun managerAnimatedColor(

View File

@ -1,13 +1,16 @@
package com.vanced.manager.ui.component.dialog package com.vanced.manager.ui.component.dialog
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import com.vanced.manager.ui.component.card.ManagerCard import com.vanced.manager.ui.component.card.ManagerCard
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.theme.LargeShape
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.DefaultContentPaddingVertical
@ -15,45 +18,25 @@ import com.vanced.manager.ui.util.DefaultContentPaddingVertical
fun ManagerDialog( fun ManagerDialog(
title: String, title: String,
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,
buttons: @Composable ColumnScope.() -> Unit, confirmButton: @Composable () -> Unit,
content: @Composable ColumnScope.() -> Unit, modifier: Modifier = Modifier,
dismissButton: @Composable (() -> Unit)? = null,
icon: @Composable (() -> Unit)? = null,
content: @Composable () -> Unit,
) { ) {
ManagerDialog( AlertDialog(
modifier = modifier,
title = { title = {
ManagerText( ManagerText(
modifier = Modifier
.fillMaxWidth(),
textStyle = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
text = title text = title
) )
}, },
text = content,
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
buttons = buttons, confirmButton = confirmButton,
content = content dismissButton = dismissButton,
icon = icon,
shape = LargeShape,
tonalElevation = 2.dp,
) )
} }
@Composable
fun ManagerDialog(
title: @Composable ColumnScope.() -> Unit,
onDismissRequest: () -> Unit,
buttons: @Composable ColumnScope.() -> Unit,
content: @Composable ColumnScope.() -> Unit,
) {
Dialog(
onDismissRequest = onDismissRequest,
content = {
ManagerCard {
Column(
modifier = Modifier.padding(DefaultContentPaddingHorizontal),
verticalArrangement = Arrangement.spacedBy(DefaultContentPaddingVertical)
) {
title()
content()
buttons()
}
}
},
)
}

View File

@ -8,19 +8,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingVertical
@Composable @Composable
fun ManagerLazyColumn( fun ManagerLazyColumn(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
itemSpacing: Dp = 0.dp,
contentPadding: PaddingValues = PaddingValues(12.dp),
content: LazyListScope.() -> Unit content: LazyListScope.() -> Unit
) { ) {
LazyColumn( LazyColumn(
modifier = modifier, modifier = modifier,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(itemSpacing),
content = content content = content
) )
} }

View File

@ -0,0 +1,32 @@
package com.vanced.manager.ui.component.layout
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@ExperimentalMaterial3Api
@Composable
fun ManagerScaffold(
modifier: Modifier = Modifier,
scaffoldState: ScaffoldState = rememberScaffoldState(),
topBar: @Composable () -> Unit = {},
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
content: @Composable (PaddingValues) -> Unit
) {
// //M3 Scaffold doesn't support tonal elevation for Surface
// val absoluteTonalElevation = LocalAbsoluteTonalElevation.current + 1.dp
// CompositionLocalProvider(
// LocalAbsoluteTonalElevation provides absoluteTonalElevation
// ) {
Scaffold(
modifier = modifier,
scaffoldState = scaffoldState,
topBar = topBar,
floatingActionButton = floatingActionButton,
floatingActionButtonPosition = floatingActionButtonPosition,
content = content
)
// }
}

View File

@ -4,7 +4,7 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -20,7 +20,7 @@ fun ManagerScrim(
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
val scrimColor = Color.Black.copy(alpha = 0.5f) val scrimColor = Color.Black.copy(alpha = 0.5f)
val surfaceColor = MaterialTheme.colors.surface val surfaceColor = MaterialTheme.colorScheme.surface
val isDark = isDark() val isDark = isDark()

View File

@ -1,7 +1,7 @@
package com.vanced.manager.ui.component.layout package com.vanced.manager.ui.component.layout
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.vanced.manager.ui.component.color.managerSurfaceColor import com.vanced.manager.ui.component.color.managerSurfaceColor

View File

@ -1,18 +1,25 @@
package com.vanced.manager.ui.component.layout package com.vanced.manager.ui.component.layout
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.google.accompanist.swiperefresh.SwipeRefresh import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.SwipeRefreshIndicator import com.google.accompanist.swiperefresh.SwipeRefreshIndicator
import com.google.accompanist.swiperefresh.SwipeRefreshState import com.google.accompanist.swiperefresh.SwipeRefreshState
import com.vanced.manager.ui.component.card.ManagerCard
import com.vanced.manager.ui.component.color.managerAccentColor import com.vanced.manager.ui.component.color.managerAccentColor
@Composable @Composable
fun ManagerSwipeRefresh( fun ManagerSwipeRefresh(
refreshState: SwipeRefreshState, refreshState: SwipeRefreshState,
onRefresh: () -> Unit, onRefresh: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
SwipeRefresh( SwipeRefresh(
modifier = modifier,
state = refreshState, state = refreshState,
onRefresh = onRefresh, onRefresh = onRefresh,
indicator = { state, trigger -> indicator = { state, trigger ->
@ -20,7 +27,8 @@ fun ManagerSwipeRefresh(
state = state, state = state,
refreshTriggerDistance = trigger, refreshTriggerDistance = trigger,
scale = true, scale = true,
contentColor = managerAccentColor() contentColor = MaterialTheme.colorScheme.primary,
backgroundColor = MaterialTheme.colorScheme.surface
) )
}, },
content = content content = content

View File

@ -12,11 +12,12 @@ import androidx.compose.ui.unit.dp
@Composable @Composable
fun <T> ScrollableItemRow( fun <T> ScrollableItemRow(
items: List<T>, items: List<T>,
modifier: Modifier = Modifier,
content: @Composable (T) -> Unit content: @Composable (T) -> Unit
) { ) {
val state = rememberLazyListState() val state = rememberLazyListState()
LazyRow( LazyRow(
modifier = Modifier.fillMaxWidth(), modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),
state = state state = state
) { ) {

View File

@ -0,0 +1,103 @@
package com.vanced.manager.ui.component.menu
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.scale
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.PopupProperties
import com.vanced.manager.ui.component.card.ManagerCard
private const val TransitionDuration = 200
@ExperimentalAnimationApi
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ManagerDropdownMenu(
expanded: Boolean,
onDismissRequest: () -> Unit,
content: @Composable ColumnScope.() -> Unit,
) {
val expandedStates = remember { MutableTransitionState(false) }
expandedStates.targetState = expanded
val transition = updateTransition(expandedStates, "ManagerDropDownMenu")
val alphaAndScale by transition.animateFloat(
transitionSpec = { tween(durationMillis = TransitionDuration) },
label = "AlphaAndScale"
) {
if (it) 1f else 0f
}
if (expandedStates.currentState || expandedStates.targetState) {
val density = LocalDensity.current
val popupPositionProvider =
ManagerDropdownMenuPopupPositionProvider(density)
Popup(
popupPositionProvider = popupPositionProvider,
onDismissRequest = onDismissRequest,
properties = PopupProperties(focusable = true)
) {
ManagerCard(
modifier = Modifier
.width(IntrinsicSize.Max)
.alpha(alphaAndScale)
.scale(alphaAndScale),
tonalElevation = 2.dp,
shadowElevation = 2.dp
) {
Column(content = content)
}
}
}
}
//Kanged from Menu.kt
data class ManagerDropdownMenuPopupPositionProvider(
val density: Density
) : PopupPositionProvider {
override fun calculatePosition(
anchorBounds: IntRect,
windowSize: IntSize,
layoutDirection: LayoutDirection,
popupContentSize: IntSize
): IntOffset {
val verticalMargin = with(density) { 48.dp.roundToPx() }
//Compute horizontal position.
val toRight = anchorBounds.left
val toLeft = anchorBounds.right - popupContentSize.width
val toDisplayRight = windowSize.width - popupContentSize.width
val toDisplayLeft = 0
val x = if (layoutDirection == LayoutDirection.Ltr) {
sequenceOf(toRight, toLeft, toDisplayRight)
} else {
sequenceOf(toLeft, toRight, toDisplayLeft)
}.firstOrNull {
it >= 0 && it + popupContentSize.width <= windowSize.width
} ?: toLeft
// Compute vertical position.
val toBottom = maxOf(anchorBounds.bottom, verticalMargin)
val toTop = anchorBounds.top - popupContentSize.height
val toCenter = anchorBounds.top - popupContentSize.height / 2
val toDisplayBottom = windowSize.height - popupContentSize.height - verticalMargin
val y = sequenceOf(toBottom, toTop, toCenter, toDisplayBottom).firstOrNull {
it >= verticalMargin &&
it + popupContentSize.height <= windowSize.height - verticalMargin
} ?: toTop
return IntOffset(x, y)
}
}

View File

@ -1,9 +1,12 @@
package com.vanced.manager.ui.component.menu package com.vanced.manager.ui.component.menu
import androidx.compose.material.DropdownMenuItem import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.theme.SmallShape
@Composable @Composable
fun ManagerDropdownMenuItem( fun ManagerDropdownMenuItem(
@ -12,10 +15,11 @@ fun ManagerDropdownMenuItem(
) { ) {
DropdownMenuItem( DropdownMenuItem(
onClick = onClick, onClick = onClick,
modifier = Modifier.clip(SmallShape),
) { ) {
ManagerText( ManagerText(
text = title, text = title,
textStyle = MaterialTheme.typography.h6 textStyle = MaterialTheme.typography.labelLarge
) )
} }
} }

View File

@ -2,12 +2,12 @@ package com.vanced.manager.ui.component.modifier
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ripple.rememberRipple import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import com.vanced.manager.ui.theme.MediumShape
fun Modifier.managerClickable( fun Modifier.managerClickable(
onClick: () -> Unit onClick: () -> Unit
@ -15,9 +15,7 @@ fun Modifier.managerClickable(
val ripple = rememberRipple() val ripple = rememberRipple()
val interactionSource = remember { MutableInteractionSource() } val interactionSource = remember { MutableInteractionSource() }
return@composed then( then(clip(MediumShape)).then(
clip(MaterialTheme.shapes.medium)
).then(
clickable( clickable(
interactionSource = interactionSource, interactionSource = interactionSource,
onClick = onClick, onClick = onClick,

View File

@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -15,6 +16,7 @@ import com.vanced.manager.R
import com.vanced.manager.core.preferences.CheckboxPreference import com.vanced.manager.core.preferences.CheckboxPreference
import com.vanced.manager.core.preferences.ManagerPreference import com.vanced.manager.core.preferences.ManagerPreference
import com.vanced.manager.ui.component.button.ManagerThemedTextButton import com.vanced.manager.ui.component.button.ManagerThemedTextButton
import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.widget.list.CheckboxItem import com.vanced.manager.ui.widget.list.CheckboxItem
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -37,10 +39,8 @@ fun CheckboxDialogPreference(
} }
}.sortedBy { it.title }.joinToString(separator = ", ") { it.title }, }.sortedBy { it.title }.joinToString(separator = ", ") { it.title },
trailing = trailing, trailing = trailing,
buttons = { isShown -> confirmButton = { isShown ->
ManagerThemedTextButton( TextButton(
text = stringResource(id = R.string.dialog_button_save),
modifier = Modifier.fillMaxWidth(),
onClick = { onClick = {
coroutineScope.launch { coroutineScope.launch {
isShown.value = false isShown.value = false
@ -48,8 +48,10 @@ fun CheckboxDialogPreference(
onSave(selectedButtons) onSave(selectedButtons)
} }
} }
) ) {
} ManagerText(stringResource(id = R.string.dialog_button_save))
}
},
) { ) {
LazyColumn( LazyColumn(
modifier = Modifier.heightIn(max = 400.dp) modifier = Modifier.heightIn(max = 400.dp)

View File

@ -1,6 +1,5 @@
package com.vanced.manager.ui.component.preference package com.vanced.manager.ui.component.preference
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -13,8 +12,9 @@ fun DialogPreference(
preferenceDescription: String? = null, preferenceDescription: String? = null,
onDismissRequest: () -> Unit = {}, onDismissRequest: () -> Unit = {},
trailing: @Composable () -> Unit = {}, trailing: @Composable () -> Unit = {},
buttons: @Composable ColumnScope.(isShown: MutableState<Boolean>) -> Unit, confirmButton: @Composable (isShown: MutableState<Boolean>) -> Unit,
content: @Composable ColumnScope.() -> Unit dismissButton: @Composable ((isShown: MutableState<Boolean>) -> Unit)? = null,
content: @Composable () -> Unit
) { ) {
val isShown = remember { mutableStateOf(false) } val isShown = remember { mutableStateOf(false) }
Preference( Preference(
@ -31,7 +31,14 @@ fun DialogPreference(
onDismissRequest() onDismissRequest()
isShown.value = false isShown.value = false
}, },
buttons = { buttons(isShown) }, confirmButton = {
confirmButton(isShown)
},
dismissButton = {
if (dismissButton != null) {
dismissButton(isShown)
}
},
content = content content = content
) )
} }

View File

@ -1,9 +1,9 @@
package com.vanced.manager.ui.component.preference package com.vanced.manager.ui.component.preference
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -39,7 +39,7 @@ fun Preference(
trailing: @Composable () -> Unit = {}, trailing: @Composable () -> Unit = {},
onClick: () -> Unit onClick: () -> Unit
) { ) {
val color = managerAnimatedColor(color = MaterialTheme.colors.onSurface) val color = managerAnimatedColor(color = MaterialTheme.colorScheme.onSurface)
ManagerListItem( ManagerListItem(
modifier = Modifier modifier = Modifier
.managerClickable(onClick = onClick) .managerClickable(onClick = onClick)
@ -47,7 +47,7 @@ fun Preference(
title = { title = {
CompositionLocalProvider( CompositionLocalProvider(
LocalContentColor provides color, LocalContentColor provides color,
LocalTextStyle provides MaterialTheme.typography.h6 LocalTextStyle provides MaterialTheme.typography.titleSmall
) { ) {
preferenceTitle() preferenceTitle()
} }
@ -56,7 +56,7 @@ fun Preference(
{ {
CompositionLocalProvider( CompositionLocalProvider(
LocalContentColor provides color, LocalContentColor provides color,
LocalTextStyle provides MaterialTheme.typography.subtitle1 LocalTextStyle provides MaterialTheme.typography.bodySmall
) { ) {
preferenceDescription() preferenceDescription()
} }

View File

@ -3,11 +3,15 @@ package com.vanced.manager.ui.component.preference
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.TextButton
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vanced.manager.R
import com.vanced.manager.core.preferences.ManagerPreference import com.vanced.manager.core.preferences.ManagerPreference
import com.vanced.manager.core.preferences.RadioButtonPreference import com.vanced.manager.core.preferences.RadioButtonPreference
import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.widget.button.ManagerSaveButton import com.vanced.manager.ui.widget.button.ManagerSaveButton
import com.vanced.manager.ui.widget.list.RadiobuttonItem import com.vanced.manager.ui.widget.list.RadiobuttonItem
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -27,13 +31,13 @@ fun RadiobuttonDialogPreference(
preferenceTitle = preferenceTitle, preferenceTitle = preferenceTitle,
preferenceDescription = buttons.find { it.key == pref }?.title, preferenceDescription = buttons.find { it.key == pref }?.title,
trailing = trailing, trailing = trailing,
buttons = { isShown -> confirmButton = { isShown ->
ManagerSaveButton { TextButton(onClick = {
coroutineScope.launch { isShown.value = false
isShown.value = false pref = currentSelection
pref = currentSelection onSave(currentSelection)
onSave(currentSelection) }) {
} ManagerText(managerString(stringId = R.string.dialog_button_save))
} }
}, },
) { ) {

View File

@ -4,7 +4,6 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.material.LinearProgressIndicator import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ProgressIndicatorDefaults import androidx.compose.material.ProgressIndicatorDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -13,11 +12,12 @@ import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.component.color.managerAccentColor import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.theme.MediumShape
private val progressBarModifier = Modifier.composed { private val progressBarModifier = Modifier.composed {
then(height(5.dp)) then(height(5.dp))
.then(fillMaxWidth()) .then(fillMaxWidth())
.then(clip(MaterialTheme.shapes.medium)) .then(clip(MediumShape))
} }
@Composable @Composable

View File

@ -1,25 +1,24 @@
package com.vanced.manager.ui.component.radiobutton package com.vanced.manager.ui.component.radiobutton
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.Shape
import com.vanced.manager.ui.component.card.ManagerCard import com.vanced.manager.ui.component.card.ManagerCard
import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.component.color.managerAnimatedColor import com.vanced.manager.ui.component.color.managerAnimatedColor
import com.vanced.manager.ui.component.color.managerThemedCardColor import com.vanced.manager.ui.theme.MediumShape
@SuppressLint("UnusedTransitionTargetStateParameter") @SuppressLint("UnusedTransitionTargetStateParameter")
@Composable @Composable
fun ManagerRadiobutton( fun ManagerRadiobutton(
modifier: Modifier, modifier: Modifier,
isSelected: Boolean, isSelected: Boolean,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
onClick: () -> Unit onClick: () -> Unit
) { ) {
val accentColor = managerAccentColor() val cardColor =
val cardColor = managerAnimatedColor(if (isSelected) accentColor else managerThemedCardColor()) managerAnimatedColor(if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primaryContainer)
ManagerCard( ManagerCard(
modifier = modifier, modifier = modifier,
onClick = onClick, onClick = onClick,

View File

@ -1,6 +1,6 @@
package com.vanced.manager.ui.component.text package com.vanced.manager.ui.component.text
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -12,6 +12,6 @@ fun AppVersionText(
ManagerText( ManagerText(
modifier = modifier, modifier = modifier,
text = text, text = text,
textStyle = MaterialTheme.typography.body2, textStyle = MaterialTheme.typography.bodySmall,
) )
} }

View File

@ -1,7 +1,7 @@
package com.vanced.manager.ui.component.text package com.vanced.manager.ui.component.text
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.vanced.manager.ui.component.color.managerAnimatedColor import com.vanced.manager.ui.component.color.managerAnimatedColor
@ -14,7 +14,7 @@ fun CategoryTitleText(
ManagerText( ManagerText(
modifier = Modifier.padding(start = DefaultContentPaddingHorizontal), modifier = Modifier.padding(start = DefaultContentPaddingHorizontal),
text = text, text = text,
textStyle = MaterialTheme.typography.h2, textStyle = MaterialTheme.typography.headlineSmall,
color = managerAnimatedColor(MaterialTheme.colors.onSurface) color = managerAnimatedColor(MaterialTheme.colorScheme.onSurface)
) )
} }

View File

@ -1,7 +1,7 @@
package com.vanced.manager.ui.component.text package com.vanced.manager.ui.component.text
import androidx.compose.material.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View File

@ -1,6 +1,6 @@
package com.vanced.manager.ui.component.text package com.vanced.manager.ui.component.text
import androidx.compose.material.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import com.vanced.manager.ui.component.color.managerAnimatedColor import com.vanced.manager.ui.component.color.managerAnimatedColor
@ -10,7 +10,7 @@ fun ToolbarTitleText(
) { ) {
ManagerText( ManagerText(
text = text, text = text,
textStyle = MaterialTheme.typography.h1, textStyle = MaterialTheme.typography.headlineMedium,
color = managerAnimatedColor(MaterialTheme.colors.onSurface) color = managerAnimatedColor(MaterialTheme.colorScheme.onSurface)
) )
} }

View File

@ -0,0 +1,30 @@
package com.vanced.manager.ui.component.topappbar
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.vanced.manager.ui.component.color.managerAnimatedColor
import com.vanced.manager.ui.component.text.ManagerText
@Composable
fun ManagerTopAppBar(
title: String,
modifier: Modifier = Modifier,
actions: @Composable RowScope.() -> Unit = {},
navigationIcon: @Composable () -> Unit = {},
) {
SmallTopAppBar(
modifier = modifier,
title = {
ManagerText(
text = title,
textStyle = MaterialTheme.typography.headlineMedium,
color = managerAnimatedColor(MaterialTheme.colorScheme.onSurface)
)
},
actions = actions,
navigationIcon = navigationIcon,
)
}

View File

@ -2,11 +2,13 @@ package com.vanced.manager.ui.screens
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column import androidx.compose.material.icons.Icons
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.icons.rounded.ArrowBackIosNew
import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material.MaterialTheme import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -15,96 +17,83 @@ import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.ui.component.card.ManagerLinkCard import com.vanced.manager.ui.component.card.ManagerLinkCard
import com.vanced.manager.ui.component.card.ManagerThemedCard import com.vanced.manager.ui.component.card.ManagerTonalCard
import com.vanced.manager.ui.component.layout.ManagerScrollableColumn import com.vanced.manager.ui.component.layout.ManagerLazyColumn
import com.vanced.manager.ui.component.layout.ManagerScaffold
import com.vanced.manager.ui.component.layout.ScrollableItemRow import com.vanced.manager.ui.component.layout.ScrollableItemRow
import com.vanced.manager.ui.component.list.ManagerListItem import com.vanced.manager.ui.component.list.ManagerListItem
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.component.topappbar.ManagerTopAppBar
import com.vanced.manager.ui.resources.managerString import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.theme.LargeShape
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.DefaultContentPaddingVertical
import com.vanced.manager.ui.widget.layout.CategoryLayout import com.vanced.manager.ui.util.Screen
import com.vanced.manager.ui.widget.layout.managerCategory
data class Person( data class Person(
val name: String, val name: String,
val contribution: String val contribution: String
) )
data class Credit(
@StringRes val nameId: Int,
val persons: List<Person>
)
data class Source( data class Source(
@StringRes val nameId: Int, @StringRes val nameId: Int,
@DrawableRes val iconId: Int, @DrawableRes val iconId: Int,
val link: String val link: String
) )
private val credits = listOf( private val vancedTeam = listOf(
Credit( Person(
nameId = R.string.about_category_credits_vanced_team, name = "xfileFIN",
persons = listOf( contribution = "Mods, Theming, Support"
Person(
name = "xfileFIN",
contribution = "Mods, Theming, Support"
),
Person(
name = "Laura",
contribution = "Theming, Support"
),
Person(
name = "ZaneZam",
contribution = "Publishing, Support"
),
Person(
name = "KevinX8",
contribution = "Overlord, Support"
)
)
), ),
Credit( Person(
nameId = R.string.about_category_credits_manager_devs, name = "Laura",
persons = listOf( contribution = "Theming, Support"
Person(
name = "Xinto",
contribution = "Manager Core"
),
Person(
name = "Koopah",
contribution = "Root installer"
),
Person(
name = "Logan",
contribution = "UI"
),
Person(
name = "HaliksaR",
contribution = "Refactoring, UI"
),
)
), ),
Credit( Person(
nameId = R.string.about_category_credits_other, name = "ZaneZam",
persons = listOf( contribution = "Publishing, Support"
Person( ),
name = "bhatVikrant", Person(
contribution = "Website" name = "KevinX8",
), contribution = "Overlord, Support"
Person( ),
name = "bawm", Person(
contribution = "Sponsorblock" name = "Xinto",
), contribution = "Vanced Manager"
Person(
name = "cane",
contribution = "Sponsorblock"
),
)
) )
) )
private val otherContributors = listOf(
Person(
name = "bhatVikrant",
contribution = "Website"
),
Person(
name = "bawm",
contribution = "Sponsorblock"
),
Person(
name = "cane",
contribution = "Sponsorblock"
),
Person(
name = "Koopah",
contribution = "Vanced Manager root installer"
),
Person(
name = "Logan",
contribution = "Vanced Manager UI"
),
Person(
name = "HaliksaR",
contribution = "Vanced Manager Refactoring, UI"
),
)
private val sources = listOf( private val sources = listOf(
Source( Source(
nameId = R.string.about_sources_source_code, nameId = R.string.about_sources_source_code,
@ -118,79 +107,119 @@ private val sources = listOf(
) )
) )
@ExperimentalMaterial3Api
@Composable @Composable
fun AboutLayout() { fun AboutLayout(
ManagerScrollableColumn( onToolbarBackButtonClick: () -> Unit
itemSpacing = 12.dp ) {
) { val aboutCategoryVancedTeam = managerString(R.string.about_category_credits_vanced_team)
AboutManagerCard() val aboutCategoryOtherContributors = managerString(R.string.about_category_credits_other)
credits.fastForEach { credit -> val aboutCategorySources = managerString(R.string.about_category_sources)
CategoryLayout(
categoryName = managerString(stringId = credit.nameId), ManagerScaffold(
categoryNameSpacing = 4.dp topBar = {
) { ManagerTopAppBar(
Column { title = managerString(Screen.About.displayName),
credit.persons.fastForEach { person -> navigationIcon = {
ManagerListItem( IconButton(onClick = onToolbarBackButtonClick) {
title = { Icon(
ManagerText( imageVector = Icons.Rounded.ArrowBackIosNew,
text = person.name, contentDescription = "Back"
textStyle = MaterialTheme.typography.h6 )
) }
}
)
}
) { paddingValues ->
ManagerLazyColumn(
modifier = Modifier.fillMaxSize().padding(paddingValues),
) {
item {
ManagerTonalCard(
modifier = Modifier.fillMaxWidth(),
shape = LargeShape
) {
Column(
modifier = Modifier.padding(vertical = DefaultContentPaddingVertical),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
ManagerText(
modifier = Modifier,
text = managerString(R.string.app_name),
textStyle = MaterialTheme.typography.headlineSmall
)
ManagerText(
modifier = Modifier,
text = buildAnnotatedString {
append("Re")
withStyle(style = SpanStyle(Color(0xFFBBB529))) {
append("@Compose")
}
append("d")
}, },
description = { textStyle = MaterialTheme.typography.titleSmall
ManagerText(
text = person.contribution,
textStyle = MaterialTheme.typography.subtitle1
)
}
) )
} }
} }
} }
} managerCategory(
CategoryLayout( categoryName = aboutCategoryVancedTeam,
categoryName = managerString( items = vancedTeam
stringId = R.string.about_category_sources ) { person ->
), CreditPersonItem(
) { modifier = Modifier.fillMaxWidth(),
ScrollableItemRow(items = sources) { source -> personName = person.name,
ManagerLinkCard( personContribution = person.contribution
title = managerString(source.nameId),
icon = source.iconId,
link = source.link
) )
} }
managerCategory(
categoryName = aboutCategoryOtherContributors,
items = otherContributors
) { person ->
CreditPersonItem(
modifier = Modifier.fillMaxWidth(),
personName = person.name,
personContribution = person.contribution
)
}
managerCategory(aboutCategorySources) {
ScrollableItemRow(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = DefaultContentPaddingHorizontal),
items = sources
) { source ->
ManagerLinkCard(
title = managerString(source.nameId),
icon = source.iconId,
link = source.link
)
}
}
} }
} }
} }
@Composable @Composable
fun AboutManagerCard() { private fun CreditPersonItem(
ManagerThemedCard( personName: String,
modifier = Modifier.fillMaxWidth() personContribution: String,
) { modifier: Modifier = Modifier,
Column( ) {
modifier = Modifier.padding(vertical = DefaultContentPaddingVertical), ManagerListItem(
horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier.padding(horizontal = DefaultContentPaddingHorizontal),
verticalArrangement = Arrangement.spacedBy(4.dp) title = {
) {
ManagerText( ManagerText(
modifier = Modifier, text = personName,
text = managerString(R.string.app_name), textStyle = MaterialTheme.typography.titleSmall
textStyle = MaterialTheme.typography.h1
) )
},
description = {
ManagerText( ManagerText(
modifier = Modifier, text = personContribution,
text = buildAnnotatedString { textStyle = MaterialTheme.typography.bodySmall
append("Re")
withStyle(style = SpanStyle(Color(0xFFBBB529))) {
append("@Compose")
}
append("d")
},
textStyle = MaterialTheme.typography.h5
) )
} }
} )
} }

View File

@ -1,15 +1,14 @@
package com.vanced.manager.ui.screens package com.vanced.manager.ui.screens
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column import androidx.compose.material.icons.Icons
import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.rounded.MoreVert
import androidx.compose.material.MaterialTheme import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import coil.compose.rememberImagePainter import coil.compose.rememberImagePainter
import coil.request.CachePolicy import coil.request.CachePolicy
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
@ -19,23 +18,28 @@ import com.vanced.manager.core.util.sponsors
import com.vanced.manager.domain.model.InstallationOption import com.vanced.manager.domain.model.InstallationOption
import com.vanced.manager.ui.component.card.ManagerLinkCard import com.vanced.manager.ui.component.card.ManagerLinkCard
import com.vanced.manager.ui.component.dialog.ManagerDialog import com.vanced.manager.ui.component.dialog.ManagerDialog
import com.vanced.manager.ui.component.layout.ManagerScrollableColumn import com.vanced.manager.ui.component.layout.ManagerLazyColumn
import com.vanced.manager.ui.component.layout.ManagerScaffold
import com.vanced.manager.ui.component.layout.ManagerSwipeRefresh import com.vanced.manager.ui.component.layout.ManagerSwipeRefresh
import com.vanced.manager.ui.component.layout.ScrollableItemRow import com.vanced.manager.ui.component.layout.ScrollableItemRow
import com.vanced.manager.ui.component.menu.ManagerDropdownMenu
import com.vanced.manager.ui.component.menu.ManagerDropdownMenuItem
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.component.topappbar.ManagerTopAppBar
import com.vanced.manager.ui.resources.managerString import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.Screen import com.vanced.manager.ui.util.Screen
import com.vanced.manager.ui.viewmodel.MainViewModel import com.vanced.manager.ui.viewmodel.MainViewModel
import com.vanced.manager.ui.widget.app.AppCard import com.vanced.manager.ui.widget.app.AppCard
import com.vanced.manager.ui.widget.app.AppCardPlaceholder import com.vanced.manager.ui.widget.app.AppCardPlaceholder
import com.vanced.manager.ui.widget.button.ManagerCloseButton import com.vanced.manager.ui.widget.layout.managerCategory
import com.vanced.manager.ui.widget.layout.CategoryLayout
import org.koin.androidx.compose.getViewModel import org.koin.androidx.compose.getViewModel
@ExperimentalMaterial3Api
@ExperimentalAnimationApi @ExperimentalAnimationApi
@Composable @Composable
fun HomeLayout( fun HomeLayout(
onToolbarScreenSelected: (Screen) -> Unit,
onAppInstallPress: ( onAppInstallPress: (
appName: String, appName: String,
appVersions: List<String>?, appVersions: List<String>?,
@ -43,102 +47,152 @@ fun HomeLayout(
) -> Unit ) -> Unit
) { ) {
val viewModel: MainViewModel = getViewModel() val viewModel: MainViewModel = getViewModel()
val appState by viewModel.appState.collectAsState() val appState by viewModel.appState.collectAsState()
val refreshState = rememberSwipeRefreshState(isRefreshing = appState is MainViewModel.AppState.Fetching) val refreshState = rememberSwipeRefreshState(isRefreshing = appState is MainViewModel.AppState.Fetching)
ManagerSwipeRefresh( var isMenuExpanded by remember { mutableStateOf(false) }
refreshState = refreshState, val dropdownScreens = remember { listOf(Screen.Settings, Screen.About) }
onRefresh = { viewModel.fetch() }
) { val homeCategoryApps = managerString(R.string.home_category_apps)
ManagerScrollableColumn( val homeCategorySupportUs = managerString(R.string.home_category_support_us)
contentPaddingVertical = DefaultContentPaddingVertical, val homeCategorySocialMedia = managerString(R.string.home_category_social_media)
itemSpacing = 18.dp
) { ManagerScaffold(
CategoryLayout( topBar = {
categoryName = managerString(R.string.home_category_apps), ManagerTopAppBar(
contentPaddingHorizontal = 0.dp title = managerString(Screen.Home.displayName),
) { actions = {
AnimatedContent( IconButton(onClick = { isMenuExpanded = true }) {
targetState = appState, Icon(
transitionSpec = { Icons.Rounded.MoreVert,
scaleIn(initialScale = 0.9f) + fadeIn() with contentDescription = "Navigation"
scaleOut(targetScale = 0.9f) + fadeOut() )
} }
) { animatedAppState ->
Column( ManagerDropdownMenu(
verticalArrangement = Arrangement.spacedBy(8.dp) expanded = isMenuExpanded,
onDismissRequest = {
isMenuExpanded = false
}
) { ) {
when (animatedAppState) { for (dropdownScreen in dropdownScreens) {
is MainViewModel.AppState.Success -> { ManagerDropdownMenuItem(
for (app in animatedAppState.apps) { title = managerString(dropdownScreen.displayName),
val appIcon = rememberImagePainter(app.iconUrl) { onClick = {
diskCachePolicy(CachePolicy.ENABLED) onToolbarScreenSelected(dropdownScreen)
} isMenuExpanded = false
}
var showAppInfoDialog by rememberSaveable { mutableStateOf(false) } )
}
AppCard( }
appName = app.name, }
appIcon = appIcon, )
appInstalledVersion = app.installedVersion, }
appRemoteVersion = app.remoteVersion, ) { paddingValues ->
onDownloadClick = { ManagerSwipeRefresh(
onAppInstallPress(app.name, app.versions, app.installationOptions) modifier = Modifier
}, .fillMaxSize()
onUninstallClick = { /*TODO*/ }, .padding(paddingValues),
onLaunchClick = { /*TODO*/ }, refreshState = refreshState,
onInfoClick = { onRefresh = { viewModel.fetch() }
showAppInfoDialog = true ) {
ManagerLazyColumn {
managerCategory(homeCategoryApps) {
AnimatedContent(
targetState = appState,
transitionSpec = {
scaleIn(initialScale = 0.9f) + fadeIn() with
scaleOut(targetScale = 0.9f) + fadeOut()
}
) { animatedAppState ->
Column(
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
when (animatedAppState) {
is MainViewModel.AppState.Success -> {
for (app in animatedAppState.apps) {
val appIcon = rememberImagePainter(app.iconUrl) {
diskCachePolicy(CachePolicy.ENABLED)
} }
)
if (showAppInfoDialog) { var showAppInfoDialog by rememberSaveable { mutableStateOf(false) }
ManagerDialog(
title = managerString(R.string.app_info_title, app.name), AppCard(
onDismissRequest = { showAppInfoDialog = false }, appName = app.name,
buttons = { appIcon = appIcon,
ManagerCloseButton(onClick = { appInstalledVersion = app.installedVersion,
showAppInfoDialog = false appRemoteVersion = app.remoteVersion,
}) onAppDownloadClick = {
onAppInstallPress(app.name, app.versions, app.installationOptions)
},
onAppUninstallClick = { /*TODO*/ },
onAppLaunchClick = { /*TODO*/ },
onAppInfoClick = {
showAppInfoDialog = true
}
)
if (showAppInfoDialog) {
ManagerDialog(
title = managerString(R.string.app_info_title, app.name),
onDismissRequest = { showAppInfoDialog = false },
confirmButton = {
TextButton(onClick = {
showAppInfoDialog = false
}) {
ManagerText(text = managerString(R.string.dialog_button_close))
}
},
) {
ManagerText(
modifier = Modifier.padding(top = 4.dp),
text = app.changelog,
//textStyle = MaterialTheme.typography.bodyMedium
)
} }
) {
ManagerText(
modifier = Modifier.padding(top = 4.dp),
text = app.changelog,
textStyle = MaterialTheme.typography.subtitle1
)
} }
} }
} }
} is MainViewModel.AppState.Fetching -> {
is MainViewModel.AppState.Fetching -> { for (i in 0 until animatedAppState.placeholderAppsCount) {
for (i in 0 until animatedAppState.placeholderAppsCount) { AppCardPlaceholder()
AppCardPlaceholder() }
} }
} is MainViewModel.AppState.Error -> {
is MainViewModel.AppState.Error -> {
}
} }
} }
} }
} }
} managerCategory(homeCategorySupportUs) {
CategoryLayout(managerString(R.string.home_category_support_us)) { ScrollableItemRow(
ScrollableItemRow(items = sponsors) { sponsor -> modifier = Modifier
ManagerLinkCard( .fillMaxWidth()
icon = sponsor.icon, .padding(horizontal = DefaultContentPaddingHorizontal),
title = sponsor.title, items = sponsors
link = sponsor.link ) { sponsor ->
) ManagerLinkCard(
icon = sponsor.icon,
title = sponsor.title,
link = sponsor.link
)
}
} }
} managerCategory(homeCategorySocialMedia) {
CategoryLayout( managerString(R.string.home_category_social_media)) { ScrollableItemRow(
ScrollableItemRow(items = socialMedia) { socialMedia -> modifier = Modifier
ManagerLinkCard( .fillMaxWidth()
icon = socialMedia.icon, .padding(horizontal = DefaultContentPaddingHorizontal),
title = socialMedia.title, items = socialMedia
link = socialMedia.link ) { socialMedia ->
) ManagerLinkCard(
icon = socialMedia.icon,
title = socialMedia.title,
link = socialMedia.link
)
}
} }
} }
} }

View File

@ -1,121 +1,144 @@
package com.vanced.manager.ui.screens package com.vanced.manager.ui.screens
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.*
import androidx.compose.foundation.layout.Column import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.lazy.items
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBackIosNew
import androidx.compose.material.icons.rounded.Done import androidx.compose.material.icons.rounded.Done
import androidx.compose.material.icons.rounded.NavigateBefore
import androidx.compose.material.icons.rounded.NavigateNext
import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle import com.vanced.manager.R
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.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import com.vanced.manager.domain.model.InstallationOption import com.vanced.manager.domain.model.InstallationOption
import com.vanced.manager.ui.component.card.ManagerClickableThemedCard import com.vanced.manager.ui.component.card.ManagerTonalCard
import com.vanced.manager.ui.component.layout.ManagerScrollableColumn import com.vanced.manager.ui.component.layout.ManagerLazyColumn
import com.vanced.manager.ui.component.layout.ManagerScaffold
import com.vanced.manager.ui.component.progressindicator.ManagerProgressIndicator
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.component.topappbar.ManagerTopAppBar
import com.vanced.manager.ui.resources.managerString import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.theme.LargeShape
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.DefaultContentPaddingVertical
import com.vanced.manager.ui.widget.list.CheckboxItem import com.vanced.manager.ui.widget.list.CheckboxItem
import com.vanced.manager.ui.widget.list.RadiobuttonItem import com.vanced.manager.ui.widget.list.RadiobuttonItem
@ExperimentalFoundationApi
@ExperimentalAnimationApi
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun InstallPreferencesScreen( fun InstallPreferencesScreen(
installationOptions: List<InstallationOption>, installationOptions: List<InstallationOption>,
onDoneClick: () -> Unit onToolbarBackButtonClick: () -> Unit,
onDoneClick: () -> Unit,
) { ) {
var selectedOptionIndex by rememberSaveable { mutableStateOf(0) } var currentOptionIndex by rememberSaveable { mutableStateOf(0) }
Scaffold( ManagerScaffold(
floatingActionButton = { topBar = {
FloatingActionButton( Column {
onClick = onDoneClick ManagerTopAppBar(
) { title = managerString(R.string.toolbar_installation_preferences),
Icon( navigationIcon = {
imageVector = Icons.Rounded.Done, IconButton(
contentDescription = "Done" onClick = onToolbarBackButtonClick
) {
Icon(
imageVector = Icons.Rounded.ArrowBackIosNew,
contentDescription = "Back"
)
}
}
)
ManagerProgressIndicator(
progress = (currentOptionIndex + 1).toFloat() / installationOptions.size.toFloat()
) )
} }
} },
) { paddingValues -> ) { paddingValues ->
ManagerScrollableColumn( Column(
modifier = Modifier.padding(paddingValues), modifier = Modifier
itemSpacing = DefaultContentPaddingVertical .fillMaxSize()
.padding(paddingValues),
) { ) {
installationOptions.fastForEachIndexed { index, installationOption -> AnimatedContent(
ManagerClickableThemedCard( modifier = Modifier
.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
)
.weight(1f),
targetState = currentOptionIndex,
transitionSpec = {
getSlideAnimationSpec(
if (targetState > initialState) {
AnimatedContentScope.SlideDirection.Start
} else {
AnimatedContentScope.SlideDirection.End
}
)
}
) { optionIndex ->
val installationOption = installationOptions[optionIndex]
ManagerTonalCard(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .wrapContentHeight(
.padding(horizontal = DefaultContentPaddingHorizontal), align = Alignment.Top
onClick = { ),
selectedOptionIndex = index shape = LargeShape
}
) { ) {
Column( Column {
modifier = Modifier.padding(12.dp)
) {
ManagerText( ManagerText(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
text = managerString(installationOption.itemTitleId), text = managerString(installationOption.itemTitleId),
textStyle = TextStyle( textStyle = MaterialTheme.typography.titleLarge,
fontSize = 20.sp,
fontWeight = FontWeight.SemiBold
),
textAlign = TextAlign.Center
) )
AnimatedVisibility( ManagerLazyColumn {
visible = index == selectedOptionIndex when (installationOption) {
) { is InstallationOption.MultiSelect -> {
ManagerScrollableColumn( items(installationOption.items) { item ->
modifier = Modifier.sizeIn( val preference = installationOption.getOption()
maxHeight = 400.dp CheckboxItem(
) modifier = Modifier.fillMaxWidth(),
) { text = item.displayText(item.key),
when (installationOption) { isChecked = preference.contains(item.key),
is InstallationOption.MultiSelect -> { onCheck = {
installationOption.items.fastForEach { item -> if (it) {
val preference = installationOption.getOption() installationOption.addOption(item.key)
CheckboxItem( } else {
modifier = Modifier.fillMaxWidth(), installationOption.removeOption(item.key)
text = item.displayText(item.key),
isChecked = preference.contains(item.key),
onCheck = {
if (it) {
installationOption.addOption(item.key)
} else {
installationOption.removeOption(item.key)
}
} }
) }
} )
} }
is InstallationOption.SingleSelect -> { }
installationOption.items.fastForEach { item -> is InstallationOption.SingleSelect -> {
val preference = installationOption.getOption() items(installationOption.items) { item ->
RadiobuttonItem( val preference = installationOption.getOption()
modifier = Modifier.fillMaxWidth(), RadiobuttonItem(
text = item.displayText(item.key), modifier = Modifier.fillMaxWidth(),
isSelected = preference == item.key, text = item.displayText(item.key),
onSelect = { isSelected = preference == item.key,
installationOption.setOption(item.key) onSelect = {
}, installationOption.setOption(item.key)
tag = item.key },
) tag = item.key
} )
} }
} }
} }
@ -123,8 +146,80 @@ fun InstallPreferencesScreen(
} }
} }
} }
Row(
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
) {
AnimatedVisibility(
visible = currentOptionIndex > 0
) {
FloatingActionButton(
onClick = {
currentOptionIndex--
}
) {
Icon(
imageVector = Icons.Rounded.NavigateBefore,
contentDescription = "Back"
)
}
}
Spacer(modifier = Modifier.weight(1f))
AnimatedContent(
targetState = currentOptionIndex == installationOptions.lastIndex,
transitionSpec = {
getSlideAnimationSpec(
if (initialState && !targetState) {
AnimatedContentScope.SlideDirection.Up
} else {
AnimatedContentScope.SlideDirection.Down
}
)
}
) { lastIndex ->
if (lastIndex) {
FloatingActionButton(
onClick = onDoneClick
) {
Icon(
imageVector = Icons.Rounded.Done,
contentDescription = "Done"
)
}
} else {
FloatingActionButton(
onClick = {
currentOptionIndex++
}
) {
Icon(
imageVector = Icons.Rounded.NavigateNext,
contentDescription = "Next"
)
}
}
}
}
} }
} }
}
@ExperimentalAnimationApi
} private fun <S> AnimatedContentScope<S>.getSlideAnimationSpec(
slideDirection: AnimatedContentScope.SlideDirection
) = slideIntoContainer(
towards = slideDirection,
animationSpec = tween(400)
) + fadeIn(
animationSpec = tween(400)
) with slideOutOfContainer(
towards = slideDirection,
animationSpec = tween(400)
) + fadeOut(
animationSpec = tween(400)
)

View File

@ -5,33 +5,37 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowDropDown import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.vanced.manager.R
import com.vanced.manager.ui.component.layout.ManagerLazyColumn import com.vanced.manager.ui.component.layout.ManagerLazyColumn
import com.vanced.manager.ui.component.layout.ManagerScaffold
import com.vanced.manager.ui.component.modifier.managerClickable import com.vanced.manager.ui.component.modifier.managerClickable
import com.vanced.manager.ui.component.progressindicator.ManagerProgressIndicator import com.vanced.manager.ui.component.progressindicator.ManagerProgressIndicator
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.component.topappbar.ManagerTopAppBar
import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical
import com.vanced.manager.ui.viewmodel.InstallViewModel import com.vanced.manager.ui.viewmodel.InstallViewModel
import org.koin.androidx.compose.getViewModel import org.koin.androidx.compose.getViewModel
@OptIn(ExperimentalFoundationApi::class) @OptIn(
ExperimentalFoundationApi::class,
ExperimentalMaterial3Api::class
)
@Composable @Composable
fun InstallScreen( fun InstallScreen(
appName: String, appName: String,
@ -41,18 +45,12 @@ fun InstallScreen(
viewModel.startAppProcess(appName, appVersions) viewModel.startAppProcess(appName, appVersions)
Scaffold( ManagerScaffold(
floatingActionButton = { topBar = {
Column {
} ManagerTopAppBar(
) { paddingValues -> title = managerString(R.string.toolbar_install),
ManagerLazyColumn( )
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues),
contentPadding = PaddingValues(0.dp),
) {
stickyHeader {
when (val status = viewModel.status) { when (val status = viewModel.status) {
is InstallViewModel.Status.Progress -> { is InstallViewModel.Status.Progress -> {
ManagerProgressIndicator(status.progress) ManagerProgressIndicator(status.progress)
@ -63,11 +61,16 @@ fun InstallScreen(
else -> {} else -> {}
} }
} }
},
floatingActionButton = {
item { }
Spacer(Modifier.height(DefaultContentPaddingVertical)) ) { paddingValues ->
} ManagerLazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues),
) {
items(viewModel.logs) { log -> items(viewModel.logs) { log ->
when (log) { when (log) {
is InstallViewModel.Log.Success -> { is InstallViewModel.Log.Success -> {
@ -79,7 +82,7 @@ fun InstallScreen(
textStyle = TextStyle( textStyle = TextStyle(
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 14.sp, fontSize = 14.sp,
color = Color.Blue color = MaterialTheme.colorScheme.tertiary
), ),
) )
} }
@ -92,7 +95,7 @@ fun InstallScreen(
textStyle = TextStyle( textStyle = TextStyle(
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
fontSize = 14.sp, fontSize = 14.sp,
color = Color.Black color = MaterialTheme.colorScheme.onSurface
), ),
) )
} }
@ -114,7 +117,7 @@ fun InstallScreen(
) { ) {
ManagerText( ManagerText(
text = buildAnnotatedString { text = buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.error)) { withStyle(SpanStyle(color = MaterialTheme.colorScheme.error)) {
append(log.displayText) append(log.displayText)
} }
}, },
@ -127,7 +130,7 @@ fun InstallScreen(
modifier = Modifier.rotate(iconRotation), modifier = Modifier.rotate(iconRotation),
imageVector = Icons.Rounded.ArrowDropDown, imageVector = Icons.Rounded.ArrowDropDown,
contentDescription = "expand", contentDescription = "expand",
tint = MaterialTheme.colors.error tint = MaterialTheme.colorScheme.error
) )
} }
AnimatedVisibility(visible) { AnimatedVisibility(visible) {
@ -136,7 +139,7 @@ fun InstallScreen(
textStyle = TextStyle( textStyle = TextStyle(
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 14.sp, fontSize = 14.sp,
color = MaterialTheme.colors.error.copy(alpha = 0.7f) color = MaterialTheme.colorScheme.error.copy(alpha = 0.7f)
), ),
) )
} }

View File

@ -1,41 +0,0 @@
package com.vanced.manager.ui.screens
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.items
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Share
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.component.color.managerSurfaceColor
import com.vanced.manager.ui.component.layout.ManagerLazyColumn
import com.vanced.manager.core.util.logs
@Composable
fun LogLayout() {
Scaffold(
modifier = Modifier.fillMaxSize(),
floatingActionButton = {
FloatingActionButton(
onClick = { /*TODO*/ },
backgroundColor = managerAccentColor()
) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = "share"
)
}
},
backgroundColor = managerSurfaceColor()
) {
ManagerLazyColumn {
items(logs) { log ->
Text(text = log.body)
}
}
}
}

View File

@ -1,37 +1,59 @@
package com.vanced.manager.ui.screens package com.vanced.manager.ui.screens
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBackIosNew
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp import androidx.compose.ui.Modifier
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.ui.component.layout.ManagerScrollableColumn import com.vanced.manager.ui.component.layout.ManagerLazyColumn
import com.vanced.manager.ui.component.topappbar.ManagerTopAppBar
import com.vanced.manager.ui.resources.managerString import com.vanced.manager.ui.resources.managerString
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.Screen
import com.vanced.manager.ui.widget.layout.SettingsCategoryLayout import com.vanced.manager.ui.widget.layout.managerCategory
import com.vanced.manager.ui.widget.screens.settings.* import com.vanced.manager.ui.widget.screens.settings.*
@ExperimentalMaterial3Api
@Composable @Composable
fun SettingsLayout() { fun SettingsLayout(
ManagerScrollableColumn( onToolbarBackButtonClick: () -> Unit,
contentPaddingVertical = DefaultContentPaddingVertical, ) {
itemSpacing = 12.dp val settingsCategoryBehaviour = managerString(R.string.settings_category_behaviour)
) { val settingsCategoryApperance = managerString(R.string.settings_category_appearance)
SettingsCategoryLayout(
categoryName = managerString( Scaffold(
stringId = R.string.settings_category_behaviour modifier = Modifier.fillMaxSize(),
topBar = {
ManagerTopAppBar(
title = managerString(Screen.Settings.displayName),
navigationIcon = {
IconButton(onClick = onToolbarBackButtonClick) {
Icon(
imageVector = Icons.Rounded.ArrowBackIosNew,
contentDescription = "Back"
)
}
}
) )
) {
SettingsCustomTabsItem()
SettingsNotificationsItem()
SettingsManagerVariantItem()
} }
SettingsCategoryLayout( ) { paddingValues ->
categoryName = managerString( ManagerLazyColumn(
stringId = R.string.settings_category_appearance modifier = Modifier.fillMaxSize().padding(paddingValues),
)
) { ) {
SettingsAccentColorItem() managerCategory(settingsCategoryBehaviour) {
ThemeSettingsItem() SettingsCustomTabsItem()
SettingsNotificationsItem()
SettingsManagerVariantItem()
}
managerCategory(settingsCategoryApperance) {
SettingsAccentColorItem()
ThemeSettingsItem()
}
} }
} }
} }

View File

@ -9,4 +9,59 @@ val darkSurface = Color.Black
val darkOnSurface = Color(0xFFD5D5D5) val darkOnSurface = Color(0xFFD5D5D5)
val lightSurface = Color.White val lightSurface = Color.White
val lightOnSurface = Color.Black val lightOnSurface = Color.Black
val md_theme_light_primary = Color(0xFF0054d9)
val md_theme_light_onPrimary = Color(0xFFffffff)
val md_theme_light_primaryContainer = Color(0xFFdae2ff)
val md_theme_light_onPrimaryContainer = Color(0xFF00174a)
val md_theme_light_secondary = Color(0xFFc00020)
val md_theme_light_onSecondary = Color(0xFFffffff)
val md_theme_light_secondaryContainer = Color(0xFFffdad6)
val md_theme_light_onSecondaryContainer = Color(0xFF410005)
val md_theme_light_tertiary = Color(0xFF943896)
val md_theme_light_onTertiary = Color(0xFFffffff)
val md_theme_light_tertiaryContainer = Color(0xFFffd6fa)
val md_theme_light_onTertiaryContainer = Color(0xFF37003c)
val md_theme_light_error = Color(0xFFba1b1b)
val md_theme_light_errorContainer = Color(0xFFffdad4)
val md_theme_light_onError = Color(0xFFffffff)
val md_theme_light_onErrorContainer = Color(0xFF410001)
val md_theme_light_background = Color(0xFFfefbff)
val md_theme_light_onBackground = Color(0xFF1b1b1e)
val md_theme_light_surface = Color(0xFFfefbff)
val md_theme_light_onSurface = Color(0xFF1b1b1e)
val md_theme_light_surfaceVariant = Color(0xFFe2e2ec)
val md_theme_light_onSurfaceVariant = Color(0xFF44464e)
val md_theme_light_outline = Color(0xFF75767f)
val md_theme_light_inverseOnSurface = Color(0xFFf2f0f5)
val md_theme_light_inverseSurface = Color(0xFF303033)
val md_theme_dark_primary = Color(0xFFb1c5ff)
val md_theme_dark_onPrimary = Color(0xFF002a77)
val md_theme_dark_primaryContainer = Color(0xFF003ea6)
val md_theme_dark_onPrimaryContainer = Color(0xFFdae2ff)
val md_theme_dark_secondary = Color(0xFFffb3af)
val md_theme_dark_onSecondary = Color(0xFF69000c)
val md_theme_dark_secondaryContainer = Color(0xFF920016)
val md_theme_dark_onSecondaryContainer = Color(0xFFffdad6)
val md_theme_dark_tertiary = Color(0xFFffa9fc)
val md_theme_dark_onTertiary = Color(0xFF5a0061)
val md_theme_dark_tertiaryContainer = Color(0xFF781c7c)
val md_theme_dark_onTertiaryContainer = Color(0xFFffd6fa)
val md_theme_dark_error = Color(0xFFffb4a9)
val md_theme_dark_errorContainer = Color(0xFF930006)
val md_theme_dark_onError = Color(0xFF680003)
val md_theme_dark_onErrorContainer = Color(0xFFffdad4)
val md_theme_dark_background = Color(0xFF1b1b1e)
val md_theme_dark_onBackground = Color(0xFFe3e1e6)
val md_theme_dark_surface = Color(0xFF1b1b1e)
val md_theme_dark_onSurface = Color(0xFFe3e1e6)
val md_theme_dark_surfaceVariant = Color(0xFF44464e)
val md_theme_dark_onSurfaceVariant = Color(0xFFc6c6d0)
val md_theme_dark_outline = Color(0xFF8f909a)
val md_theme_dark_inverseOnSurface = Color(0xFF1b1b1e)
val md_theme_dark_inverseSurface = Color(0xFFe3e1e6)
val seed = Color(0xFF2e73ff)
val error = Color(0xFFba1b1b)

View File

@ -1,11 +1,9 @@
package com.vanced.manager.ui.theme package com.vanced.manager.ui.theme
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Shapes
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
val shapes = Shapes( //TODO M3 doesn't support Shapes yet
small = RoundedCornerShape(8.dp), val SmallShape = RoundedCornerShape(8.dp)
medium = RoundedCornerShape(12.dp), val MediumShape = RoundedCornerShape(12.dp)
large = RoundedCornerShape(8.dp) val LargeShape = RoundedCornerShape(16.dp)
)

View File

@ -1,26 +1,74 @@
package com.vanced.manager.ui.theme package com.vanced.manager.ui.theme
import android.annotation.SuppressLint
import android.os.Build
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.gestures.LocalOverScrollConfiguration
import androidx.compose.foundation.gestures.OverScrollConfiguration
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.MaterialTheme import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material.darkColors import androidx.compose.material3.*
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import com.vanced.manager.core.preferences.holder.managerThemePref import com.vanced.manager.core.preferences.holder.managerThemePref
const val defAccentColor = 0xFF0477E1 const val defAccentColor = 0xFF0477E1
private val DarkColorPalette = darkColors( private val LightThemeColors = lightColorScheme(
primary = primaryColor, primary = md_theme_light_primary,
primaryVariant = primaryColorVariant, onPrimary = md_theme_light_onPrimary,
surface = darkSurface, primaryContainer = md_theme_light_primaryContainer,
onSurface = darkOnSurface onPrimaryContainer = md_theme_light_onPrimaryContainer,
secondary = md_theme_light_secondary,
onSecondary = md_theme_light_onSecondary,
secondaryContainer = md_theme_light_secondaryContainer,
onSecondaryContainer = md_theme_light_onSecondaryContainer,
tertiary = md_theme_light_tertiary,
onTertiary = md_theme_light_onTertiary,
tertiaryContainer = md_theme_light_tertiaryContainer,
onTertiaryContainer = md_theme_light_onTertiaryContainer,
error = md_theme_light_error,
errorContainer = md_theme_light_errorContainer,
onError = md_theme_light_onError,
onErrorContainer = md_theme_light_onErrorContainer,
background = md_theme_light_background,
onBackground = md_theme_light_onBackground,
surface = md_theme_light_surface,
onSurface = md_theme_light_onSurface,
surfaceVariant = md_theme_light_surfaceVariant,
onSurfaceVariant = md_theme_light_onSurfaceVariant,
outline = md_theme_light_outline,
inverseOnSurface = md_theme_light_inverseOnSurface,
inverseSurface = md_theme_light_inverseSurface,
) )
private val DarkThemeColors = darkColorScheme(
private val LightColorPalette = lightColors( primary = md_theme_dark_primary,
primary = primaryColor, onPrimary = md_theme_dark_onPrimary,
primaryVariant = primaryColorVariant, primaryContainer = md_theme_dark_primaryContainer,
surface = lightSurface, onPrimaryContainer = md_theme_dark_onPrimaryContainer,
onSurface = lightOnSurface, secondary = md_theme_dark_secondary,
onSecondary = md_theme_dark_onSecondary,
secondaryContainer = md_theme_dark_secondaryContainer,
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
tertiary = md_theme_dark_tertiary,
onTertiary = md_theme_dark_onTertiary,
tertiaryContainer = md_theme_dark_tertiaryContainer,
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
error = md_theme_dark_error,
errorContainer = md_theme_dark_errorContainer,
onError = md_theme_dark_onError,
onErrorContainer = md_theme_dark_onErrorContainer,
background = md_theme_dark_background,
onBackground = md_theme_dark_onBackground,
surface = md_theme_dark_surface,
onSurface = md_theme_dark_onSurface,
surfaceVariant = md_theme_dark_surfaceVariant,
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
outline = md_theme_dark_outline,
inverseOnSurface = md_theme_dark_inverseOnSurface,
inverseSurface = md_theme_dark_inverseSurface,
) )
@Composable @Composable
@ -31,16 +79,41 @@ fun isDark(): Boolean = when (managerThemePref.value.value) {
else -> throw IllegalArgumentException("Unknown theme") else -> throw IllegalArgumentException("Unknown theme")
} }
@SuppressLint("NewApi")
@ExperimentalFoundationApi
@Composable @Composable
fun ManagerTheme( fun ManagerTheme(
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
val colors = if (isDark()) DarkColorPalette else LightColorPalette val isAndroid12OrHigher = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colorScheme =
if (isAndroid12OrHigher) {
val context = LocalContext.current
if (isDark()) {
dynamicDarkColorScheme(context)
} else {
dynamicLightColorScheme(context)
}
} else {
if (isDark()) {
DarkThemeColors
} else {
LightThemeColors
}
}
MaterialTheme( MaterialTheme(
colors = colors, colorScheme = colorScheme,
typography = typography, typography = ManagerTypography,
shapes = shapes, ) {
content = content val rippleIndication = rememberRipple()
) CompositionLocalProvider(
LocalIndication provides rippleIndication,
LocalOverScrollConfiguration provides OverScrollConfiguration(
forceShowAlways = isAndroid12OrHigher
)
) {
content()
}
}
} }

View File

@ -1,6 +1,6 @@
package com.vanced.manager.ui.theme package com.vanced.manager.ui.theme
import androidx.compose.material.Typography import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
@ -14,45 +14,112 @@ private val medium = Font(R.font.inter_medium, FontWeight.Medium)
private val semibold = Font(R.font.inter_semibold, FontWeight.SemiBold) private val semibold = Font(R.font.inter_semibold, FontWeight.SemiBold)
private val bold = Font(R.font.inter_bold, FontWeight.Bold) private val bold = Font(R.font.inter_bold, FontWeight.Bold)
private val interFontFamily = FontFamily(light, regular, medium, semibold, bold) private val InterFontFamily = FontFamily(light, regular, medium, semibold, bold)
// Set of Material typography styles to start with val ManagerTypography = Typography(
val typography = Typography( displayLarge = TextStyle(
defaultFontFamily = interFontFamily, fontFamily = InterFontFamily,
h1 = TextStyle(
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
),
h2 = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.SemiBold
),
h5 = TextStyle(
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
),
h6 = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Bold
),
body1 = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 12.sp
),
body2 = TextStyle(
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 10.sp, fontSize = 57.sp,
lineHeight = 64.sp,
letterSpacing = (-0.25).sp,
), ),
subtitle1 = TextStyle( displayMedium = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Normal,
fontSize = 45.sp,
lineHeight = 52.sp,
letterSpacing = 0.sp,
),
displaySmall = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Normal,
fontSize = 36.sp,
lineHeight = 44.sp,
letterSpacing = 0.sp,
),
headlineLarge = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Bold,
fontSize = 32.sp,
lineHeight = 40.sp,
letterSpacing = 0.sp,
),
headlineMedium = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Bold,
fontSize = 28.sp,
lineHeight = 36.sp,
letterSpacing = 0.sp,
),
headlineSmall = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.SemiBold,
fontSize = 24.sp,
lineHeight = 32.sp,
letterSpacing = 0.sp,
),
titleLarge = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.SemiBold,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp,
),
titleMedium = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
lineHeight = 24.sp,
letterSpacing = 0.1.sp,
),
titleSmall = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.SemiBold,
fontSize = 16.sp,
lineHeight = 20.sp,
letterSpacing = 0.1.sp,
),
bodyLarge = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp,
),
bodyMedium = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
lineHeight = 20.sp,
letterSpacing = 0.25.sp,
),
bodySmall = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 12.sp, fontSize = 12.sp,
lineHeight = 14.sp,
letterSpacing = 0.sp,
), ),
subtitle2 = TextStyle( labelLarge = TextStyle(
fontWeight = FontWeight.Normal, fontFamily = InterFontFamily,
fontSize = 14.sp fontWeight = FontWeight.SemiBold,
),
button = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium lineHeight = 20.sp,
) letterSpacing = 0.1.sp,
),
labelMedium = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Medium,
fontSize = 12.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp,
),
labelSmall = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp,
),
) )

View File

@ -1,13 +1,8 @@
package com.vanced.manager.ui.util package com.vanced.manager.ui.util
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.domain.model.InstallationOption import com.vanced.manager.domain.model.InstallationOption
import com.vanced.manager.ui.screens.AboutLayout
import com.vanced.manager.ui.screens.HomeLayout
import com.vanced.manager.ui.screens.LogLayout
import com.vanced.manager.ui.screens.SettingsLayout
sealed class Screen( sealed class Screen(
val route: String, val route: String,

View File

@ -3,13 +3,10 @@ package com.vanced.manager.ui.viewmodel
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vanced.manager.core.downloader.base.AppDownloader
import com.vanced.manager.core.downloader.util.DownloadStatus
import com.vanced.manager.domain.model.App
import com.vanced.manager.core.preferences.holder.managerVariantPref import com.vanced.manager.core.preferences.holder.managerVariantPref
import com.vanced.manager.core.preferences.holder.musicEnabled import com.vanced.manager.core.preferences.holder.musicEnabled
import com.vanced.manager.core.preferences.holder.vancedEnabled import com.vanced.manager.core.preferences.holder.vancedEnabled
import com.vanced.manager.domain.model.App
import com.vanced.manager.repository.JsonRepository import com.vanced.manager.repository.JsonRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -34,7 +31,7 @@ class MainViewModel(
val appState: StateFlow<AppState> = _appState val appState: StateFlow<AppState> = _appState
fun fetch() { fun fetch() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch {
val vancedEnabled = vancedEnabled.value.value val vancedEnabled = vancedEnabled.value.value
val musicEnabled = musicEnabled.value.value val musicEnabled = musicEnabled.value.value
val isNonroot = managerVariantPref.value.value == "nonroot" val isNonroot = managerVariantPref.value.value == "nonroot"

View File

@ -4,19 +4,22 @@ import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.rounded.DeleteForever import androidx.compose.material.icons.rounded.DeleteForever
import androidx.compose.material.icons.rounded.Download import androidx.compose.material.icons.rounded.Download
import androidx.compose.material.icons.rounded.Launch import androidx.compose.material.icons.rounded.Launch
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil.compose.ImagePainter import coil.compose.ImagePainter
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.ui.component.button.IconButton import com.vanced.manager.ui.component.button.ManagerIconButton
import com.vanced.manager.ui.component.text.AppVersionText import com.vanced.manager.ui.component.text.AppVersionText
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
@ -27,17 +30,17 @@ fun AppCard(
appIcon: ImagePainter, appIcon: ImagePainter,
appInstalledVersion: String?, appInstalledVersion: String?,
appRemoteVersion: String?, appRemoteVersion: String?,
onDownloadClick: () -> Unit, onAppDownloadClick: () -> Unit,
onUninstallClick: () -> Unit, onAppUninstallClick: () -> Unit,
onLaunchClick: () -> Unit, onAppLaunchClick: () -> Unit,
onInfoClick: () -> Unit, onAppInfoClick: () -> Unit,
) { ) {
BaseAppCard( BaseAppCard(
appTitle = { appTitle = {
ManagerText( ManagerText(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
text = appName, text = appName,
textStyle = MaterialTheme.typography.h5 textStyle = MaterialTheme.typography.titleMedium
) )
}, },
appIcon = { appIcon = {
@ -47,6 +50,14 @@ fun AppCard(
contentDescription = "App Icon", contentDescription = "App Icon",
) )
}, },
appTrailing = {
IconButton(onClick = onAppInfoClick) {
Icon(
imageVector = Icons.Outlined.Info,
contentDescription = "App Info"
)
}
},
appVersionsColumn = { appVersionsColumn = {
AppVersionText( AppVersionText(
text = stringResource( text = stringResource(
@ -66,26 +77,24 @@ fun AppCard(
) )
}, },
appActionsRow = { appActionsRow = {
IconButton( IconButton(onClick = onAppUninstallClick) {
icon = Icons.Outlined.Info, Icon(
contentDescription = "App Info", imageVector = Icons.Rounded.DeleteForever,
onClick = onInfoClick contentDescription = "Uninstall"
) )
IconButton( }
icon = Icons.Rounded.DeleteForever, IconButton(onClick = onAppLaunchClick) {
contentDescription = "Uninstall", Icon(
onClick = onUninstallClick imageVector = Icons.Rounded.Launch,
) contentDescription = "Launch",
IconButton( )
icon = Icons.Rounded.Launch, }
contentDescription = "Launch", IconButton(onClick = onAppDownloadClick) {
onClick = onLaunchClick Icon(
) imageVector = Icons.Rounded.Download,
IconButton( contentDescription = "Install",
icon = Icons.Rounded.Download, )
contentDescription = "Install", }
onClick = onDownloadClick
)
} }
) )
} }

View File

@ -1,7 +1,12 @@
package com.vanced.manager.ui.widget.app package com.vanced.manager.ui.widget.app
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.material.MaterialTheme import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -9,6 +14,8 @@ import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.component.modifier.managerPlaceholder import com.vanced.manager.ui.component.modifier.managerPlaceholder
import com.vanced.manager.ui.component.text.AppVersionText import com.vanced.manager.ui.component.text.AppVersionText
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.theme.MediumShape
import com.vanced.manager.ui.theme.SmallShape
@Composable @Composable
fun AppCardPlaceholder() { fun AppCardPlaceholder() {
@ -16,38 +23,46 @@ fun AppCardPlaceholder() {
appTitle = { appTitle = {
ManagerText( ManagerText(
modifier = Modifier modifier = Modifier
.clip(MaterialTheme.shapes.medium) .clip(MediumShape)
.managerPlaceholder(true), .managerPlaceholder(true),
text = " ".repeat(40), text = " ".repeat(40),
textStyle = MaterialTheme.typography.h5 textStyle = MaterialTheme.typography.titleMedium
) )
}, },
appIcon = { appIcon = {
Box( Box(
Modifier Modifier
.clip(MaterialTheme.shapes.medium) .clip(MediumShape)
.managerPlaceholder(true) .managerPlaceholder(true)
.size(48.dp) .size(48.dp)
) )
}, },
appTrailing = {
Box(
Modifier
.clip(CircleShape)
.managerPlaceholder(true)
.size(24.dp)
)
},
appVersionsColumn = { appVersionsColumn = {
AppVersionText( AppVersionText(
modifier = Modifier modifier = Modifier
.managerPlaceholder(true) .managerPlaceholder(true)
.clip(MaterialTheme.shapes.small), .clip(SmallShape),
text = " ".repeat(30) text = " ".repeat(30)
) )
AppVersionText( AppVersionText(
modifier = Modifier modifier = Modifier
.managerPlaceholder(true) .managerPlaceholder(true)
.clip(MaterialTheme.shapes.small), .clip(SmallShape),
text = " ".repeat(30) text = " ".repeat(30)
) )
}, },
appActionsRow = { appActionsRow = {
Box( Box(
Modifier Modifier
.clip(MaterialTheme.shapes.medium) .clip(MediumShape)
.fillMaxWidth(0.8f) .fillMaxWidth(0.8f)
.height(36.dp) .height(36.dp)
.managerPlaceholder(true) .managerPlaceholder(true)

View File

@ -1,19 +1,21 @@
package com.vanced.manager.ui.widget.app package com.vanced.manager.ui.widget.app
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.LocalContentColor import androidx.compose.material.Divider
import androidx.compose.material.MaterialTheme import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vanced.manager.R import com.vanced.manager.R
import com.vanced.manager.ui.component.card.ManagerCard import com.vanced.manager.ui.component.card.ManagerTonalCard
import com.vanced.manager.ui.component.card.ManagerThemedCard
import com.vanced.manager.ui.component.list.ManagerListItem import com.vanced.manager.ui.component.list.ManagerListItem
import com.vanced.manager.ui.component.text.ManagerText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.theme.LargeShape
import com.vanced.manager.ui.theme.MediumShape
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.DefaultContentPaddingVertical
@ -21,48 +23,59 @@ import com.vanced.manager.ui.util.DefaultContentPaddingVertical
fun BaseAppCard( fun BaseAppCard(
appTitle: @Composable () -> Unit, appTitle: @Composable () -> Unit,
appIcon: @Composable () -> Unit, appIcon: @Composable () -> Unit,
appTrailing: @Composable () -> Unit,
appVersionsColumn: @Composable ColumnScope.() -> Unit, appVersionsColumn: @Composable ColumnScope.() -> Unit,
appActionsRow: @Composable RowScope.() -> Unit, appActionsRow: @Composable RowScope.() -> Unit,
) { ) {
ManagerThemedCard { ManagerTonalCard(
Column { modifier = Modifier.fillMaxWidth(),
ManagerCard { shape = LargeShape,
ManagerListItem( ) {
modifier = Modifier.padding( Column(
horizontal = DefaultContentPaddingHorizontal, modifier = Modifier
vertical = DefaultContentPaddingVertical .fillMaxWidth()
), .padding(
title = appTitle, horizontal = DefaultContentPaddingHorizontal,
icon = appIcon vertical = DefaultContentPaddingVertical
) ),
} verticalArrangement = Arrangement
CompositionLocalProvider( .spacedBy(DefaultContentPaddingVertical)
LocalContentColor provides MaterialTheme.colors.onSurface ) {
ManagerListItem(
modifier = Modifier.fillMaxWidth(),
title = appTitle,
icon = appIcon,
trailing = appTrailing
)
Divider(
modifier = Modifier
.fillMaxWidth()
.clip(MediumShape),
thickness = 2.dp,
color = LocalContentColor.current.copy(alpha = 0.12f)
)
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) { ) {
Row( Column(
modifier = Modifier.padding( modifier = Modifier.wrapContentWidth(),
horizontal = DefaultContentPaddingHorizontal, verticalArrangement = Arrangement.spacedBy(4.dp),
vertical = 8.dp horizontalAlignment = Alignment.Start
),
verticalAlignment = Alignment.CenterVertically,
) { ) {
Column( ManagerText(
modifier = Modifier text = stringResource(id = R.string.app_versions),
.weight(1f) textStyle = MaterialTheme.typography.bodyMedium
.wrapContentWidth(Alignment.Start),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
ManagerText(stringResource(id = R.string.app_versions))
appVersionsColumn()
}
Row(
modifier = Modifier
.weight(1f)
.padding(start = 4.dp)
.wrapContentWidth(Alignment.End),
content = appActionsRow
) )
appVersionsColumn()
} }
Row(
modifier = Modifier.wrapContentWidth(),
content = appActionsRow,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
)
} }
} }
} }

View File

@ -2,7 +2,6 @@ package com.vanced.manager.ui.widget.checkbox
import androidx.compose.animation.core.updateTransition import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -10,12 +9,13 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import com.vanced.manager.ui.component.animation.jumpAnimation import com.vanced.manager.ui.component.animation.jumpAnimation
import com.vanced.manager.ui.component.checkbox.ManagerCheckbox import com.vanced.manager.ui.component.checkbox.ManagerCheckbox
import com.vanced.manager.ui.theme.MediumShape
@Composable @Composable
fun ManagerAnimatedCheckbox( fun ManagerAnimatedCheckbox(
size: Dp, size: Dp,
isChecked: Boolean, isChecked: Boolean,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
onCheckedChange: (isChecked: Boolean) -> Unit, onCheckedChange: (isChecked: Boolean) -> Unit,
) { ) {
val transition = updateTransition( val transition = updateTransition(

View File

@ -1,29 +1,73 @@
package com.vanced.manager.ui.widget.layout package com.vanced.manager.ui.widget.layout
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp import com.vanced.manager.ui.component.color.managerAnimatedColor
import com.vanced.manager.ui.component.text.CategoryTitleText import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical import com.vanced.manager.ui.util.DefaultContentPaddingVertical
@Composable @Composable
fun CategoryLayout( fun CategoryLayout(
categoryName: String, categoryName: String,
contentPaddingHorizontal: Dp = DefaultContentPaddingHorizontal, modifier: Modifier = Modifier,
categoryNameSpacing: Dp = DefaultContentPaddingVertical, content: @Composable ColumnScope.() -> Unit,
content: @Composable () -> Unit,
) { ) {
Column( Column(
modifier = Modifier.fillMaxWidth(), modifier = modifier,
verticalArrangement = Arrangement.spacedBy(categoryNameSpacing), verticalArrangement = Arrangement.spacedBy(DefaultContentPaddingVertical)
) { ) {
CategoryTitleText(text = categoryName) ManagerText(
Box( modifier = Modifier.padding(start = DefaultContentPaddingHorizontal),
modifier = Modifier.padding(horizontal = contentPaddingHorizontal) text = categoryName,
) { textStyle = MaterialTheme.typography.headlineSmall,
content() color = managerAnimatedColor(MaterialTheme.colorScheme.onSurface)
} )
content()
} }
} }
fun <T> LazyListScope.managerCategory(
categoryName: String,
items: List<T>,
itemContent: @Composable (T) -> Unit
) {
item {
ManagerText(
modifier = Modifier.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
text = categoryName,
textStyle = MaterialTheme.typography.headlineSmall,
color = managerAnimatedColor(MaterialTheme.colorScheme.onSurface)
)
}
items(items) { item ->
itemContent(item)
}
}
fun LazyListScope.managerCategory(
categoryName: String,
content: @Composable LazyItemScope.() -> Unit,
) {
item {
ManagerText(
modifier = Modifier
.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
text = categoryName,
textStyle = MaterialTheme.typography.headlineSmall,
color = managerAnimatedColor(MaterialTheme.colorScheme.onSurface)
)
}
item(content = content)
}

View File

@ -11,8 +11,6 @@ fun SettingsCategoryLayout(
) { ) {
CategoryLayout( CategoryLayout(
categoryName = categoryName, categoryName = categoryName,
contentPaddingHorizontal = 0.dp,
categoryNameSpacing = 4.dp
) { ) {
Column { Column {
content() content()

View File

@ -1,7 +1,7 @@
package com.vanced.manager.ui.widget.list package com.vanced.manager.ui.widget.list
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp

View File

@ -1,8 +1,7 @@
package com.vanced.manager.ui.widget.list package com.vanced.manager.ui.widget.list
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp

View File

@ -2,7 +2,6 @@ package com.vanced.manager.ui.widget.radiobutton
import androidx.compose.animation.core.updateTransition import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -10,12 +9,13 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import com.vanced.manager.ui.component.animation.jumpAnimation import com.vanced.manager.ui.component.animation.jumpAnimation
import com.vanced.manager.ui.component.radiobutton.ManagerRadiobutton import com.vanced.manager.ui.component.radiobutton.ManagerRadiobutton
import com.vanced.manager.ui.theme.MediumShape
@Composable @Composable
fun ManagerAnimatedRadiobutton( fun ManagerAnimatedRadiobutton(
size: Dp, size: Dp,
isSelected: Boolean, isSelected: Boolean,
shape: Shape = MaterialTheme.shapes.medium, shape: Shape = MediumShape,
onClick: () -> Unit onClick: () -> Unit
) { ) {
val transition = updateTransition( val transition = updateTransition(

View File

@ -13,29 +13,29 @@ import com.vanced.manager.ui.widget.button.ManagerSaveButton
@Composable @Composable
fun SettingsAccentColorItem() { fun SettingsAccentColorItem() {
var localAccentColor by remember { mutableStateOf(managerAccentColorPref.value.value) } // var localAccentColor by remember { mutableStateOf(managerAccentColorPref.value.value) }
DialogPreference( // DialogPreference(
preferenceTitle = managerString( // preferenceTitle = managerString(
stringId = R.string.settings_preference_accent_color_title // stringId = R.string.settings_preference_accent_color_title
), // ),
preferenceDescription = "#" + Integer.toHexString(localAccentColor.toInt()), // preferenceDescription = "#" + Integer.toHexString(localAccentColor.toInt()),
buttons = { isShown -> // buttons = { isShown ->
ManagerResetButton( // ManagerResetButton(
backgroundColor = Color(localAccentColor) // backgroundColor = Color(localAccentColor)
) { // ) {
isShown.value = false // isShown.value = false
managerAccentColorPref.save(defAccentColor) // managerAccentColorPref.save(defAccentColor)
} // }
ManagerSaveButton( // ManagerSaveButton(
backgroundColor = Color(localAccentColor) // backgroundColor = Color(localAccentColor)
) { // ) {
isShown.value = false // isShown.value = false
managerAccentColorPref.save(localAccentColor) // managerAccentColorPref.save(localAccentColor)
} // }
} // }
) { // ) {
ManagerColorPicker { // ManagerColorPicker {
localAccentColor = it // localAccentColor = it
} // }
} // }
} }