diff --git a/GITHUB_CHANGELOG.md b/GITHUB_CHANGELOG.md
index 4e354724ad..7eb78c04c7 100644
--- a/GITHUB_CHANGELOG.md
+++ b/GITHUB_CHANGELOG.md
@@ -16,6 +16,8 @@ older (i.e., Lawnchair `15-dev`).
* Reimplement Hotseat background customisation
* Make haptic on a locked workspace use MSDL vibration
* Make Launcher3 colour more accurate to upstream Android 16
+* ProvideComposeSheetHandler now have expressive blur
+* Lawnchair Settings now uses Material 3 Expressive
#### Fixes
diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml
index 47c3bbbc03..ec1e66c0aa 100644
--- a/lawnchair/res/values/strings.xml
+++ b/lawnchair/res/values/strings.xml
@@ -188,6 +188,12 @@
Experimental features
+ Workspace
+ Smartspace
+
+ Internal
+ Internal may be more unstable than other experimental group
+
Font customization
Some text remains unchanged
@@ -199,6 +205,7 @@
Always reload icons
Avoid using cached icons from icon packs
+ Will cause icon to reload regularly, this is not required if icon pack doesn\'t update regularly
Icon swipe gestures
Perform actions when swiping left or right on icons instead of moving the home screen
@@ -211,6 +218,7 @@
GestureNavContract API
Render launcher animations without root, does not work with heavily modified AOSP
+ GestureNavContract may cause artifacting during animations
Lock/unlock
diff --git a/lawnchair/src/app/lawnchair/LawnchairApp.kt b/lawnchair/src/app/lawnchair/LawnchairApp.kt
index 20909f9f15..14128fa828 100644
--- a/lawnchair/src/app/lawnchair/LawnchairApp.kt
+++ b/lawnchair/src/app/lawnchair/LawnchairApp.kt
@@ -30,6 +30,9 @@ import android.util.Log
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
@@ -233,6 +236,7 @@ class LawnchairApp : Application() {
@JvmStatic
val isAtleastT: Boolean get() = instance.isAtleastT
+ @OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
fun Launcher.showQuickstepWarningIfNecessary() {
val launcher = this
if (!lawnchairApp.isRecentsComponent || isRecentsEnabled) return
@@ -253,12 +257,14 @@ class LawnchairApp : Application() {
openAppInfo(launcher)
close(true)
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = R.string.app_info_drop_target_label))
}
Spacer(modifier = Modifier.requiredWidth(8.dp))
Button(
onClick = { close(true) },
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.ok))
}
diff --git a/lawnchair/src/app/lawnchair/gestures/handlers/SleepGestureHandler.kt b/lawnchair/src/app/lawnchair/gestures/handlers/SleepGestureHandler.kt
index 00fdfdfef7..d9d8013115 100644
--- a/lawnchair/src/app/lawnchair/gestures/handlers/SleepGestureHandler.kt
+++ b/lawnchair/src/app/lawnchair/gestures/handlers/SleepGestureHandler.kt
@@ -29,6 +29,9 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -129,6 +132,7 @@ class SleepMethodDeviceAdmin(context: Context) : SleepGestureHandler.SleepMethod
}
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
@Composable
fun ServiceWarningDialog(
title: Int,
@@ -145,6 +149,7 @@ fun ServiceWarningDialog(
buttons = {
OutlinedButton(
onClick = handleClose,
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.cancel))
}
@@ -154,6 +159,7 @@ fun ServiceWarningDialog(
context.startActivity(settingsIntent)
handleClose()
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = R.string.dt2s_recents_warning_open_settings))
}
diff --git a/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt b/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt
index 77d20e62b0..e10e873b1a 100644
--- a/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt
+++ b/lawnchair/src/app/lawnchair/smartspace/model/SmartspaceCalendar.kt
@@ -27,6 +27,7 @@ sealed class SmartspaceCalendar(@StringRes val nameResourceId: Int, val formatCu
override fun toString() = "gregorian"
}
object Persian : SmartspaceCalendar(nameResourceId = R.string.smartspace_calendar_persian) {
+ // Officially known as Solar Hijri
override fun toString() = "persian"
}
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/about/ChangesDialog.kt b/lawnchair/src/app/lawnchair/ui/preferences/about/ChangesDialog.kt
index da978c72c7..74c37bd6ab 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/about/ChangesDialog.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/about/ChangesDialog.kt
@@ -15,7 +15,9 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
@@ -34,7 +36,7 @@ import com.android.launcher3.R
import java.time.Instant
import java.util.concurrent.TimeUnit
-@OptIn(ExperimentalMaterial3Api::class)
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ChangesDialog(
changelogState: ChangelogState?,
@@ -100,6 +102,7 @@ fun ChangesDialog(
) {
OutlinedButton(
onClick = onDismiss,
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(android.R.string.cancel))
}
@@ -109,6 +112,7 @@ fun ChangesDialog(
onDownload()
onDismiss()
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(R.string.download_update))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/about/UpdateSection.kt b/lawnchair/src/app/lawnchair/ui/preferences/about/UpdateSection.kt
index 247cf14305..f4c8c4d7ae 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/about/UpdateSection.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/about/UpdateSection.kt
@@ -4,7 +4,9 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -16,6 +18,7 @@ import androidx.compose.ui.unit.dp
import com.android.launcher3.R
import java.io.File
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun UpdateSection(
updateState: UpdateState,
@@ -43,6 +46,7 @@ fun UpdateSection(
is UpdateState.Available -> {
Button(
onClick = onViewChanges,
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(R.string.download_update))
}
@@ -64,6 +68,7 @@ fun UpdateSection(
onClick = {
onInstall(updateState.file)
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(R.string.install_update))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/DraggablePreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/DraggablePreference.kt
index 36cf72e93a..11839b1cf4 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/DraggablePreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/DraggablePreference.kt
@@ -9,17 +9,23 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.rounded.DragHandle
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
@@ -203,6 +209,21 @@ fun DraggableSwitchPreference(
checked = checked,
onCheckedChange = onCheckedChange,
enabled = enabled,
+ thumbContent = {
+ if (checked) {
+ Icon(
+ imageVector = Icons.Filled.Check,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ },
)
},
enabled = enabled,
@@ -210,6 +231,7 @@ fun DraggableSwitchPreference(
)
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun DragHandle(
scope: ReorderableScope,
@@ -240,6 +262,7 @@ fun DragHandle(
enabled = isDraggable,
onClick = {},
interactionSource = interactionSource,
+ shapes = IconButtonDefaults.shapes(),
) {
Icon(
imageVector = Icons.Rounded.DragHandle,
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/GestureHandlerPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/GestureHandlerPreference.kt
index 63320dce80..2dc9458772 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/GestureHandlerPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/GestureHandlerPreference.kt
@@ -10,6 +10,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
@@ -49,6 +52,7 @@ val options = listOf(
GestureHandlerOption.OpenAssistant,
)
+@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
@Composable
fun GestureHandlerPreference(
adapter: PreferenceAdapter,
@@ -85,7 +89,10 @@ fun GestureHandlerPreference(
ModalBottomSheetContent(
title = { Text(label) },
buttons = {
- OutlinedButton(onClick = { bottomSheetHandler.hide() }) {
+ OutlinedButton(
+ onClick = { bottomSheetHandler.hide() },
+ shapes = ButtonDefaults.shapes()
+ ) {
Text(text = stringResource(id = AndroidR.string.cancel))
}
},
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/PermissionDialog.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/PermissionDialog.kt
index d149805cae..a04ec0de9e 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/PermissionDialog.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/PermissionDialog.kt
@@ -19,6 +19,8 @@ import androidx.compose.material.icons.rounded.Check
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@@ -55,6 +57,7 @@ import com.google.accompanist.permissions.shouldShowRationale
* @param onGoToSettings Called when the user clicks the "Go to settings" button.
* @param modifier The modifier to be applied to the dialog.
*/
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun PermissionDialog(
title: String,
@@ -76,6 +79,7 @@ fun PermissionDialog(
if (isPermanentlyDenied) onGoToSettings() else onConfirm()
onDismiss()
},
+ shapes = ButtonDefaults.shapes()
) {
Text(
stringResource(
@@ -85,7 +89,10 @@ fun PermissionDialog(
}
},
dismissButton = {
- TextButton(onClick = onDismiss) { Text(stringResource(android.R.string.cancel)) }
+ TextButton(
+ onClick = onDismiss,
+ shapes = ButtonDefaults.shapes()
+ ) { Text(stringResource(android.R.string.cancel)) }
},
)
}
@@ -97,7 +104,7 @@ fun PermissionDialog(
* @param modifier The modifier to be applied to the dialog.
* @param onPermissionRequest Called when a permission request is initiated.
*/
-@OptIn(ExperimentalPermissionsApi::class)
+@OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun WallpaperAccessPermissionDialog(
managedFilesChecked: Boolean,
@@ -119,7 +126,10 @@ fun WallpaperAccessPermissionDialog(
Text(stringResource(R.string.manage_storage_access_denied_description, stringResource(id = R.string.derived_app_name)))
},
confirmButton = {
- FilledTonalButton(onClick = onDismiss) { Text(stringResource(R.string.dismiss)) }
+ FilledTonalButton(
+ onClick = onDismiss,
+ shapes = ButtonDefaults.shapes()
+ ) { Text(stringResource(R.string.dismiss)) }
},
)
} else {
@@ -164,7 +174,10 @@ fun WallpaperAccessPermissionDialog(
}
},
confirmButton = {
- TextButton(onClick = onDismiss) { Text(stringResource(android.R.string.cancel)) }
+ TextButton(
+ onClick = onDismiss,
+ shapes = ButtonDefaults.shapes()
+ ) { Text(stringResource(android.R.string.cancel)) }
},
)
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/WallpaperPreview.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/WallpaperPreview.kt
index 00d3497353..d1f19d3a71 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/WallpaperPreview.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/WallpaperPreview.kt
@@ -14,6 +14,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Wallpaper
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
@@ -41,6 +43,7 @@ import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ColumnScope.WithWallpaper(
modifier: Modifier = Modifier,
@@ -67,6 +70,7 @@ fun ColumnScope.WithWallpaper(
) {
FilledTonalButton(
onClick = { showPermissionDialog = true },
+ shapes = ButtonDefaults.shapes()
) {
Icon(
imageVector = Icons.Rounded.Wallpaper,
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/colorpreference/ColorSelectionPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/colorpreference/ColorSelectionPreference.kt
index f357bef305..92007cb3c4 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/colorpreference/ColorSelectionPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/colorpreference/ColorSelectionPreference.kt
@@ -11,6 +11,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
@@ -34,6 +36,7 @@ import com.android.launcher3.R
import com.patrykmichalik.opto.domain.Preference
import kotlinx.coroutines.launch
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ColorSelection(
label: String,
@@ -84,6 +87,7 @@ fun ColorSelection(
modifier = Modifier
.fillMaxWidth()
.padding(all = 16.dp),
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = R.string.action_apply))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ClickablePreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ClickablePreference.kt
index fc75ffe108..cea526d905 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ClickablePreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ClickablePreference.kt
@@ -20,6 +20,8 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -63,6 +65,7 @@ fun ClickablePreference(
)
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun PreferenceClickConfirmation(
title: String,
@@ -77,6 +80,7 @@ fun PreferenceClickConfirmation(
buttons = {
OutlinedButton(
onClick = onDismissRequest,
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.cancel))
}
@@ -86,6 +90,7 @@ fun PreferenceClickConfirmation(
onDismissRequest()
onConfirm()
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.ok))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ListPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ListPreference.kt
index 5999047131..3af7947741 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ListPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/ListPreference.kt
@@ -22,6 +22,8 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
@@ -58,6 +60,7 @@ fun ListPreference(
)
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ListPreference(
entries: List>,
@@ -89,7 +92,10 @@ fun ListPreference(
ModalBottomSheetContent(
title = { Text(label) },
buttons = {
- OutlinedButton(onClick = { bottomSheetHandler.hide() }) {
+ OutlinedButton(
+ onClick = { bottomSheetHandler.hide() },
+ shapes = ButtonDefaults.shapes()
+ ) {
Text(text = stringResource(id = AndroidR.string.cancel))
}
},
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/MainSwitchPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/MainSwitchPreference.kt
index 1d219cc53e..59c3e59372 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/MainSwitchPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/MainSwitchPreference.kt
@@ -8,9 +8,15 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
@@ -128,6 +134,21 @@ fun MainSwitchPreference(
onCheckedChange = onCheckedChange,
enabled = enabled,
interactionSource = interactionSource,
+ thumbContent = {
+ if (checked) {
+ Icon(
+ imageVector = Icons.Filled.Check,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ },
)
},
enabled = enabled,
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SwitchPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SwitchPreference.kt
index 5a859f520e..5a13eeaa37 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SwitchPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SwitchPreference.kt
@@ -23,8 +23,14 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.Icon
import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
@@ -112,6 +118,21 @@ fun SwitchPreference(
onCheckedChange = onCheckedChange,
enabled = enabled,
interactionSource = interactionSource,
+ thumbContent = {
+ if (checked) {
+ Icon(
+ imageVector = Icons.Filled.Check,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ },
)
},
enabled = enabled,
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/TextPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/TextPreference.kt
index 679bf10306..4d0052764d 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/TextPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/TextPreference.kt
@@ -5,6 +5,8 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
@@ -71,6 +73,7 @@ fun TextPreference(
)
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun TextPreferenceDialog(
title: String,
@@ -94,6 +97,7 @@ fun TextPreferenceDialog(
buttons = {
OutlinedButton(
onClick = onDismissRequest,
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.cancel))
}
@@ -103,6 +107,7 @@ fun TextPreferenceDialog(
onDismissRequest()
onConfirm(value)
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.ok))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/ClickableIcon.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/ClickableIcon.kt
index 7bd790c206..5a92a8ad15 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/ClickableIcon.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/ClickableIcon.kt
@@ -1,8 +1,10 @@
package app.lawnchair.ui.preferences.components.layout
import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.LocalContentColor
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -12,6 +14,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun ClickableIcon(
painter: Painter,
@@ -24,6 +27,7 @@ fun ClickableIcon(
onClick = onClick,
modifier = modifier,
enabled = enabled,
+ shapes = IconButtonDefaults.shapes(),
) {
val contentAlpha = if (enabled) tint.alpha else 0.38f
val alpha by animateFloatAsState(targetValue = contentAlpha, label = "")
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/DividerColumn.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/DividerColumn.kt
index d6b915a975..8e04a84152 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/DividerColumn.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/DividerColumn.kt
@@ -1,5 +1,6 @@
package app.lawnchair.ui.preferences.components.layout
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -14,14 +15,13 @@ import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import app.lawnchair.ui.theme.dividerColor
import kotlin.math.roundToInt
@Composable
fun DividerColumn(
modifier: Modifier = Modifier,
- color: Color = dividerColor(),
- thickness: Dp = 1.dp,
+ color: Color = MaterialTheme.colorScheme.surface,
+ thickness: Dp = 3.dp,
startIndent: Dp = 0.dp,
endIndent: Dp = 0.dp,
dividersToSkip: Int = 0,
@@ -30,8 +30,8 @@ fun DividerColumn(
val state = remember { DividersState() }
val density = LocalDensity.current
val thicknessPx = with(density) { thickness.toPx() }
- val startIndentPx = with(density) { (startIndent + 16.dp).toPx() }
- val endIndentPx = with(density) { (endIndent + 16.dp).toPx() }
+ val startIndentPx = with(density) { (startIndent).toPx() }
+ val endIndentPx = with(density) { (endIndent).toPx() }
Layout(
modifier = modifier
.drawDividers(state, color, thicknessPx, startIndentPx, endIndentPx),
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/LoadingScreen.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/LoadingScreen.kt
index 82e8d2834b..2cc07419a8 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/LoadingScreen.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/LoadingScreen.kt
@@ -20,16 +20,20 @@ import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.ContainedLoadingIndicator
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
/**
- * Creates a simple loading animation with [Crossfade] and [CircularProgressIndicator].
+ * Creates a simple loading animation with [Crossfade] and [ContainedLoadingIndicator].
* @param isLoading Defines whether the content is still loading or not
* @param content Content to appear or disappear based on the value of [isLoading]
*/
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LoadingScreen(
isLoading: Boolean,
@@ -47,7 +51,9 @@ fun LoadingScreen(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
- CircularProgressIndicator()
+ ContainedLoadingIndicator(
+ modifier = Modifier.size(128.dp)
+ )
}
} else {
content()
@@ -56,7 +62,7 @@ fun LoadingScreen(
}
/**
- * Creates a simple loading animation with [Crossfade] and [CircularProgressIndicator]. [obj] will be passed as a parameter of [content].
+ * Creates a simple loading animation with [Crossfade] and [ContainedLoadingIndicator]. [obj] will be passed as a parameter of [content].
* @param obj A key representing the content object
* @param content Content to appear or disappear based on the value of [obj].
*/
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/PreferenceGroup.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/PreferenceGroup.kt
index ed079c94d3..201f4503ee 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/layout/PreferenceGroup.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/layout/PreferenceGroup.kt
@@ -32,9 +32,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import app.lawnchair.ui.theme.dividerColor
import app.lawnchair.ui.theme.preferenceGroupColor
@Composable
@@ -47,7 +47,7 @@ fun PreferenceGroup(
dividerStartIndent: Dp = 0.dp,
dividerEndIndent: Dp = 0.dp,
dividersToSkip: Int = 0,
- dividerColor: Color = dividerColor(),
+ dividerColor: Color = MaterialTheme.colorScheme.surface,
content: @Composable () -> Unit,
) {
Column(
@@ -56,7 +56,7 @@ fun PreferenceGroup(
PreferenceGroupHeading(heading)
Surface(
modifier = Modifier.padding(horizontal = 16.dp),
- shape = MaterialTheme.shapes.large,
+ shape = MaterialTheme.shapes.extraLarge,
color = preferenceGroupColor(),
) {
if (showDividers) {
@@ -93,6 +93,7 @@ fun PreferenceGroupHeading(
Text(
text = heading,
style = MaterialTheme.typography.titleSmall,
+ fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.semantics { this.heading() },
)
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/search/FileSearchProvider.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/search/FileSearchProvider.kt
index 7b0e5cd2cb..2fd22fdd5f 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/search/FileSearchProvider.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/search/FileSearchProvider.kt
@@ -13,11 +13,19 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledTonalButton
+import androidx.compose.material3.Icon
import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.ripple
@@ -208,7 +216,7 @@ private fun ManageExternalStorageSetting(
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
-@OptIn(ExperimentalPermissionsApi::class)
+@OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun VisualMediaSetting(
accessState: FileAccessState,
@@ -283,6 +291,7 @@ private fun VisualMediaSetting(
showPartialAccessDialog = false
},
modifier = Modifier.fillMaxWidth(),
+ shapes = ButtonDefaults.shapes()
) { Text(stringResource(R.string.permissions_photos_videos_grant_full)) }
TextButton(
@@ -291,11 +300,13 @@ private fun VisualMediaSetting(
showPartialAccessDialog = false
},
modifier = Modifier.fillMaxWidth(),
+ shapes = ButtonDefaults.shapes()
) { Text(stringResource(R.string.permissions_photos_videos_manage_selected)) }
TextButton(
onClick = { showPartialAccessDialog = false },
modifier = Modifier.fillMaxWidth(),
+ shapes = ButtonDefaults.shapes()
) { Text(stringResource(android.R.string.cancel)) }
}
},
@@ -403,6 +414,21 @@ internal fun TwoTargetSwitchPreference(
onCheckedChange = onCheckedChange,
enabled = switchEnabled,
interactionSource = interactionSource,
+ thumbContent = {
+ if (checked) {
+ Icon(
+ imageVector = Icons.Filled.Check,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ },
)
},
enabled = enabled,
@@ -422,7 +448,7 @@ internal fun TwoTargetSwitchPreference(
* @param rationale The rationale to show to the user.
* @param onPermissionRequest Called when the permission is requested.
*/
-@OptIn(ExperimentalPermissionsApi::class)
+@OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun FileAccessPermissionDialog(
onDismiss: () -> Unit,
@@ -457,7 +483,10 @@ private fun FileAccessPermissionDialog(
Text(stringResource(R.string.manage_storage_access_denied_description, stringResource(id = R.string.derived_app_name)))
},
confirmButton = {
- FilledTonalButton(onClick = onDismiss) { Text(stringResource(R.string.dismiss)) }
+ FilledTonalButton(
+ onClick = onDismiss,
+ shapes = ButtonDefaults.shapes()
+ ) { Text(stringResource(R.string.dismiss)) }
},
)
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/search/SearchProviderPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/search/SearchProviderPreference.kt
index ac5f1570c2..757e764383 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/search/SearchProviderPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/search/SearchProviderPreference.kt
@@ -10,8 +10,14 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.Icon
import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -101,6 +107,21 @@ fun SearchProviderPreferenceItem(
checked = enabled && adapter.state.value,
onCheckedChange = adapter::onChange,
enabled = enabled,
+ thumbContent = {
+ if (enabled && adapter.state.value) {
+ Icon(
+ imageVector = Icons.Filled.Check,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ },
)
},
applyPaddings = false,
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt
index 5dac9b04ba..f83172000b 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt
@@ -9,6 +9,8 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
@@ -79,6 +81,7 @@ fun WebSearchProvider(
}
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun SearchPopupPreference(
title: String,
@@ -101,6 +104,7 @@ fun SearchPopupPreference(
showPopup = false
onConfirm(value.text)
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.ok))
}
@@ -110,6 +114,7 @@ fun SearchPopupPreference(
onClick = {
showPopup = false
},
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = android.R.string.cancel))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/AppDrawerFoldersPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/AppDrawerFoldersPreference.kt
index 7524da9847..4373eb24bf 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/AppDrawerFoldersPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/AppDrawerFoldersPreference.kt
@@ -13,8 +13,11 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
@@ -246,6 +249,7 @@ fun AppDrawerFoldersPreference(
}
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun FolderEditSheet(
folderInfo: FolderInfo,
@@ -262,6 +266,7 @@ fun FolderEditSheet(
buttons = {
OutlinedButton(
onClick = onDismiss,
+ shapes = ButtonDefaults.shapes()
) {
Text(stringResource(android.R.string.cancel))
}
@@ -271,6 +276,7 @@ fun FolderEditSheet(
onRename(folderInfo, textFieldValue.text)
onDismiss()
},
+ shapes = ButtonDefaults.shapes()
) {
Text(stringResource(android.R.string.ok))
}
@@ -308,6 +314,7 @@ fun FolderEditSheet(
}
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun FolderItem(
folderInfo: FolderInfo,
@@ -338,6 +345,7 @@ fun FolderItem(
onClick = {
onItemDelete(folderInfo)
},
+ shapes = IconButtonDefaults.shapes(),
) {
Icon(Icons.Rounded.Delete, contentDescription = "Delete", tint = MaterialTheme.colorScheme.onSurfaceVariant)
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/CustomIconShapePreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/CustomIconShapePreference.kt
index 202a29c350..438764f7f3 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/CustomIconShapePreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/CustomIconShapePreference.kt
@@ -17,6 +17,8 @@ import androidx.compose.material.icons.rounded.ArrowDropDown
import androidx.compose.material.icons.rounded.ContentCopy
import androidx.compose.material.icons.rounded.ContentPaste
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
@@ -56,6 +58,7 @@ import app.lawnchair.util.getClipboardContent
import com.android.launcher3.R
import kotlin.math.roundToInt
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun CustomIconShapePreference(
modifier: Modifier = Modifier,
@@ -89,6 +92,7 @@ fun CustomIconShapePreference(
modifier = Modifier
.fillMaxWidth()
.padding(all = 16.dp),
+ shapes = ButtonDefaults.shapes()
) {
Text(
text = if (appliedIconShape != null) {
@@ -264,6 +268,7 @@ private fun IconShapeCornerPreference(
)
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun CornerSlider(
label: String,
@@ -337,7 +342,10 @@ private fun CornerSlider(
ModalBottomSheetContent(
title = { Text(stringResource(id = R.string.custom_icon_shape_corner)) },
buttons = {
- OutlinedButton(onClick = { bottomSheetHandler.hide() }) {
+ OutlinedButton(
+ onClick = { bottomSheetHandler.hide() },
+ shapes = ButtonDefaults.shapes()
+ ) {
Text(text = stringResource(id = android.R.string.cancel))
}
},
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/DebugMenuPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/DebugMenuPreferences.kt
index 29f4bfcb92..99eb182b61 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/DebugMenuPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/DebugMenuPreferences.kt
@@ -1,8 +1,11 @@
package app.lawnchair.ui.preferences.destinations
+import android.Manifest
+import android.content.pm.PackageManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.datastore.preferences.core.Preferences
import app.lawnchair.preferences.PreferenceManager
@@ -14,6 +17,7 @@ import app.lawnchair.ui.preferences.LocalIsExpandedScreen
import app.lawnchair.ui.preferences.LocalNavController
import app.lawnchair.ui.preferences.components.controls.ClickablePreference
import app.lawnchair.ui.preferences.components.controls.MainSwitchPreference
+import app.lawnchair.ui.preferences.components.controls.PreferenceCategory
import app.lawnchair.ui.preferences.components.controls.SwitchPreference
import app.lawnchair.ui.preferences.components.controls.TextPreference
import app.lawnchair.ui.preferences.components.layout.PreferenceGroup
@@ -23,6 +27,7 @@ import app.lawnchair.ui.preferences.data.liveinfo.liveInformationManager
import app.lawnchair.ui.preferences.data.liveinfo.model.LiveInformation
import app.lawnchair.ui.preferences.navigation.FeatureFlags
import com.android.launcher3.R
+import com.android.systemui.shared.system.BlurUtils
import com.patrykmichalik.opto.domain.Preference
import kotlinx.coroutines.runBlocking
@@ -102,6 +107,28 @@ fun DebugMenuPreferences(
)
}
}
+
+ PreferenceGroup(heading = "Launcher3 Readiness") {
+ var apmSupport = false
+ if (LocalContext.current.checkCallingOrSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+ == PackageManager.PERMISSION_GRANTED) {
+ apmSupport = true
+ }
+ PreferenceCategory(
+ label = "Blur effect",
+ description = BlurUtils.supportsBlursOnWindows().toString(),
+ iconResource = R.drawable.ic_search,
+ onNavigate = { null },
+ isSelected = false,
+ )
+ PreferenceCategory(
+ label = "App Prediction",
+ description = apmSupport.toString(),
+ iconResource = R.drawable.ic_search,
+ onNavigate = { null },
+ isSelected = false,
+ )
+ }
}
}
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/ExperimentalFeaturesPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/ExperimentalFeaturesPreferences.kt
index bf7f669165..b4c2cf60bf 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/ExperimentalFeaturesPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/ExperimentalFeaturesPreferences.kt
@@ -17,6 +17,7 @@ import app.lawnchair.ui.preferences.LocalIsExpandedScreen
import app.lawnchair.ui.preferences.components.WallpaperAccessPermissionDialog
import app.lawnchair.ui.preferences.components.controls.SliderPreference
import app.lawnchair.ui.preferences.components.controls.SwitchPreference
+import app.lawnchair.ui.preferences.components.controls.WarningPreference
import app.lawnchair.ui.preferences.components.layout.DividerColumn
import app.lawnchair.ui.preferences.components.layout.ExpandAndShrink
import app.lawnchair.ui.preferences.components.layout.PreferenceGroup
@@ -24,6 +25,8 @@ import app.lawnchair.ui.preferences.components.layout.PreferenceLayout
import app.lawnchair.util.FileAccessManager
import app.lawnchair.util.FileAccessState
import com.android.launcher3.R
+import com.android.launcher3.Utilities.ATLEAST_S
+import com.android.systemui.shared.system.BlurUtils
@Composable
fun ExperimentalFeaturesPreferences(
@@ -36,27 +39,36 @@ fun ExperimentalFeaturesPreferences(
backArrowVisible = !LocalIsExpandedScreen.current,
modifier = modifier,
) {
- PreferenceGroup {
+ PreferenceGroup(
+ Modifier,
+ stringResource(R.string.workspace_label),
+ ) {
+ // pE-FeatureTaskForce-TODO(N/A): Make Material 3 Expressive Toggle
+ val enableMaterialExpressiveAdapter = prefs.enableMaterialExpressive.getAdapter()
+ SwitchPreference(
+ adapter = enableMaterialExpressiveAdapter,
+ label = stringResource(id = R.string.material_expressive_label),
+ description = stringResource(id = R.string.material_expressive_description),
+ )
+ ExpandAndShrink(visible = enableMaterialExpressiveAdapter.state.value) {
+ if (!ATLEAST_S || !BlurUtils.supportsBlursOnWindows()) {
+ WarningPreference(
+ "Expressive Blur will be ignored because blur effect required at " +
+ "least Android 12 or above, and device need performant GPU to render " +
+ "blur and need to enable support rendering cross window blur by the " +
+ "device manufacturer.")
+ }
+ }
SwitchPreference(
adapter = prefs2.enableFontSelection.getAdapter(),
label = stringResource(id = R.string.font_picker_label),
description = stringResource(id = R.string.font_picker_description),
)
- SwitchPreference(
- adapter = prefs2.enableSmartspaceCalendarSelection.getAdapter(),
- label = stringResource(id = R.string.smartspace_calendar_label),
- description = stringResource(id = R.string.smartspace_calendar_description),
- )
SwitchPreference(
adapter = prefs.workspaceIncreaseMaxGridSize.getAdapter(),
label = stringResource(id = R.string.workspace_increase_max_grid_size_label),
description = stringResource(id = R.string.workspace_increase_max_grid_size_description),
)
- SwitchPreference(
- adapter = prefs2.alwaysReloadIcons.getAdapter(),
- label = stringResource(id = R.string.always_reload_icons_label),
- description = stringResource(id = R.string.always_reload_icons_description),
- )
SwitchPreference(
adapter = prefs2.iconSwipeGestures.getAdapter(),
label = stringResource(R.string.icon_swipe_gestures),
@@ -119,5 +131,45 @@ fun ExperimentalFeaturesPreferences(
onPauseOrDispose { }
}
}
+
+ PreferenceGroup(
+ Modifier,
+ stringResource(R.string.smartspace_label),
+ ) {
+ SwitchPreference(
+ adapter = prefs2.enableSmartspaceCalendarSelection.getAdapter(),
+ label = stringResource(id = R.string.smartspace_calendar_label),
+ description = stringResource(id = R.string.smartspace_calendar_description),
+ )
+ }
+
+ PreferenceGroup(
+ Modifier,
+ stringResource(R.string.internal_label),
+ stringResource(R.string.internal_description),
+ ) {
+ // Lawnchair-TODO(Merge): Investigate Always Reload Icons
+ val alwaysReloadIconsAdapter = prefs2.alwaysReloadIcons.getAdapter()
+ SwitchPreference(
+ adapter = alwaysReloadIconsAdapter,
+ label = stringResource(id = R.string.always_reload_icons_label),
+ description = stringResource(id = R.string.always_reload_icons_description),
+ )
+ ExpandAndShrink(visible = alwaysReloadIconsAdapter.state.value) {
+ WarningPreference(stringResource(R.string.always_reload_icons_warning))
+ }
+
+ // pE-FeatureTaskForce-TODO(N/A): Make GestureNavContract API Toggle
+ val enableGncAdapter = prefs.enableGnc.getAdapter()
+ SwitchPreference(
+ adapter = enableGncAdapter,
+ label = stringResource(id = R.string.gesturenavcontract_label),
+ description = stringResource(id = R.string.gesturenavcontract_description),
+ enabled = ATLEAST_S,
+ )
+ ExpandAndShrink(visible = enableGncAdapter.state.value) {
+ WarningPreference(stringResource(R.string.gesturenavcontract_warning_incompatibility))
+ }
+ }
}
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/FontSelectionPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/FontSelectionPreference.kt
index d0618c228a..7349c5b37b 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/FontSelectionPreference.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/FontSelectionPreference.kt
@@ -22,8 +22,10 @@ import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
@@ -202,6 +204,7 @@ fun FontSelection(
}
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun FontSelectionItem(
adapter: PreferenceAdapter,
@@ -243,6 +246,7 @@ private fun FontSelectionItem(
IconButton(
onClick = onDelete,
modifier = Modifier.padding(end = 8.dp),
+ shapes = IconButtonDefaults.shapes(),
) {
Icon(
imageVector = Icons.Rounded.Delete,
@@ -273,6 +277,7 @@ private fun removeFamilyPrefix(
return fontName.removePrefix(familyName).trim().toString()
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun VariantDropdown(
adapter: PreferenceAdapter,
@@ -300,6 +305,7 @@ private fun VariantDropdown(
onClick = { showVariants = true },
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.onSurface),
contentPadding = VariantButtonContentPadding,
+ shapes = ButtonDefaults.shapes()
) {
AndroidText(
modifier = Modifier.wrapContentWidth(),
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenGridPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenGridPreferences.kt
index 5c49086ecb..db72e21c63 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenGridPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenGridPreferences.kt
@@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableIntStateOf
@@ -28,6 +30,7 @@ import app.lawnchair.ui.preferences.components.layout.PreferenceLayout
import com.android.launcher3.LauncherAppState
import com.android.launcher3.R
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun HomeScreenGridPreferences(
modifier: Modifier = Modifier,
@@ -96,6 +99,7 @@ fun HomeScreenGridPreferences(
.align(Alignment.CenterEnd)
.fillMaxWidth(),
enabled = columns.intValue != originalColumns || rows.intValue != originalRows,
+ shapes = ButtonDefaults.shapes()
) {
Text(text = stringResource(id = R.string.action_apply))
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/PreferencesDashboard.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/PreferencesDashboard.kt
index af00bae3b8..572a774a59 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/PreferencesDashboard.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/PreferencesDashboard.kt
@@ -17,11 +17,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Backup
import androidx.compose.material.icons.outlined.Science
-import androidx.compose.material.icons.outlined.SettingsBackupRestore
-import androidx.compose.material.icons.rounded.Backup
import androidx.compose.material.icons.rounded.Build
import androidx.compose.material.icons.rounded.Refresh
-import androidx.compose.material.icons.rounded.Science
import androidx.compose.material.icons.rounded.SettingsBackupRestore
import androidx.compose.material.icons.rounded.TipsAndUpdates
import androidx.compose.material3.DropdownMenuItem
@@ -213,7 +210,7 @@ fun PreferenceCategoryGroup(
Surface(
modifier = modifier.padding(horizontal = 16.dp),
- shape = MaterialTheme.shapes.large,
+ shape = MaterialTheme.shapes.extraLarge,
color = color,
tonalElevation = if (isSelectedThemeDark) 1.dp else 0.dp,
) {
@@ -222,7 +219,6 @@ fun PreferenceCategoryGroup(
startIndent = (-16).dp,
endIndent = (-16).dp,
color = MaterialTheme.colorScheme.surface,
- thickness = 2.dp,
)
}
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/SearchProviderPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/SearchProviderPreferences.kt
index 3a482578c7..9c8dc21d29 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/SearchProviderPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/SearchProviderPreferences.kt
@@ -4,6 +4,8 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
@@ -201,6 +203,7 @@ private fun Options(
}
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun SponsorDisclaimer(
sponsor: String,
@@ -209,7 +212,10 @@ private fun SponsorDisclaimer(
) {
ModalBottomSheetContent(
buttons = {
- OutlinedButton(onClick = onAcknowledge) {
+ OutlinedButton(
+ onClick = onAcknowledge,
+ shapes = ButtonDefaults.shapes()
+ ) {
Text(text = stringResource(id = android.R.string.ok))
}
},
diff --git a/lawnchair/src/app/lawnchair/ui/theme/Theme.kt b/lawnchair/src/app/lawnchair/ui/theme/Theme.kt
index 21676e4aaf..b987dc9b17 100644
--- a/lawnchair/src/app/lawnchair/ui/theme/Theme.kt
+++ b/lawnchair/src/app/lawnchair/ui/theme/Theme.kt
@@ -22,9 +22,12 @@ import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.MaterialExpressiveTheme
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.MotionScheme
import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.lightColorScheme
+import androidx.compose.material3.expressiveLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -45,17 +48,19 @@ import app.lawnchair.ui.preferences.components.ThemeChoice
import app.lawnchair.wallpaper.WallpaperManagerCompat
import com.android.launcher3.Utilities
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun LawnchairTheme(
darkTheme: Boolean = isSelectedThemeDark,
content: @Composable () -> Unit,
) {
val colorScheme = getColorScheme(darkTheme = darkTheme)
- MaterialTheme(
+ MaterialExpressiveTheme(
colorScheme = colorScheme,
typography = Typography,
content = content,
shapes = Shapes,
+ motionScheme = MotionScheme.expressive(),
)
}
@@ -101,10 +106,11 @@ fun getColorScheme(darkTheme: Boolean): ColorScheme {
return colorScheme.toComposeColorScheme(isDark = darkTheme)
}
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
private fun getPreviewColorScheme(darkTheme: Boolean) = if (darkTheme) {
darkColorScheme()
} else {
- lightColorScheme()
+ expressiveLightColorScheme()
}
val isSelectedThemeDark: Boolean
diff --git a/lawnchair/src/app/lawnchair/ui/util/ProvideBottomSheetHandler.kt b/lawnchair/src/app/lawnchair/ui/util/ProvideBottomSheetHandler.kt
index c4cc2ec5e7..a3ec43b998 100644
--- a/lawnchair/src/app/lawnchair/ui/util/ProvideBottomSheetHandler.kt
+++ b/lawnchair/src/app/lawnchair/ui/util/ProvideBottomSheetHandler.kt
@@ -16,9 +16,16 @@
package app.lawnchair.ui.util
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetValue
import androidx.compose.material3.rememberModalBottomSheetState
@@ -31,6 +38,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.blur
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
@@ -78,10 +88,54 @@ fun ProvideBottomSheetHandler(
}
CompositionLocalProvider(LocalBottomSheetHandler provides bottomSheetHandler) {
- content()
-
val windowInsets = if (bottomSheetState.isVisible) WindowInsets.navigationBars else WindowInsets(0.dp)
+ var maxOffsetPx by remember(showBottomSheet) { mutableStateOf(null) }
+
+ // Live Edit doesn't like that we call requireOffset(), rebuild it instead of update.
+ val currentOffsetPx = try {
+ bottomSheetState.requireOffset()
+ } catch (_: IllegalStateException) {
+ null
+ }
+ if (showBottomSheet && currentOffsetPx != null) {
+ maxOffsetPx = maxOf(maxOffsetPx ?: 0f, currentOffsetPx)
+ }
+
+ val rawFraction = when {
+ !showBottomSheet -> 0f
+ currentOffsetPx == null || maxOffsetPx == null || maxOffsetPx == 0f -> 1f
+ else -> 1f - (currentOffsetPx / maxOffsetPx!!)
+ }.coerceIn(0f, 1f)
+
+ val animatedFraction by animateFloatAsState(
+ targetValue = rawFraction,
+ animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
+ label = "BottomSheetBlurFraction"
+ )
+
+ // See R.dimen.max_depth_blur_radius_enhanced
+ val blur = (34f * animatedFraction).dp
+ val scrimAlpha = 0.32f * animatedFraction
+
+ Box(modifier = Modifier.fillMaxSize()) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .blur(blur)
+ ) {
+ content()
+ }
+
+ if (showBottomSheet) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.onSurface.copy(alpha = scrimAlpha))
+ )
+ }
+ }
+
if (showBottomSheet) {
ModalBottomSheet(
sheetState = bottomSheetState,
@@ -91,6 +145,8 @@ fun ProvideBottomSheetHandler(
contentWindowInsets = {
windowInsets
},
+ // We render our own scrim to control the scrim's blur and alpha
+ scrimColor = Color.Transparent,
) {
bottomSheetContent.content()
}
diff --git a/wmshell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/wmshell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index 118ad9c4bf..eefd9e431e 100644
--- a/wmshell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/wmshell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -388,4 +388,4 @@ public class PipAccessibilityInteractionConnection {
int interactionId,
IAccessibilityInteractionConnectionCallback callback) {}
}
-}
\ No newline at end of file
+}