1+ @file:OptIn(ExperimentalMaterial3ExpressiveApi ::class )
2+
13package com.dede.android_eggs.views.settings.compose.prefs
24
5+ import android.content.Context
36import androidx.compose.foundation.Image
47import androidx.compose.foundation.background
58import androidx.compose.foundation.layout.Box
@@ -10,32 +13,40 @@ import androidx.compose.material.icons.Icons
1013import androidx.compose.material.icons.rounded.CheckCircle
1114import androidx.compose.material3.Card
1215import androidx.compose.material3.CardDefaults
16+ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
1317import androidx.compose.material3.Icon
18+ import androidx.compose.material3.MaterialShapes
1419import androidx.compose.material3.MaterialTheme.colorScheme
20+ import androidx.compose.material3.toShape
1521import androidx.compose.runtime.Composable
1622import androidx.compose.runtime.getValue
1723import androidx.compose.runtime.setValue
1824import androidx.compose.ui.Alignment
1925import androidx.compose.ui.Modifier
2026import androidx.compose.ui.draw.clip
27+ import androidx.compose.ui.graphics.Shape
2128import androidx.compose.ui.layout.ContentScale
2229import androidx.compose.ui.layout.Layout
30+ import androidx.compose.ui.platform.LocalContext
2331import androidx.compose.ui.res.painterResource
24- import androidx.compose.ui.res.stringArrayResource
2532import androidx.compose.ui.res.stringResource
2633import androidx.compose.ui.tooling.preview.Preview
2734import androidx.compose.ui.unit.Constraints
2835import androidx.compose.ui.unit.dp
2936import androidx.core.os.bundleOf
37+ import androidx.graphics.shapes.CornerRounding
38+ import androidx.graphics.shapes.RoundedPolygon
39+ import androidx.graphics.shapes.rectangle
40+ import androidx.graphics.shapes.star
3041import com.dede.android_eggs.R
3142import com.dede.android_eggs.alterable_adaptive_icon.PathShape
3243import com.dede.android_eggs.ui.composes.icons.rounded.Shapes
3344import com.dede.android_eggs.util.LocalEvent
3445import com.dede.android_eggs.views.settings.compose.basic.ExpandOptionsPref
3546import com.dede.android_eggs.views.settings.compose.basic.SettingPrefUtil
3647import com.dede.android_eggs.views.settings.compose.basic.rememberPrefIntState
48+ import sv.lib.squircleshape.SquircleShape
3749import com.dede.android_eggs.resources.R as StringsR
38- import com.dede.android_eggs.settings.R as SettingsR
3950
4051private const val SPAN_COUNT = 5
4152
@@ -47,45 +58,109 @@ fun IconShapePref() {
4758 leadingIcon = Icons .Rounded .Shapes ,
4859 title = stringResource(StringsR .string.pref_title_icon_shape_override),
4960 ) {
50- IconShapeGroup (selectedIndex) { index, path ->
51- selectedIndex = index
52- val extras = bundleOf(SettingPrefUtil .EXTRA_VALUE to path)
53- with (LocalEvent .poster()) {
54- post(IconShapePrefUtil .ACTION_CHANGED , extras)
55- post(SettingPrefUtil .ACTION_CLOSE_SETTING )
56- }
57- }
58- }
59- }
60-
61- @Preview
62- @Composable
63- private fun IconShapeGroup (
64- selectedIndex : Int = 0,
65- onShapeClick : ((index: Int , path: String ) -> Unit )? = null
66- ) {
67- val items = stringArrayResource(SettingsR .array.icon_shape_override_paths)
68- Layout (
69- content = {
70- items.forEachIndexed { index, path ->
61+ IconShapeGridLayout {
62+ polygonItems.forEachIndexed { index, roundedPolygon ->
7163 Box (modifier = Modifier .padding(4 .dp)) {
7264 ShapeItem (
7365 isChecked = index == selectedIndex,
74- path = path ,
66+ polygon = roundedPolygon.toShapePlusNullable() ,
7567 onClick = onClick@{
7668 if (selectedIndex == index) return @onClick
77- onShapeClick?.invoke(index, path)
69+ selectedIndex = index
70+ val extras = bundleOf(SettingPrefUtil .EXTRA_VALUE to index)
71+ with (LocalEvent .poster()) {
72+ post(IconShapePrefUtil .ACTION_CHANGED , extras)
73+ post(SettingPrefUtil .ACTION_CLOSE_SETTING )
74+ }
7875 }
7976 )
8077 }
8178 }
82- },
79+ }
80+ }
81+ }
82+
83+ fun getIconShapeRoundedPolygon (context : Context ): RoundedPolygon ? {
84+ val index = IconShapePrefUtil .getIconShapeIndexOf(context)
85+ return polygonItems.getOrNull(index)
86+ }
87+
88+ @Composable
89+ fun getIconShapePref (): Shape {
90+ val roundedPolygon = getIconShapeRoundedPolygon(LocalContext .current)
91+ return roundedPolygon.toShapePlus()
92+ }
93+
94+ @Composable
95+ fun RoundedPolygon?.toShapePlus (): Shape {
96+ val shape = this .toShapePlusNullable()
97+ if (shape == null ) {
98+ val path = IconShapePrefUtil .getSystemIconMaskPath(LocalContext .current)
99+ if (path != null ) {
100+ return PathShape (path)
101+ }
102+ return defaultSquare.toShape()
103+ }
104+ return shape
105+ }
106+
107+ @Composable
108+ private fun RoundedPolygon?.toShapePlusNullable (): Shape ? {
109+ if (this == null ) return null
110+ if (this == _fakeSquircle ) return SquircleShape ()
111+ return this .toShape()
112+ }
113+
114+ private val defaultSquare = MaterialShapes .Square
115+
116+ @Suppress(" ObjectPropertyName" )
117+ private val _fakeSquircle = RoundedPolygon .rectangle()
118+
119+ private val polygonItems: Array <RoundedPolygon ?> = arrayOf(
120+ null ,
121+ defaultSquare,
122+ // Squircle
123+ _fakeSquircle ,
124+ MaterialShapes .Circle ,
125+ // CornerSE
126+ RoundedPolygon (
127+ vertices = floatArrayOf(1f , 1f , - 1f , 1f , - 1f , - 1f , 1f , - 1f ),
128+ perVertexRounding = listOf (
129+ CornerRounding (0.4f ),
130+ CornerRounding (1f ),
131+ CornerRounding (1f ),
132+ CornerRounding (1f ),
133+ ),
134+ ).normalized(),
135+
136+ MaterialShapes .Cookie4Sided ,
137+ // Scallop
138+ RoundedPolygon .star(
139+ numVerticesPerRadius = 13 ,
140+ innerRadius = .9f ,
141+ rounding = CornerRounding (.2f ),
142+ innerRounding = CornerRounding (.3f )
143+ ).normalized(),
144+ MaterialShapes .Clover8Leaf ,
145+ MaterialShapes .Pill ,
146+ RoundedPolygon .star(
147+ numVerticesPerRadius = 10 ,
148+ innerRadius = .6f ,
149+ rounding = CornerRounding (.3f ),
150+ innerRounding = CornerRounding (.3f )
151+ ).normalized(),
152+ )
153+
154+ @Composable
155+ private fun IconShapeGridLayout (spanCount : Int = SPAN_COUNT , content : @Composable () -> Unit ) {
156+ Layout (
157+ content = content,
83158 measurePolicy = { measurables, constraints ->
84- val childConstraints = Constraints .fixedWidth(constraints.maxWidth / SPAN_COUNT )
159+ val childConstraints = Constraints .fixedWidth(constraints.maxWidth / spanCount )
85160 var height = 0
86161 val placeables = measurables.mapIndexed { index, measurable ->
87162 measurable.measure(childConstraints).also { placeable ->
88- if (index % SPAN_COUNT == 0 ) {
163+ if (index % spanCount == 0 ) {
89164 height + = placeable.height
90165 }
91166 }
@@ -94,25 +169,24 @@ private fun IconShapeGroup(
94169 var x: Int
95170 var y: Int
96171 placeables.forEachIndexed { index, placeable ->
97- x = index % SPAN_COUNT * placeable.width
98- y = index / SPAN_COUNT * placeable.height
172+ x = index % spanCount * placeable.width
173+ y = index / spanCount * placeable.height
99174 placeable.placeRelative(x, y)
100175 }
101176 }
102177 }
103178 )
104179}
105180
106- @Preview(widthDp = 56 )
107181@Composable
108182private fun ShapeItem (
109183 modifier : Modifier = Modifier ,
110184 isChecked : Boolean = false,
111- path : String = stringResource(id = SettingsR .string.icon_shape_clover_path ),
185+ polygon : Shape ? = MaterialShapes . Circle .toShape( ),
112186 onClick : () -> Unit = {}
113187) {
114188 Card (
115- shape = PathShape (stringResource( SettingsR .string.icon_shape_clover_path) ),
189+ shape = MaterialShapes . Cookie4Sided .toShape( ),
116190 onClick = onClick,
117191 modifier = modifier then Modifier .aspectRatio(1f ),
118192 colors = CardDefaults .cardColors(containerColor = colorScheme.surface)
@@ -121,7 +195,7 @@ private fun ShapeItem(
121195 contentAlignment = Alignment .Center ,
122196 modifier = Modifier .fillMaxSize()
123197 ) {
124- if (path.isEmpty() ) {
198+ if (polygon == null ) {
125199 Image (
126200 painter = painterResource(R .drawable.ic_android_classic),
127201 contentDescription = null ,
@@ -132,7 +206,7 @@ private fun ShapeItem(
132206 } else {
133207 Box (
134208 modifier = Modifier
135- .clip(PathShape (path) )
209+ .clip(polygon )
136210 .background(colorScheme.primary)
137211 .fillMaxSize(0.56f )
138212 )
0 commit comments