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-extended:$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.ui:ui-tooling:$composeVersion")
implementation("androidx.compose.ui:ui-util:$composeVersion")

View File

@ -7,27 +7,17 @@ import android.content.IntentFilter
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.background
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIos
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 androidx.compose.animation.*
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
import com.github.zsoltk.compose.backpress.BackPressHandler
import com.github.zsoltk.compose.backpress.LocalBackPressHandler
import com.github.zsoltk.compose.router.Router
import com.google.accompanist.systemuicontroller.rememberSystemUiController
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.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.theme.ManagerTheme
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?) {
super.onCreate(savedInstanceState)
setContent {
ManagerTheme {
var isMenuExpanded by remember { mutableStateOf(false) }
var currentScreen by remember { mutableStateOf<Screen>(Screen.Home) }
val surfaceColor = managerSurfaceColor()
val isDark = isDark()
@ -78,98 +69,62 @@ class MainActivity : ComponentActivity() {
LocalBackPressHandler provides backPressHandler
) {
Router<Screen>("VancedManager", Screen.Home) { backStack ->
val screen = backStack.last()
currentScreen = screen
when (val screen = backStack.last()) {
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 = {
TopAppBar(
title = {
ToolbarTitleText(
text = managerString(
stringId = currentScreen.displayName
}
is Screen.InstallPreferences -> {
InstallPreferencesScreen(
installationOptions = screen.appInstallationOptions,
onToolbarBackButtonClick = {
backStack.pop()
},
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
) {
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)
}
}
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.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@ -15,7 +15,7 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
@Composable
fun IconButton(
fun ManagerIconButton(
icon: ImageVector,
contentDescription: String,
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.fillMaxWidth
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.theme.MediumShape
@Composable
fun ManagerThemedButton(
@ -22,16 +22,16 @@ fun ManagerThemedButton(
Button(
modifier = modifier.fillMaxWidth(),
onClick = onClick,
shape = MaterialTheme.shapes.medium,
shape = MediumShape,
colors = ButtonDefaults.buttonColors(
backgroundColor = backgroundColor,
containerColor = backgroundColor,
contentColor =
if (backgroundColor.luminance() > 0.7)
Color.Black
else
Color.White
),
elevation = ButtonDefaults.elevation(0.dp, 0.dp, 0.dp)
elevation = ButtonDefaults.elevatedButtonElevation(0.dp, 0.dp, 0.dp, 0.dp)
) {
content()
}

View File

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

View File

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

View File

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

View File

@ -1,38 +1,37 @@
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.ui.Modifier
import androidx.compose.ui.graphics.Shape
import com.vanced.manager.ui.component.color.managerThemedCardColor
import com.vanced.manager.ui.theme.MediumShape
@Composable
fun ManagerThemedCard(
fun ManagerContainerCard(
modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium,
shape: Shape = MediumShape,
content: @Composable () -> Unit,
) {
ManagerCard(
modifier = modifier,
shape = shape,
backgroundColor = managerThemedCardColor(),
backgroundColor = MaterialTheme.colorScheme.primaryContainer,
content = content
)
}
@Composable
fun ManagerClickableThemedCard(
fun ManagerContainerCard(
modifier: Modifier = Modifier,
shape: Shape = MaterialTheme.shapes.medium,
shape: Shape = MediumShape,
onClick: () -> Unit,
content: @Composable () -> Unit,
) {
ManagerCard(
modifier = modifier,
shape = shape,
backgroundColor = managerThemedCardColor(),
backgroundColor = MaterialTheme.colorScheme.primaryContainer,
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 androidx.compose.foundation.layout.BoxWithConstraints
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.rounded.Close
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.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
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.managerThemedCardColor
import com.vanced.manager.ui.theme.MediumShape
@SuppressLint("UnusedTransitionTargetStateParameter")
@Composable
fun ManagerCheckbox(
modifier: Modifier,
isChecked: Boolean,
shape: Shape = MaterialTheme.shapes.medium,
shape: Shape = MediumShape,
onCheckedChange: (isChecked: Boolean) -> Unit
) {
val cardColor =
managerAnimatedColor(if (isChecked) managerAccentColor() else managerThemedCardColor())
managerAnimatedColor(if (isChecked) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.primaryContainer)
val iconTint =
managerAnimatedColor(if (isChecked) contentColorForColor(cardColor) else managerAccentColor())
managerAnimatedColor(
if (isChecked)
contentColorFor(MaterialTheme.colorScheme.primary)
else
contentColorFor(MaterialTheme.colorScheme.primaryContainer)
)
ManagerCard(
modifier = modifier,

View File

@ -1,6 +1,6 @@
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.CompositionLocalProvider

View File

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

View File

@ -1,13 +1,16 @@
package com.vanced.manager.ui.component.dialog
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.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.vanced.manager.ui.component.card.ManagerCard
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.DefaultContentPaddingVertical
@ -15,45 +18,25 @@ import com.vanced.manager.ui.util.DefaultContentPaddingVertical
fun ManagerDialog(
title: String,
onDismissRequest: () -> Unit,
buttons: @Composable ColumnScope.() -> Unit,
content: @Composable ColumnScope.() -> Unit,
confirmButton: @Composable () -> Unit,
modifier: Modifier = Modifier,
dismissButton: @Composable (() -> Unit)? = null,
icon: @Composable (() -> Unit)? = null,
content: @Composable () -> Unit,
) {
ManagerDialog(
AlertDialog(
modifier = modifier,
title = {
ManagerText(
modifier = Modifier
.fillMaxWidth(),
textStyle = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
text = title
)
},
text = content,
onDismissRequest = onDismissRequest,
buttons = buttons,
content = content
confirmButton = confirmButton,
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.unit.Dp
import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical
@Composable
fun ManagerLazyColumn(
modifier: Modifier = Modifier,
itemSpacing: Dp = 0.dp,
contentPadding: PaddingValues = PaddingValues(12.dp),
content: LazyListScope.() -> Unit
) {
LazyColumn(
modifier = modifier,
contentPadding = contentPadding,
verticalArrangement = Arrangement.spacedBy(itemSpacing),
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.foundation.Canvas
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.SideEffect
import androidx.compose.runtime.getValue
@ -20,7 +20,7 @@ fun ManagerScrim(
val systemUiController = rememberSystemUiController()
val scrimColor = Color.Black.copy(alpha = 0.5f)
val surfaceColor = MaterialTheme.colors.surface
val surfaceColor = MaterialTheme.colorScheme.surface
val isDark = isDark()

View File

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

View File

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

View File

@ -12,11 +12,12 @@ import androidx.compose.ui.unit.dp
@Composable
fun <T> ScrollableItemRow(
items: List<T>,
modifier: Modifier = Modifier,
content: @Composable (T) -> Unit
) {
val state = rememberLazyListState()
LazyRow(
modifier = Modifier.fillMaxWidth(),
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp),
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
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.MaterialTheme
import androidx.compose.material3.MaterialTheme
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.theme.SmallShape
@Composable
fun ManagerDropdownMenuItem(
@ -12,10 +15,11 @@ fun ManagerDropdownMenuItem(
) {
DropdownMenuItem(
onClick = onClick,
modifier = Modifier.clip(SmallShape),
) {
ManagerText(
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.interaction.MutableInteractionSource
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip
import com.vanced.manager.ui.theme.MediumShape
fun Modifier.managerClickable(
onClick: () -> Unit
@ -15,9 +15,7 @@ fun Modifier.managerClickable(
val ripple = rememberRipple()
val interactionSource = remember { MutableInteractionSource() }
return@composed then(
clip(MaterialTheme.shapes.medium)
).then(
then(clip(MediumShape)).then(
clickable(
interactionSource = interactionSource,
onClick = onClick,

View File

@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
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.ManagerPreference
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 kotlinx.coroutines.launch
@ -37,10 +39,8 @@ fun CheckboxDialogPreference(
}
}.sortedBy { it.title }.joinToString(separator = ", ") { it.title },
trailing = trailing,
buttons = { isShown ->
ManagerThemedTextButton(
text = stringResource(id = R.string.dialog_button_save),
modifier = Modifier.fillMaxWidth(),
confirmButton = { isShown ->
TextButton(
onClick = {
coroutineScope.launch {
isShown.value = false
@ -48,8 +48,10 @@ fun CheckboxDialogPreference(
onSave(selectedButtons)
}
}
)
}
) {
ManagerText(stringResource(id = R.string.dialog_button_save))
}
},
) {
LazyColumn(
modifier = Modifier.heightIn(max = 400.dp)

View File

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

View File

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

View File

@ -3,11 +3,15 @@ package com.vanced.manager.ui.component.preference
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.vanced.manager.R
import com.vanced.manager.core.preferences.ManagerPreference
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.list.RadiobuttonItem
import kotlinx.coroutines.launch
@ -27,13 +31,13 @@ fun RadiobuttonDialogPreference(
preferenceTitle = preferenceTitle,
preferenceDescription = buttons.find { it.key == pref }?.title,
trailing = trailing,
buttons = { isShown ->
ManagerSaveButton {
coroutineScope.launch {
isShown.value = false
pref = currentSelection
onSave(currentSelection)
}
confirmButton = { isShown ->
TextButton(onClick = {
isShown.value = false
pref = 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.height
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ProgressIndicatorDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -13,11 +12,12 @@ import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.vanced.manager.ui.component.color.managerAccentColor
import com.vanced.manager.ui.theme.MediumShape
private val progressBarModifier = Modifier.composed {
then(height(5.dp))
.then(fillMaxWidth())
.then(clip(MaterialTheme.shapes.medium))
.then(clip(MediumShape))
}
@Composable

View File

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

View File

@ -1,6 +1,6 @@
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.ui.Modifier
@ -12,6 +12,6 @@ fun AppVersionText(
ManagerText(
modifier = modifier,
text = text,
textStyle = MaterialTheme.typography.body2,
textStyle = MaterialTheme.typography.bodySmall,
)
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,121 +1,144 @@
package com.vanced.manager.ui.screens
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.items
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.NavigateBefore
import androidx.compose.material.icons.rounded.NavigateNext
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
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.R
import com.vanced.manager.domain.model.InstallationOption
import com.vanced.manager.ui.component.card.ManagerClickableThemedCard
import com.vanced.manager.ui.component.layout.ManagerScrollableColumn
import com.vanced.manager.ui.component.card.ManagerTonalCard
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.topappbar.ManagerTopAppBar
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.widget.list.CheckboxItem
import com.vanced.manager.ui.widget.list.RadiobuttonItem
@ExperimentalFoundationApi
@ExperimentalAnimationApi
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun InstallPreferencesScreen(
installationOptions: List<InstallationOption>,
onDoneClick: () -> Unit
onToolbarBackButtonClick: () -> Unit,
onDoneClick: () -> Unit,
) {
var selectedOptionIndex by rememberSaveable { mutableStateOf(0) }
var currentOptionIndex by rememberSaveable { mutableStateOf(0) }
Scaffold(
floatingActionButton = {
FloatingActionButton(
onClick = onDoneClick
) {
Icon(
imageVector = Icons.Rounded.Done,
contentDescription = "Done"
ManagerScaffold(
topBar = {
Column {
ManagerTopAppBar(
title = managerString(R.string.toolbar_installation_preferences),
navigationIcon = {
IconButton(
onClick = onToolbarBackButtonClick
) {
Icon(
imageVector = Icons.Rounded.ArrowBackIosNew,
contentDescription = "Back"
)
}
}
)
ManagerProgressIndicator(
progress = (currentOptionIndex + 1).toFloat() / installationOptions.size.toFloat()
)
}
}
},
) { paddingValues ->
ManagerScrollableColumn(
modifier = Modifier.padding(paddingValues),
itemSpacing = DefaultContentPaddingVertical
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
) {
installationOptions.fastForEachIndexed { index, installationOption ->
ManagerClickableThemedCard(
AnimatedContent(
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
.fillMaxWidth()
.padding(horizontal = DefaultContentPaddingHorizontal),
onClick = {
selectedOptionIndex = index
}
.wrapContentHeight(
align = Alignment.Top
),
shape = LargeShape
) {
Column(
modifier = Modifier.padding(12.dp)
) {
Column {
ManagerText(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
text = managerString(installationOption.itemTitleId),
textStyle = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.SemiBold
),
textAlign = TextAlign.Center
textStyle = MaterialTheme.typography.titleLarge,
)
AnimatedVisibility(
visible = index == selectedOptionIndex
) {
ManagerScrollableColumn(
modifier = Modifier.sizeIn(
maxHeight = 400.dp
)
) {
when (installationOption) {
is InstallationOption.MultiSelect -> {
installationOption.items.fastForEach { item ->
val preference = installationOption.getOption()
CheckboxItem(
modifier = Modifier.fillMaxWidth(),
text = item.displayText(item.key),
isChecked = preference.contains(item.key),
onCheck = {
if (it) {
installationOption.addOption(item.key)
} else {
installationOption.removeOption(item.key)
}
ManagerLazyColumn {
when (installationOption) {
is InstallationOption.MultiSelect -> {
items(installationOption.items) { item ->
val preference = installationOption.getOption()
CheckboxItem(
modifier = Modifier.fillMaxWidth(),
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 ->
val preference = installationOption.getOption()
RadiobuttonItem(
modifier = Modifier.fillMaxWidth(),
text = item.displayText(item.key),
isSelected = preference == item.key,
onSelect = {
installationOption.setOption(item.key)
},
tag = item.key
)
}
}
is InstallationOption.SingleSelect -> {
items(installationOption.items) { item ->
val preference = installationOption.getOption()
RadiobuttonItem(
modifier = Modifier.fillMaxWidth(),
text = item.displayText(item.key),
isSelected = preference == item.key,
onSelect = {
installationOption.setOption(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.layout.*
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.rounded.ArrowDropDown
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
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.ManagerScaffold
import com.vanced.manager.ui.component.modifier.managerClickable
import com.vanced.manager.ui.component.progressindicator.ManagerProgressIndicator
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.DefaultContentPaddingVertical
import com.vanced.manager.ui.viewmodel.InstallViewModel
import org.koin.androidx.compose.getViewModel
@OptIn(ExperimentalFoundationApi::class)
@OptIn(
ExperimentalFoundationApi::class,
ExperimentalMaterial3Api::class
)
@Composable
fun InstallScreen(
appName: String,
@ -41,18 +45,12 @@ fun InstallScreen(
viewModel.startAppProcess(appName, appVersions)
Scaffold(
floatingActionButton = {
}
) { paddingValues ->
ManagerLazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues),
contentPadding = PaddingValues(0.dp),
) {
stickyHeader {
ManagerScaffold(
topBar = {
Column {
ManagerTopAppBar(
title = managerString(R.string.toolbar_install),
)
when (val status = viewModel.status) {
is InstallViewModel.Status.Progress -> {
ManagerProgressIndicator(status.progress)
@ -63,11 +61,16 @@ fun InstallScreen(
else -> {}
}
}
},
floatingActionButton = {
item {
Spacer(Modifier.height(DefaultContentPaddingVertical))
}
}
) { paddingValues ->
ManagerLazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(paddingValues),
) {
items(viewModel.logs) { log ->
when (log) {
is InstallViewModel.Log.Success -> {
@ -79,7 +82,7 @@ fun InstallScreen(
textStyle = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 14.sp,
color = Color.Blue
color = MaterialTheme.colorScheme.tertiary
),
)
}
@ -92,7 +95,7 @@ fun InstallScreen(
textStyle = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 14.sp,
color = Color.Black
color = MaterialTheme.colorScheme.onSurface
),
)
}
@ -114,7 +117,7 @@ fun InstallScreen(
) {
ManagerText(
text = buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.error)) {
withStyle(SpanStyle(color = MaterialTheme.colorScheme.error)) {
append(log.displayText)
}
},
@ -127,7 +130,7 @@ fun InstallScreen(
modifier = Modifier.rotate(iconRotation),
imageVector = Icons.Rounded.ArrowDropDown,
contentDescription = "expand",
tint = MaterialTheme.colors.error
tint = MaterialTheme.colorScheme.error
)
}
AnimatedVisibility(visible) {
@ -136,7 +139,7 @@ fun InstallScreen(
textStyle = TextStyle(
fontWeight = FontWeight.Bold,
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
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.ui.unit.dp
import androidx.compose.ui.Modifier
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.util.DefaultContentPaddingVertical
import com.vanced.manager.ui.widget.layout.SettingsCategoryLayout
import com.vanced.manager.ui.util.Screen
import com.vanced.manager.ui.widget.layout.managerCategory
import com.vanced.manager.ui.widget.screens.settings.*
@ExperimentalMaterial3Api
@Composable
fun SettingsLayout() {
ManagerScrollableColumn(
contentPaddingVertical = DefaultContentPaddingVertical,
itemSpacing = 12.dp
) {
SettingsCategoryLayout(
categoryName = managerString(
stringId = R.string.settings_category_behaviour
fun SettingsLayout(
onToolbarBackButtonClick: () -> Unit,
) {
val settingsCategoryBehaviour = managerString(R.string.settings_category_behaviour)
val settingsCategoryApperance = managerString(R.string.settings_category_appearance)
Scaffold(
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(
categoryName = managerString(
stringId = R.string.settings_category_appearance
)
) { paddingValues ->
ManagerLazyColumn(
modifier = Modifier.fillMaxSize().padding(paddingValues),
) {
SettingsAccentColorItem()
ThemeSettingsItem()
managerCategory(settingsCategoryBehaviour) {
SettingsCustomTabsItem()
SettingsNotificationsItem()
SettingsManagerVariantItem()
}
managerCategory(settingsCategoryApperance) {
SettingsAccentColorItem()
ThemeSettingsItem()
}
}
}
}

View File

@ -9,4 +9,59 @@ val darkSurface = Color.Black
val darkOnSurface = Color(0xFFD5D5D5)
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
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Shapes
import androidx.compose.ui.unit.dp
val shapes = Shapes(
small = RoundedCornerShape(8.dp),
medium = RoundedCornerShape(12.dp),
large = RoundedCornerShape(8.dp)
)
//TODO M3 doesn't support Shapes yet
val SmallShape = RoundedCornerShape(8.dp)
val MediumShape = RoundedCornerShape(12.dp)
val LargeShape = RoundedCornerShape(16.dp)

View File

@ -1,26 +1,74 @@
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.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import com.vanced.manager.core.preferences.holder.managerThemePref
const val defAccentColor = 0xFF0477E1
private val DarkColorPalette = darkColors(
primary = primaryColor,
primaryVariant = primaryColorVariant,
surface = darkSurface,
onSurface = darkOnSurface
private val LightThemeColors = lightColorScheme(
primary = md_theme_light_primary,
onPrimary = md_theme_light_onPrimary,
primaryContainer = md_theme_light_primaryContainer,
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 LightColorPalette = lightColors(
primary = primaryColor,
primaryVariant = primaryColorVariant,
surface = lightSurface,
onSurface = lightOnSurface,
private val DarkThemeColors = darkColorScheme(
primary = md_theme_dark_primary,
onPrimary = md_theme_dark_onPrimary,
primaryContainer = md_theme_dark_primaryContainer,
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
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
@ -31,16 +79,41 @@ fun isDark(): Boolean = when (managerThemePref.value.value) {
else -> throw IllegalArgumentException("Unknown theme")
}
@SuppressLint("NewApi")
@ExperimentalFoundationApi
@Composable
fun ManagerTheme(
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(
colors = colors,
typography = typography,
shapes = shapes,
content = content
)
colorScheme = colorScheme,
typography = ManagerTypography,
) {
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
import androidx.compose.material.Typography
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
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 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 typography = Typography(
defaultFontFamily = 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(
val ManagerTypography = Typography(
displayLarge = TextStyle(
fontFamily = InterFontFamily,
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,
fontSize = 12.sp,
lineHeight = 14.sp,
letterSpacing = 0.sp,
),
subtitle2 = TextStyle(
fontWeight = FontWeight.Normal,
fontSize = 14.sp
),
button = TextStyle(
labelLarge = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.SemiBold,
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
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import com.vanced.manager.R
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(
val route: String,

View File

@ -3,13 +3,10 @@ package com.vanced.manager.ui.viewmodel
import android.util.Log
import androidx.lifecycle.ViewModel
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.musicEnabled
import com.vanced.manager.core.preferences.holder.vancedEnabled
import com.vanced.manager.domain.model.App
import com.vanced.manager.repository.JsonRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
@ -34,7 +31,7 @@ class MainViewModel(
val appState: StateFlow<AppState> = _appState
fun fetch() {
viewModelScope.launch(Dispatchers.IO) {
viewModelScope.launch {
val vancedEnabled = vancedEnabled.value.value
val musicEnabled = musicEnabled.value.value
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.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
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.rounded.DeleteForever
import androidx.compose.material.icons.rounded.Download
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.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import coil.compose.ImagePainter
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.ManagerText
@ -27,17 +30,17 @@ fun AppCard(
appIcon: ImagePainter,
appInstalledVersion: String?,
appRemoteVersion: String?,
onDownloadClick: () -> Unit,
onUninstallClick: () -> Unit,
onLaunchClick: () -> Unit,
onInfoClick: () -> Unit,
onAppDownloadClick: () -> Unit,
onAppUninstallClick: () -> Unit,
onAppLaunchClick: () -> Unit,
onAppInfoClick: () -> Unit,
) {
BaseAppCard(
appTitle = {
ManagerText(
modifier = Modifier.fillMaxSize(),
text = appName,
textStyle = MaterialTheme.typography.h5
textStyle = MaterialTheme.typography.titleMedium
)
},
appIcon = {
@ -47,6 +50,14 @@ fun AppCard(
contentDescription = "App Icon",
)
},
appTrailing = {
IconButton(onClick = onAppInfoClick) {
Icon(
imageVector = Icons.Outlined.Info,
contentDescription = "App Info"
)
}
},
appVersionsColumn = {
AppVersionText(
text = stringResource(
@ -66,26 +77,24 @@ fun AppCard(
)
},
appActionsRow = {
IconButton(
icon = Icons.Outlined.Info,
contentDescription = "App Info",
onClick = onInfoClick
)
IconButton(
icon = Icons.Rounded.DeleteForever,
contentDescription = "Uninstall",
onClick = onUninstallClick
)
IconButton(
icon = Icons.Rounded.Launch,
contentDescription = "Launch",
onClick = onLaunchClick
)
IconButton(
icon = Icons.Rounded.Download,
contentDescription = "Install",
onClick = onDownloadClick
)
IconButton(onClick = onAppUninstallClick) {
Icon(
imageVector = Icons.Rounded.DeleteForever,
contentDescription = "Uninstall"
)
}
IconButton(onClick = onAppLaunchClick) {
Icon(
imageVector = Icons.Rounded.Launch,
contentDescription = "Launch",
)
}
IconButton(onClick = onAppDownloadClick) {
Icon(
imageVector = Icons.Rounded.Download,
contentDescription = "Install",
)
}
}
)
}

View File

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

View File

@ -1,19 +1,21 @@
package com.vanced.manager.ui.widget.app
import androidx.compose.foundation.layout.*
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Divider
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.vanced.manager.R
import com.vanced.manager.ui.component.card.ManagerCard
import com.vanced.manager.ui.component.card.ManagerThemedCard
import com.vanced.manager.ui.component.card.ManagerTonalCard
import com.vanced.manager.ui.component.list.ManagerListItem
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.DefaultContentPaddingVertical
@ -21,48 +23,59 @@ import com.vanced.manager.ui.util.DefaultContentPaddingVertical
fun BaseAppCard(
appTitle: @Composable () -> Unit,
appIcon: @Composable () -> Unit,
appTrailing: @Composable () -> Unit,
appVersionsColumn: @Composable ColumnScope.() -> Unit,
appActionsRow: @Composable RowScope.() -> Unit,
) {
ManagerThemedCard {
Column {
ManagerCard {
ManagerListItem(
modifier = Modifier.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
title = appTitle,
icon = appIcon
)
}
CompositionLocalProvider(
LocalContentColor provides MaterialTheme.colors.onSurface
ManagerTonalCard(
modifier = Modifier.fillMaxWidth(),
shape = LargeShape,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = DefaultContentPaddingVertical
),
verticalArrangement = Arrangement
.spacedBy(DefaultContentPaddingVertical)
) {
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(
modifier = Modifier.padding(
horizontal = DefaultContentPaddingHorizontal,
vertical = 8.dp
),
verticalAlignment = Alignment.CenterVertically,
Column(
modifier = Modifier.wrapContentWidth(),
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalAlignment = Alignment.Start
) {
Column(
modifier = Modifier
.weight(1f)
.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
ManagerText(
text = stringResource(id = R.string.app_versions),
textStyle = MaterialTheme.typography.bodyMedium
)
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.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@ -10,12 +9,13 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import com.vanced.manager.ui.component.animation.jumpAnimation
import com.vanced.manager.ui.component.checkbox.ManagerCheckbox
import com.vanced.manager.ui.theme.MediumShape
@Composable
fun ManagerAnimatedCheckbox(
size: Dp,
isChecked: Boolean,
shape: Shape = MaterialTheme.shapes.medium,
shape: Shape = MediumShape,
onCheckedChange: (isChecked: Boolean) -> Unit,
) {
val transition = updateTransition(

View File

@ -1,29 +1,73 @@
package com.vanced.manager.ui.widget.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.ui.Modifier
import androidx.compose.ui.unit.Dp
import com.vanced.manager.ui.component.text.CategoryTitleText
import com.vanced.manager.ui.component.color.managerAnimatedColor
import com.vanced.manager.ui.component.text.ManagerText
import com.vanced.manager.ui.util.DefaultContentPaddingHorizontal
import com.vanced.manager.ui.util.DefaultContentPaddingVertical
@Composable
fun CategoryLayout(
categoryName: String,
contentPaddingHorizontal: Dp = DefaultContentPaddingHorizontal,
categoryNameSpacing: Dp = DefaultContentPaddingVertical,
content: @Composable () -> Unit,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit,
) {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(categoryNameSpacing),
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(DefaultContentPaddingVertical)
) {
CategoryTitleText(text = categoryName)
Box(
modifier = Modifier.padding(horizontal = contentPaddingHorizontal)
) {
content()
}
ManagerText(
modifier = Modifier.padding(start = DefaultContentPaddingHorizontal),
text = categoryName,
textStyle = MaterialTheme.typography.headlineSmall,
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(
categoryName = categoryName,
contentPaddingHorizontal = 0.dp,
categoryNameSpacing = 4.dp
) {
Column {
content()

View File

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

View File

@ -1,8 +1,7 @@
package com.vanced.manager.ui.widget.list
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
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.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
@ -10,12 +9,13 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import com.vanced.manager.ui.component.animation.jumpAnimation
import com.vanced.manager.ui.component.radiobutton.ManagerRadiobutton
import com.vanced.manager.ui.theme.MediumShape
@Composable
fun ManagerAnimatedRadiobutton(
size: Dp,
isSelected: Boolean,
shape: Shape = MaterialTheme.shapes.medium,
shape: Shape = MediumShape,
onClick: () -> Unit
) {
val transition = updateTransition(

View File

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