feat: Improve Lawnchair grid specifications (#6583)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: TheSuperDragon <70206496+superdragonxd@users.noreply.github.com> Signed-off-by: Pun Butrach <pun.butrach@gmail.com>
This commit is contained in:
20 files changed
+601
-110
No files matched your search
@@ -370,7 +370,7 @@ public final class FeatureFlagsImpl implements FeatureFlags {
|
||||
|
||||
|
||||
public boolean enableScalabilityForDesktopExperience() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -765,6 +765,14 @@
|
||||
<string name="open_in_store_drop_target_label">Open in store</string>
|
||||
|
||||
<string name="dock_icons">Dock icons</string>
|
||||
<string name="state_folded">%1$s (folded)</string>
|
||||
<string name="state_unfolded">%1$s (unfolded)</string>
|
||||
<string name="folded_label">Folded</string>
|
||||
<string name="unfolded_label">Unfolded</string>
|
||||
<string name="when_folded_label">When folded</string>
|
||||
<string name="when_unfolded_label">When unfolded</string>
|
||||
<string name="unfolded_grid_description">Lawnchair pairs two pages together to fill the larger display</string>
|
||||
<string name="foldable_columns_error">The folded value must be less than or equal to the unfolded value. It will be automatically adjusted if needed.</string>
|
||||
<string name="hotseat_bottom_space_label">Bottom padding</string>
|
||||
<string name="page_indicator_height">Page indicator height</string>
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
launcher:packageName="com.google.android.deskclock"
|
||||
launcher:screen="0"
|
||||
launcher:spanX="2"
|
||||
launcher:spanY="3"
|
||||
launcher:spanY="2"
|
||||
launcher:x="2"
|
||||
launcher:y="1"/>
|
||||
|
||||
|
||||
+6
-6
@@ -33,25 +33,25 @@
|
||||
launcher:packageName="com.android.vending"
|
||||
launcher:screen="0"
|
||||
launcher:x="0"
|
||||
launcher:y="4"/>
|
||||
launcher:y="5"/>
|
||||
<favorite
|
||||
launcher:className="com.google.android.gm.ConversationListActivityGmail"
|
||||
launcher:packageName="com.google.android.gm"
|
||||
launcher:screen="0"
|
||||
launcher:x="1"
|
||||
launcher:y="4"/>
|
||||
launcher:y="5"/>
|
||||
<favorite
|
||||
launcher:className="com.google.android.apps.photos.home.HomeActivity"
|
||||
launcher:packageName="com.google.android.apps.photos"
|
||||
launcher:screen="0"
|
||||
launcher:x="2"
|
||||
launcher:y="4"/>
|
||||
launcher:y="5"/>
|
||||
<favorite
|
||||
launcher:className="com.google.android.youtube.app.honeycomb.Shell$HomeActivity"
|
||||
launcher:packageName="com.google.android.youtube"
|
||||
launcher:screen="0"
|
||||
launcher:x="3"
|
||||
launcher:y="4"/>
|
||||
launcher:y="5"/>
|
||||
<appwidget
|
||||
launcher:className="com.google.android.apps.search.assistant.verticals.snapshot.widgets.weather.WeatherWidget_Receiver"
|
||||
launcher:packageName="com.google.android.googlequicksearchbox"
|
||||
@@ -69,7 +69,7 @@
|
||||
launcher:packageName="com.google.android.calendar"
|
||||
launcher:screen="1"
|
||||
launcher:spanX="4"
|
||||
launcher:spanY="2"
|
||||
launcher:spanY="3"
|
||||
launcher:x="0"
|
||||
launcher:y="3"/>
|
||||
</favorites>
|
||||
</favorites>
|
||||
@@ -51,8 +51,8 @@
|
||||
</grid-option>
|
||||
|
||||
<grid-option
|
||||
launcher:name="4_by_7"
|
||||
launcher:numRows="7"
|
||||
launcher:name="4_by_6"
|
||||
launcher:numRows="6"
|
||||
launcher:numColumns="4"
|
||||
launcher:numFolderRows="3"
|
||||
launcher:numFolderColumns="3"
|
||||
@@ -130,7 +130,7 @@
|
||||
launcher:dbFile="launcher_6_by_5.db"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_6x5"
|
||||
launcher:inlineQsb="landscape"
|
||||
launcher:deviceCategory="tablet" >
|
||||
launcher:deviceCategory="tablet|desktop" >
|
||||
|
||||
<display-option
|
||||
launcher:name="Tablet"
|
||||
@@ -170,7 +170,7 @@
|
||||
launcher:allAppsSpecsTwoPanelId="@xml/spec_foldable_all_apps_4x5_unfolded"
|
||||
launcher:allAppsStyle="@style/AllAppsStyle4x5Fold"
|
||||
launcher:cellStyle="@style/CellStyle4x5Fold"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_splitdisplay_4x5"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_splitdisplay_4x6"
|
||||
launcher:deviceCategory="multi_display"
|
||||
launcher:devicePaddingId="@xml/paddings_split_4x5"
|
||||
launcher:folderSpecsId="@xml/spec_handheld_folder_4x5"
|
||||
@@ -189,7 +189,7 @@
|
||||
launcher:numFolderColumns="3"
|
||||
launcher:numFolderRows="3"
|
||||
launcher:numHotseatIcons="4"
|
||||
launcher:numRows="5"
|
||||
launcher:numRows="6"
|
||||
launcher:workspaceCellSpecsId="@xml/spec_handheld_workspace_cell_4x5"
|
||||
launcher:workspaceCellSpecsTwoPanelId="@xml/spec_foldable_workspace_cell_4x5_unfolded"
|
||||
launcher:workspaceSpecsId="@xml/spec_handheld_workspace_4x5"
|
||||
|
||||
@@ -55,10 +55,16 @@ class DeviceProfileOverrides @Inject constructor(
|
||||
prefs.hotseatColumns.set(gridInfo.numHotseatColumns)
|
||||
}
|
||||
|
||||
fun getOverrides(defaultGrid: InvariantDeviceProfile.GridOption) = Options(
|
||||
fun getOverrides(
|
||||
defaultGrid: InvariantDeviceProfile.GridOption,
|
||||
deviceType: Int,
|
||||
previewOverrides: PreviewOverrides? = null,
|
||||
) = Options(
|
||||
prefs = prefs,
|
||||
prefs2 = preferenceManager2,
|
||||
defaultGrid = defaultGrid,
|
||||
deviceType = deviceType,
|
||||
previewOverrides = previewOverrides ?: PreviewOverrides(),
|
||||
)
|
||||
|
||||
fun getTextFactors() = TextFactors(preferenceManager2)
|
||||
@@ -80,6 +86,11 @@ class DeviceProfileOverrides @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
/** Override for any other value that's not a DBGridInfo, extends this value when needed */
|
||||
data class PreviewOverrides(
|
||||
val foldableDatabaseHotseatIcons: Int? = null,
|
||||
)
|
||||
|
||||
data class Options(
|
||||
val numAllAppsColumns: Int,
|
||||
val numFolderRows: Int,
|
||||
@@ -90,11 +101,18 @@ class DeviceProfileOverrides @Inject constructor(
|
||||
val allAppsIconTextSizeFactor: Float,
|
||||
|
||||
val enableTaskbarOnPhone: Boolean,
|
||||
|
||||
// Foldable overrides (-1 means don't override)
|
||||
val foldableShownHotseatIcons: Int = -1,
|
||||
val foldableDatabaseHotseatIcons: Int = -1,
|
||||
val foldableDatabaseAllAppsColumns: Int = -1,
|
||||
) {
|
||||
constructor(
|
||||
prefs: PreferenceManager,
|
||||
prefs2: PreferenceManager2,
|
||||
defaultGrid: InvariantDeviceProfile.GridOption,
|
||||
deviceType: Int,
|
||||
previewOverrides: PreviewOverrides,
|
||||
) : this(
|
||||
numAllAppsColumns = prefs2.drawerColumns.firstCached(gridOption = defaultGrid),
|
||||
numFolderRows = prefs.folderRows.get(defaultGrid),
|
||||
@@ -110,6 +128,26 @@ class DeviceProfileOverrides @Inject constructor(
|
||||
},
|
||||
|
||||
enableTaskbarOnPhone = prefs2.enableTaskbarOnPhone.firstCached(),
|
||||
|
||||
foldableShownHotseatIcons = if (deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY) {
|
||||
val folded = prefs.hotseatColumns.get()
|
||||
val unfolded = previewOverrides.foldableDatabaseHotseatIcons ?: prefs.hotseatColumnsUnfolded.get()
|
||||
folded.coerceAtMost(unfolded)
|
||||
} else {
|
||||
-1
|
||||
},
|
||||
foldableDatabaseHotseatIcons = if (deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY) {
|
||||
previewOverrides.foldableDatabaseHotseatIcons ?: prefs.hotseatColumnsUnfolded.get()
|
||||
} else {
|
||||
-1
|
||||
},
|
||||
foldableDatabaseAllAppsColumns = if (deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY) {
|
||||
val folded = prefs2.drawerColumns.firstCached(gridOption = defaultGrid)
|
||||
val unfolded = prefs2.drawerColumnsUnfolded.firstCached(gridOption = defaultGrid)
|
||||
folded.coerceAtLeast(unfolded)
|
||||
} else {
|
||||
-1
|
||||
},
|
||||
)
|
||||
|
||||
fun applyUi(idp: InvariantDeviceProfile) {
|
||||
@@ -119,6 +157,17 @@ class DeviceProfileOverrides @Inject constructor(
|
||||
idp.numFolderRows[INDEX_DEFAULT] = numFolderRows
|
||||
idp.numFolderColumns[INDEX_DEFAULT] = numFolderColumns
|
||||
|
||||
// Foldable overrides for hotseat and allapps columns
|
||||
if (foldableShownHotseatIcons > 0) {
|
||||
idp.numShownHotseatIcons = foldableShownHotseatIcons
|
||||
}
|
||||
if (foldableDatabaseHotseatIcons > 0) {
|
||||
idp.numDatabaseHotseatIcons = foldableDatabaseHotseatIcons
|
||||
}
|
||||
if (foldableDatabaseAllAppsColumns > 0) {
|
||||
idp.numDatabaseAllAppsColumns = foldableDatabaseAllAppsColumns
|
||||
}
|
||||
|
||||
// apply icon and text size
|
||||
idp.iconSize[INDEX_DEFAULT] *= iconSizeFactor
|
||||
idp.iconSize[INDEX_LANDSCAPE] *= iconSizeFactor
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.android.launcher3.graphics.ThemeManager
|
||||
import com.android.launcher3.model.DeviceGridState
|
||||
import com.android.launcher3.util.ComponentKey
|
||||
import com.android.launcher3.util.DaggerSingletonObject
|
||||
import com.android.launcher3.util.DisplayController
|
||||
import com.android.launcher3.util.Executors
|
||||
import com.android.launcher3.util.SafeCloseable
|
||||
import com.android.quickstep.RecentsModel
|
||||
@@ -45,6 +46,7 @@ class PreferenceManager @Inject constructor(
|
||||
) : BasePreferenceManager(context),
|
||||
SafeCloseable {
|
||||
private val idp get() = InvariantDeviceProfile.INSTANCE.get(context)
|
||||
private val dc get() = DisplayController.INSTANCE.get(context)
|
||||
private val mRecentsModel get() = RecentsModel.INSTANCE.get(context)
|
||||
private val reloadIcons: () -> Unit = {
|
||||
mRecentsModel.onThemeChanged()
|
||||
@@ -55,6 +57,8 @@ class PreferenceManager @Inject constructor(
|
||||
}
|
||||
private val reloadGrid: () -> Unit = { idp.onPreferencesChanged(context) }
|
||||
|
||||
private val deviceType = dc.info.deviceType
|
||||
|
||||
private val recreate = {
|
||||
LawnchairLauncher.instance?.recreateIfNotScheduled()
|
||||
Unit
|
||||
@@ -67,9 +71,37 @@ class PreferenceManager @Inject constructor(
|
||||
val transparentIconBackground = BoolPref("prefs_transparentIconBackground", false)
|
||||
val shadowBGIcons = BoolPref("pref_shadowBGIcons", true)
|
||||
val addIconToHome = BoolPref("pref_add_icon_to_home", true)
|
||||
val hotseatColumns = IntPref("pref_hotseatColumns", 4, reloadGrid)
|
||||
val workspaceColumns = IntPref("pref_workspaceColumns", 4)
|
||||
val workspaceRows = IntPref("pref_workspaceRows", 7)
|
||||
|
||||
private val isPhone: Boolean get() = deviceType == InvariantDeviceProfile.TYPE_PHONE
|
||||
private val isTablet: Boolean get() = deviceType == InvariantDeviceProfile.TYPE_TABLET
|
||||
private val isFoldable: Boolean get() = deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY
|
||||
private val isDesktop: Boolean get() = deviceType == InvariantDeviceProfile.TYPE_DESKTOP
|
||||
|
||||
val calculatedGridSpec = when {
|
||||
// This grid configuration is perfect for Phone, tested against Pixel 7,
|
||||
// alternative dense configuration can be 5x5x7
|
||||
isPhone -> LayoutConfig(4, 4, 6)
|
||||
|
||||
// This grid configuration is perfect for Tablet, tested against Pixel Tablet
|
||||
isTablet -> LayoutConfig(6, 6, 5)
|
||||
|
||||
// This grid configuration is perfect for Foldable, tested against Pixel 10 Pro Fold
|
||||
// Note: Hotseat column is 4 when folded, unfolded uses hotseatColumns + 2 or higher number
|
||||
// defined in numExtendedHotseatIcons from device profile
|
||||
isFoldable -> LayoutConfig(4, 4, 6, 6)
|
||||
|
||||
// This grid configuration is not tested against actual desktop devices,
|
||||
// but tablet configuration works perfectly when displayed via emulator
|
||||
isDesktop -> LayoutConfig(6, 6, 5)
|
||||
|
||||
// This grid configuration is the fallback for all devices type, this shouldn't be possible
|
||||
else -> LayoutConfig(4, 4, 7)
|
||||
}
|
||||
|
||||
val hotseatColumns = IntPref("pref_hotseatColumns", calculatedGridSpec.hotseatColumns, reloadGrid)
|
||||
val hotseatColumnsUnfolded = IntPref("pref_hotseatColumnsUnfolded", calculatedGridSpec.hotseatColumnsUnfolded, reloadGrid)
|
||||
val workspaceColumns = IntPref("pref_workspaceColumns", calculatedGridSpec.workspaceColumns)
|
||||
val workspaceRows = IntPref("pref_workspaceRows", calculatedGridSpec.workspaceRows)
|
||||
val workspaceIncreaseMaxGridSize = BoolPref("pref_workspace_increase_max_grid_size", false)
|
||||
val folderRows = IdpIntPref("pref_folderRows", { numFolderRows[INDEX_DEFAULT] }, reloadGrid)
|
||||
|
||||
@@ -192,3 +224,35 @@ class PreferenceManager @Inject constructor(
|
||||
|
||||
@Composable
|
||||
fun preferenceManager() = PreferenceManager.getInstance(LocalContext.current)
|
||||
|
||||
/**
|
||||
* Grid layout configuration for a device's workspace.
|
||||
*
|
||||
* @param hotseatColumns The amount of column the dock can contain
|
||||
* @param workspaceColumns The amount of column the home screen can contain
|
||||
* @param workspaceRows The amount of row the home screen can contain
|
||||
* @param hotseatColumnsUnfolded The amount of column the dock can contain when unfolded (foldables only)
|
||||
*/
|
||||
data class LayoutConfig(
|
||||
/**
|
||||
* Hotseat columns refer to the amount of column the dock can contain.
|
||||
* For foldables, this is the folded (closed) state.
|
||||
*/
|
||||
val hotseatColumns: Int,
|
||||
|
||||
/**
|
||||
* Workspace columns refer to the amount of column the home screen can contain.
|
||||
*/
|
||||
val workspaceColumns: Int,
|
||||
|
||||
/**
|
||||
* Workspace rows refer to the amount of row the home screen can contain.
|
||||
*/
|
||||
val workspaceRows: Int,
|
||||
|
||||
/**
|
||||
* Hotseat columns when the foldable is in unfolded (opened) state.
|
||||
* For non-foldable devices, this must be equals to [hotseatColumns].
|
||||
*/
|
||||
val hotseatColumnsUnfolded: Int = hotseatColumns,
|
||||
)
|
||||
@@ -680,6 +680,12 @@ class PreferenceManager2 @Inject constructor(
|
||||
onSet = { reloadHelper.reloadGrid() },
|
||||
)
|
||||
|
||||
val drawerColumnsUnfolded = idpPreference(
|
||||
key = intPreferencesKey(name = "drawer_columns_unfolded"),
|
||||
defaultSelector = { numAllAppsColumns + 2 },
|
||||
onSet = { reloadHelper.reloadGrid() },
|
||||
)
|
||||
|
||||
val folderColumns = idpPreference(
|
||||
key = intPreferencesKey(name = "folder_columns"),
|
||||
defaultSelector = { numFolderColumns[INDEX_DEFAULT] },
|
||||
|
||||
@@ -145,10 +145,16 @@ class LawnQsbLayout(context: Context, attrs: AttributeSet?) : FrameLayout(contex
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val dp = activity.deviceProfile
|
||||
// Unlike Phone, for Foldable/Tablet we let the original onMeasure do that instead since it
|
||||
// matched what we need. It perfectly fit the QSB with the grid.
|
||||
if (!dp.deviceProperties.isPhone) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
return
|
||||
}
|
||||
|
||||
val requestedWidth = MeasureSpec.getSize(widthMeasureSpec)
|
||||
val height = MeasureSpec.getSize(heightMeasureSpec)
|
||||
|
||||
val dp = activity.deviceProfile
|
||||
val cellWidth = DeviceProfile.calculateCellWidth(
|
||||
requestedWidth,
|
||||
dp.cellLayoutBorderSpacePx.x,
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package app.lawnchair.ui.preferences.components
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
@@ -10,7 +14,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.lawnchair.DeviceProfileOverrides
|
||||
import app.lawnchair.preferences.preferenceManager
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
@@ -18,36 +24,88 @@ import com.android.launcher3.InvariantDeviceProfile
|
||||
@Composable
|
||||
fun ColumnScope.GridOverridesPreview(
|
||||
modifier: Modifier = Modifier,
|
||||
expandToAvailableSpace: Boolean = true,
|
||||
previewOverrides: DeviceProfileOverrides.PreviewOverrides = DeviceProfileOverrides.PreviewOverrides(),
|
||||
updateGridOptions: DeviceProfileOverrides.DBGridInfo.() -> DeviceProfileOverrides.DBGridInfo,
|
||||
) {
|
||||
val previewIdp = createPreviewIdp(updateGridOptions, previewOverrides)
|
||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
val previewAspectRatio = remember(previewIdp, isPortrait) {
|
||||
val matchingProfile = previewIdp.supportedProfiles.firstOrNull { profile ->
|
||||
profile.deviceProperties.isLandscape != isPortrait
|
||||
} ?: previewIdp.supportedProfiles.firstOrNull { profile ->
|
||||
!profile.deviceProperties.isMultiDisplay
|
||||
} ?: previewIdp.supportedProfiles.firstOrNull()
|
||||
|
||||
val width = matchingProfile?.deviceProperties?.widthPx?.toFloat()
|
||||
val height = matchingProfile?.deviceProperties?.heightPx?.toFloat()
|
||||
|
||||
if (width == null || height == null || height <= 0f) {
|
||||
1f
|
||||
} else {
|
||||
width / height
|
||||
}
|
||||
}
|
||||
|
||||
WithWallpaper { wallpaper ->
|
||||
DummyLauncherBox(
|
||||
BoxWithConstraints(
|
||||
modifier = modifier
|
||||
.weight(1f)
|
||||
.then(if (expandToAvailableSpace) Modifier.weight(1f) else Modifier)
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.clip(MaterialTheme.shapes.large),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
WallpaperPreview(
|
||||
wallpaper = wallpaper,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
DummyLauncherLayout(
|
||||
idp = createPreviewIdp(updateGridOptions),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
val fitByWidth = maxHeight == 0.dp || maxWidth == 0.dp || (maxWidth / maxHeight) <= previewAspectRatio
|
||||
val previewModifier = if (fitByWidth) {
|
||||
Modifier.requiredSize(
|
||||
width = maxWidth,
|
||||
height = maxWidth / previewAspectRatio,
|
||||
)
|
||||
} else {
|
||||
Modifier.requiredSize(
|
||||
width = maxHeight * previewAspectRatio,
|
||||
height = maxHeight,
|
||||
)
|
||||
}
|
||||
|
||||
DummyLauncherBox(
|
||||
modifier = previewModifier.clip(MaterialTheme.shapes.large),
|
||||
aspectRatio = previewAspectRatio,
|
||||
) {
|
||||
WallpaperPreview(
|
||||
wallpaper = wallpaper,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
DummyLauncherLayout(
|
||||
idp = previewIdp,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun createPreviewIdp(updateGridOptions: DeviceProfileOverrides.DBGridInfo.() -> DeviceProfileOverrides.DBGridInfo): InvariantDeviceProfile {
|
||||
return createPreviewIdp(
|
||||
updateGridOptions = updateGridOptions,
|
||||
previewOverrides = DeviceProfileOverrides.PreviewOverrides(),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun createPreviewIdp(
|
||||
updateGridOptions: DeviceProfileOverrides.DBGridInfo.() -> DeviceProfileOverrides.DBGridInfo,
|
||||
previewOverrides: DeviceProfileOverrides.PreviewOverrides = DeviceProfileOverrides.PreviewOverrides(),
|
||||
): InvariantDeviceProfile {
|
||||
val context = LocalContext.current
|
||||
val prefs = preferenceManager()
|
||||
|
||||
val newIdp by remember {
|
||||
val newIdp by remember(previewOverrides) {
|
||||
derivedStateOf {
|
||||
val options = DeviceProfileOverrides.DBGridInfo(prefs)
|
||||
InvariantDeviceProfile(context, updateGridOptions(options))
|
||||
InvariantDeviceProfile(context, updateGridOptions(options), previewOverrides)
|
||||
}
|
||||
}
|
||||
return newIdp
|
||||
|
||||
@@ -29,12 +29,13 @@ import com.android.launcher3.LauncherAppState
|
||||
fun DummyLauncherBox(
|
||||
modifier: Modifier = Modifier,
|
||||
darkText: Boolean = wallpaperSupportsDarkText(),
|
||||
aspectRatio: Float? = null,
|
||||
content: @Composable BoxScope.() -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val idp = remember { InvariantDeviceProfile.INSTANCE.get(context) }
|
||||
val dp = idp.getDeviceProfile(context)
|
||||
val ratio = dp.deviceProperties.widthPx.toFloat() / dp.deviceProperties.heightPx.toFloat()
|
||||
val ratio = aspectRatio ?: (dp.deviceProperties.widthPx.toFloat() / dp.deviceProperties.heightPx.toFloat())
|
||||
|
||||
Box(modifier = modifier.aspectRatio(ratio, matchHeightConstraintsFirst = true)) {
|
||||
LawnchairTheme(darkTheme = !darkText) {
|
||||
|
||||
@@ -59,6 +59,7 @@ fun SliderPreference(
|
||||
step: Int,
|
||||
showAsPercentage: Boolean = false,
|
||||
showUnit: String = "",
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
val transformedAdapter = rememberTransformAdapter(
|
||||
adapter = adapter,
|
||||
@@ -74,6 +75,7 @@ fun SliderPreference(
|
||||
step = step.toFloat(),
|
||||
showAsPercentage = showAsPercentage,
|
||||
showUnit = showUnit,
|
||||
enabled = enabled,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,6 +88,7 @@ fun SliderPreference(
|
||||
modifier: Modifier = Modifier,
|
||||
showAsPercentage: Boolean = false,
|
||||
showUnit: String = "",
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
var adapterValue by adapter
|
||||
|
||||
@@ -100,6 +103,7 @@ fun SliderPreference(
|
||||
modifier = modifier,
|
||||
showAsPercentage = showAsPercentage,
|
||||
showUnit = showUnit,
|
||||
enabled = enabled,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -113,6 +117,7 @@ private fun SliderPreference(
|
||||
modifier: Modifier = Modifier,
|
||||
showAsPercentage: Boolean = false,
|
||||
showUnit: String = "",
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
var sliderValue by remember { mutableFloatStateOf(value) }
|
||||
val mMSDLPlayerWrapper = MSDLPlayerWrapper.INSTANCE.get(LocalContext.current)
|
||||
@@ -176,6 +181,7 @@ private fun SliderPreference(
|
||||
.padding(top = 2.dp, bottom = 12.dp)
|
||||
.padding(horizontal = 14.dp)
|
||||
.height(24.dp),
|
||||
enabled = enabled,
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
|
||||
@@ -47,10 +47,12 @@ import app.lawnchair.ui.preferences.components.colorpreference.ColorPreference
|
||||
import app.lawnchair.ui.preferences.components.controls.SliderPreference
|
||||
import app.lawnchair.ui.preferences.components.controls.SwitchPreference
|
||||
import app.lawnchair.ui.preferences.components.controls.SwitchPreferenceWithPreview
|
||||
import app.lawnchair.ui.preferences.components.controls.WarningPreference
|
||||
import app.lawnchair.ui.preferences.components.layout.ExpandAndShrink
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceGroup
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceLayout
|
||||
import app.lawnchair.ui.preferences.navigation.AppDrawerHiddenApps
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
import com.android.launcher3.R
|
||||
|
||||
object AppDrawerRoutes {
|
||||
@@ -65,6 +67,7 @@ fun AppDrawerPreferences(
|
||||
val prefs2 = preferenceManager2()
|
||||
val context = LocalContext.current
|
||||
val resources = context.resources
|
||||
val isFoldable = InvariantDeviceProfile.deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY
|
||||
|
||||
PreferenceLayout(
|
||||
label = stringResource(id = R.string.app_drawer_label),
|
||||
@@ -117,13 +120,41 @@ fun AppDrawerPreferences(
|
||||
}
|
||||
}
|
||||
PreferenceGroup(heading = stringResource(id = R.string.grid)) {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.app_drawer_columns),
|
||||
adapter = prefs2.drawerColumns.getAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
val drawerColumnsAdapter = prefs2.drawerColumns.getAdapter()
|
||||
val drawerColumnsUnfoldedAdapter = prefs2.drawerColumnsUnfolded.getAdapter()
|
||||
if (isFoldable) {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.state_folded, stringResource(id = R.string.app_drawer_columns)),
|
||||
adapter = drawerColumnsAdapter,
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.state_unfolded, stringResource(id = R.string.app_drawer_columns)),
|
||||
adapter = drawerColumnsUnfoldedAdapter,
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
}
|
||||
Item(
|
||||
visible = drawerColumnsAdapter.state.value > drawerColumnsUnfoldedAdapter.state.value,
|
||||
) {
|
||||
WarningPreference(
|
||||
text = stringResource(id = R.string.foldable_columns_error),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.app_drawer_columns),
|
||||
adapter = drawerColumnsAdapter,
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
}
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
|
||||
@@ -44,11 +44,13 @@ import app.lawnchair.ui.preferences.components.colorpreference.ColorPreference
|
||||
import app.lawnchair.ui.preferences.components.controls.MainSwitchPreference
|
||||
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.createPreviewIdp
|
||||
import app.lawnchair.ui.preferences.components.layout.DividerColumn
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceGroup
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceGroupHeading
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceLayout
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
import com.android.launcher3.R
|
||||
|
||||
@Composable
|
||||
@@ -137,14 +139,44 @@ fun HotseatBackgroundSettings(prefs: PreferenceManager, prefs2: PreferenceManage
|
||||
|
||||
@Composable
|
||||
fun GridSettings(prefs: PreferenceManager, prefs2: PreferenceManager2) {
|
||||
val isFoldable = InvariantDeviceProfile.deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY
|
||||
val hotseatColumnsAdapter = prefs.hotseatColumns.getAdapter()
|
||||
val hotseatColumnsUnfoldedAdapter = prefs.hotseatColumnsUnfolded.getAdapter()
|
||||
|
||||
PreferenceGroup(heading = stringResource(id = R.string.grid)) {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.dock_icons),
|
||||
adapter = prefs.hotseatColumns.getAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
if (isFoldable) {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.state_folded, stringResource(id = R.string.dock_icons)),
|
||||
adapter = hotseatColumnsAdapter,
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.state_unfolded, stringResource(id = R.string.dock_icons)),
|
||||
adapter = hotseatColumnsUnfoldedAdapter,
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
}
|
||||
Item(
|
||||
visible = hotseatColumnsAdapter.state.value > hotseatColumnsUnfoldedAdapter.state.value,
|
||||
) {
|
||||
WarningPreference(
|
||||
text = stringResource(id = R.string.foldable_columns_error),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.dock_icons),
|
||||
adapter = hotseatColumnsAdapter,
|
||||
step = 1,
|
||||
valueRange = 3..10,
|
||||
)
|
||||
}
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
@@ -176,6 +208,7 @@ fun ColumnScope.DockPreferencesPreview(modifier: Modifier = Modifier) {
|
||||
val adapters = listOf(
|
||||
prefs2.hotseatMode.getAdapter(),
|
||||
prefs.hotseatColumns.getAdapter(),
|
||||
prefs.hotseatColumnsUnfolded.getAdapter(),
|
||||
prefs2.themedHotseatQsb.getAdapter(),
|
||||
prefs.hotseatQsbCornerRadius.getAdapter(),
|
||||
prefs.hotseatQsbAlpha.getAdapter(),
|
||||
|
||||
+248
-47
@@ -1,15 +1,28 @@
|
||||
package app.lawnchair.ui.preferences.destinations
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
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
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
@@ -19,15 +32,18 @@ import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.lawnchair.DeviceProfileOverrides
|
||||
import app.lawnchair.preferences.asPreferenceAdapter
|
||||
import app.lawnchair.preferences.getAdapter
|
||||
import app.lawnchair.preferences.preferenceManager
|
||||
import app.lawnchair.ui.preferences.LocalIsExpandedScreen
|
||||
import app.lawnchair.ui.preferences.LocalNavController
|
||||
import app.lawnchair.ui.preferences.components.GridOverridesPreview
|
||||
import app.lawnchair.ui.preferences.components.controls.SliderPreference
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceGroup
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceLayout
|
||||
import com.android.launcher3.LauncherAppState
|
||||
import app.lawnchair.ui.preferences.components.layout.PreferenceTemplate
|
||||
import com.android.launcher3.InvariantDeviceProfile
|
||||
import com.android.launcher3.R
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@@ -35,78 +51,263 @@ import com.android.launcher3.R
|
||||
fun HomeScreenGridPreferences(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isExpandedScreen = LocalIsExpandedScreen.current
|
||||
val isPortrait = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
val scrollState = rememberScrollState()
|
||||
PreferenceLayout(
|
||||
label = stringResource(id = R.string.home_screen_grid),
|
||||
modifier = modifier,
|
||||
isExpandedScreen = true,
|
||||
scrollState = if (isPortrait) null else scrollState,
|
||||
scrollState = null,
|
||||
) {
|
||||
val controlsScrollState = rememberScrollState()
|
||||
val prefs = preferenceManager()
|
||||
val columnsAdapter = prefs.workspaceColumns.getAdapter()
|
||||
val rowsAdapter = prefs.workspaceRows.getAdapter()
|
||||
val hotseatColumnsAdapter = prefs.hotseatColumns.getAdapter()
|
||||
val hotseatColumnsUnfoldedAdapter = prefs.hotseatColumnsUnfolded.getAdapter()
|
||||
val increaseMaxGridSize = prefs.workspaceIncreaseMaxGridSize.getAdapter()
|
||||
val isFoldable = InvariantDeviceProfile.deviceType == InvariantDeviceProfile.TYPE_MULTI_DISPLAY
|
||||
|
||||
val originalColumns = remember { columnsAdapter.state.value }
|
||||
val originalRows = remember { rowsAdapter.state.value }
|
||||
val originalHotseatColumns = remember { hotseatColumnsAdapter.state.value }
|
||||
val originalHotseatColumnsUnfolded = remember { hotseatColumnsUnfoldedAdapter.state.value }
|
||||
|
||||
val columns = rememberSaveable { mutableIntStateOf(originalColumns) }
|
||||
val rows = rememberSaveable { mutableIntStateOf(originalRows) }
|
||||
val hotseatColumns = rememberSaveable { mutableIntStateOf(originalHotseatColumns) }
|
||||
val hotseatColumnsUnfolded = rememberSaveable {
|
||||
mutableIntStateOf(originalHotseatColumnsUnfolded.coerceAtLeast(originalHotseatColumns))
|
||||
}
|
||||
|
||||
if (isPortrait) {
|
||||
GridOverridesPreview {
|
||||
copy(numColumns = columns.intValue, numRows = rows.intValue)
|
||||
LaunchedEffect(hotseatColumns.intValue) {
|
||||
if (hotseatColumnsUnfolded.intValue < hotseatColumns.intValue) {
|
||||
hotseatColumnsUnfolded.intValue = hotseatColumns.intValue
|
||||
}
|
||||
}
|
||||
|
||||
val maxGridSize = if (increaseMaxGridSize.state.value) 20 else 10
|
||||
|
||||
PreferenceGroup {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.columns),
|
||||
adapter = columns.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.rows),
|
||||
adapter = rows.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val applyOverrides = {
|
||||
prefs.batchEdit {
|
||||
columnsAdapter.onChange(columns.intValue)
|
||||
rowsAdapter.onChange(rows.intValue)
|
||||
}
|
||||
LauncherAppState.getIDP(context).onPreferencesChanged(context)
|
||||
navController.popBackStack()
|
||||
}
|
||||
|
||||
Box(
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
.weight(1f),
|
||||
) {
|
||||
Button(
|
||||
onClick = { applyOverrides() },
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.fillMaxWidth(),
|
||||
enabled = columns.intValue != originalColumns || rows.intValue != originalRows,
|
||||
shapes = ButtonDefaults.shapes(),
|
||||
// Don't stress over the coerce value,
|
||||
// we eyeballing it till there's a much better solutions(tm) or permanent workarounds.
|
||||
val settingsMinHeight = when {
|
||||
// This should allow user to see the unfolded label,
|
||||
// which will be their indicator that they can scroll the settings entries.
|
||||
isFoldable -> (maxHeight * 0.58f).coerceAtLeast(360.dp)
|
||||
|
||||
// This should be enough for 3 preferences, they can't scroll beyond this.
|
||||
// Should you introduce another prefs, raise the value by a little so that they
|
||||
// have an indication that you can scroll the entries.
|
||||
isPortrait -> (maxHeight * 0.40f).coerceAtLeast(315.dp)
|
||||
|
||||
// Landscape mode
|
||||
else -> (maxHeight * 0.52f).coerceAtLeast(280.dp)
|
||||
}
|
||||
val previewMaxHeight = (maxHeight - settingsMinHeight)
|
||||
.coerceAtLeast(if (isPortrait) 180.dp else 140.dp)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.action_apply))
|
||||
GridOverridesPreview(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(max = previewMaxHeight)
|
||||
.padding(horizontal = 16.dp, vertical = if (isPortrait) 16.dp else 12.dp),
|
||||
expandToAvailableSpace = false,
|
||||
updateGridOptions = {
|
||||
copy(
|
||||
numColumns = columns.intValue,
|
||||
numRows = rows.intValue,
|
||||
numHotseatColumns = hotseatColumns.intValue,
|
||||
)
|
||||
},
|
||||
previewOverrides = if (isFoldable) {
|
||||
DeviceProfileOverrides.PreviewOverrides(
|
||||
foldableDatabaseHotseatIcons = hotseatColumnsUnfolded.intValue,
|
||||
)
|
||||
} else {
|
||||
DeviceProfileOverrides.PreviewOverrides()
|
||||
},
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.heightIn(min = settingsMinHeight),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.verticalScroll(controlsScrollState),
|
||||
) {
|
||||
if (isFoldable) {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
maxItemsInEachRow = if (isExpandedScreen) Int.MAX_VALUE else 1,
|
||||
) {
|
||||
PreferenceGroup(heading = stringResource(id = R.string.when_folded_label)) {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.columns),
|
||||
adapter = columns.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.rows),
|
||||
adapter = rows.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.dock_icons),
|
||||
adapter = hotseatColumns.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceGroup(
|
||||
heading = stringResource(id = R.string.when_unfolded_label),
|
||||
) {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.dock_icons),
|
||||
adapter = hotseatColumnsUnfolded.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = hotseatColumns.intValue..maxGridSize,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
FakeExpandedGridPreference(
|
||||
columns = columns.intValue * 2,
|
||||
rows = rows.intValue,
|
||||
description = stringResource(id = R.string.unfolded_grid_description),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PreferenceGroup {
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.columns),
|
||||
adapter = columns.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.rows),
|
||||
adapter = rows.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
Item {
|
||||
SliderPreference(
|
||||
label = stringResource(id = R.string.dock_icons),
|
||||
adapter = hotseatColumns.asPreferenceAdapter(),
|
||||
step = 1,
|
||||
valueRange = 3..maxGridSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val applyOverrides = {
|
||||
prefs.batchEdit {
|
||||
columnsAdapter.onChange(columns.intValue)
|
||||
rowsAdapter.onChange(rows.intValue)
|
||||
hotseatColumnsAdapter.onChange(hotseatColumns.intValue)
|
||||
hotseatColumnsUnfoldedAdapter.onChange(hotseatColumnsUnfolded.intValue)
|
||||
}
|
||||
InvariantDeviceProfile.INSTANCE.get(context).onPreferencesChanged(context)
|
||||
navController.popBackStack()
|
||||
}
|
||||
|
||||
val isChanged = columns.intValue != originalColumns ||
|
||||
rows.intValue != originalRows ||
|
||||
hotseatColumns.intValue != originalHotseatColumns ||
|
||||
hotseatColumnsUnfolded.intValue != originalHotseatColumnsUnfolded
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 8.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
Button(
|
||||
onClick = { applyOverrides() },
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.fillMaxWidth(),
|
||||
enabled = isChanged,
|
||||
shapes = ButtonDefaults.shapes(),
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.action_apply))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FakeExpandedGridPreference(
|
||||
columns: Int,
|
||||
rows: Int,
|
||||
description: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
PreferenceTemplate(
|
||||
title = {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.grid),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 8.dp),
|
||||
)
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.onSurface,
|
||||
LocalTextStyle provides MaterialTheme.typography.bodyLarge,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.x_by_y, columns, rows),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
description = {
|
||||
Text(description)
|
||||
},
|
||||
modifier = modifier,
|
||||
applyPaddings = false,
|
||||
enabled = false,
|
||||
)
|
||||
}
|
||||
@@ -517,7 +517,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
|
||||
List<SystemShortcut.Factory> shortcuts = new ArrayList(Arrays.asList(
|
||||
APP_INFO, WellbeingModel.SHORTCUT_FACTORY, mHotseatPredictionController));
|
||||
|
||||
shortcuts.addAll(getSplitShortcuts());
|
||||
if (LawnchairApp.isRecentsEnabled()) {
|
||||
shortcuts.addAll(getSplitShortcuts());
|
||||
}
|
||||
shortcuts.add(WIDGETS);
|
||||
shortcuts.add(INSTALL);
|
||||
if (Flags.enableLongPressRemoveShortcut()
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
launcher:devicePaddingId="@xml/paddings_6x5"
|
||||
launcher:dbFile="launcher_6_by_5.db"
|
||||
launcher:defaultLayoutId="@xml/default_workspace_6x5"
|
||||
launcher:deviceCategory="tablet" >
|
||||
launcher:deviceCategory="tablet|desktop" >
|
||||
|
||||
<display-option
|
||||
launcher:name="Tablet"
|
||||
@@ -248,4 +248,4 @@
|
||||
|
||||
</grid-option>
|
||||
|
||||
</profiles>
|
||||
</profiles>
|
||||
@@ -897,8 +897,12 @@ public class DeviceProfile {
|
||||
+ space;
|
||||
} else if (isQsbInline) {
|
||||
hotseatBarSizePx = Math.max(hotseatIconSizePx, getHotseatProfile().getQsbVisualHeight())
|
||||
+ hotseatBarBottomSpacePx
|
||||
+ space;
|
||||
+ hotseatBarBottomSpacePx;
|
||||
} else if (isQsbOnTop()) { // LC-Note: isQsbOnTop, this usually is a foldable device, not a tablet
|
||||
hotseatBarSizePx = hotseatIconSizePx
|
||||
+ hotseatQsbSpace
|
||||
+ getHotseatProfile().getQsbVisualHeight()
|
||||
+ hotseatBarBottomSpacePx;
|
||||
} else {
|
||||
hotseatBarSizePx = hotseatIconSizePx
|
||||
+ hotseatQsbSpace
|
||||
@@ -1417,7 +1421,7 @@ public class DeviceProfile {
|
||||
}
|
||||
var allAppLeftRightMarginMultiplier = PreferenceCacheExtensionsKt
|
||||
.firstCached(preferenceManager2.getDrawerLeftRightMarginFactor());
|
||||
var marginMultiplier = allAppLeftRightMarginMultiplier * (!getDeviceProperties().isTablet() ? 100 : 2);
|
||||
var marginMultiplier = allAppLeftRightMarginMultiplier * (!getDeviceProperties().isTablet() ? 100 : 10);
|
||||
allAppsLeftRightMargin = (int) (allAppsLeftRightMargin * marginMultiplier);
|
||||
|
||||
// todo fix how drawer padding values are calculated in responsive grid type
|
||||
@@ -1881,8 +1885,8 @@ public class DeviceProfile {
|
||||
} else {
|
||||
hotseatBarPadding.left += qsbWidth;
|
||||
}
|
||||
} else if (isTaskbarPresent || isQsbInline) {
|
||||
// Center the QSB vertically with hotseat
|
||||
} else if (isQsbOnTop() || isQsbInline) {
|
||||
// Keep the hotseat icons in the lower section so the QSB can sit above them.
|
||||
int hotseatBarBottomPadding = getHotseatBarBottomPadding();
|
||||
int hotseatBarTopPadding =
|
||||
hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx;
|
||||
@@ -1986,6 +1990,11 @@ public class DeviceProfile {
|
||||
+ additionalQsbSpace;
|
||||
}
|
||||
|
||||
/** LC-Note: For ID'ing tablet/foldable mode */
|
||||
private boolean isQsbOnTop() {
|
||||
return isTaskbarPresent || mDeviceProperties.isTwoPanels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of pixels the QSB is translated from the bottom of the screen.
|
||||
*/
|
||||
@@ -1993,7 +2002,7 @@ public class DeviceProfile {
|
||||
if (mDeviceProperties.isPhone() && isQsbInline) {
|
||||
return getHotseatBarBottomPadding()
|
||||
- ((getHotseatProfile().getQsbHeight() - hotseatCellHeightPx) / 2);
|
||||
} else if (isTaskbarPresent || (mDeviceProperties.isLandscape() && isQsbInline)) { // QSB on top
|
||||
} else if (isQsbOnTop() || (mDeviceProperties.isLandscape() && isQsbInline)) { // LC-Note: isQsbOnTop
|
||||
return hotseatBarSizePx - getHotseatProfile().getQsbHeight()
|
||||
+ getHotseatProfile().getQsbShadowHeight();
|
||||
} else {
|
||||
@@ -2005,7 +2014,7 @@ public class DeviceProfile {
|
||||
* Returns the number of pixels the hotseat is translated from the bottom of the screen.
|
||||
*/
|
||||
private int getHotseatBarBottomPadding() {
|
||||
if (isTaskbarPresent || isQsbInline) { // QSB on top or inline
|
||||
if (isQsbOnTop() || isQsbInline) { // LC-Note: isQsbOnTop
|
||||
return hotseatBarBottomSpacePx - (Math.abs(hotseatCellHeightPx - iconSizePx) / 2);
|
||||
} else {
|
||||
return hotseatBarSizePx - hotseatCellHeightPx;
|
||||
|
||||
@@ -347,7 +347,16 @@ public class InvariantDeviceProfile {
|
||||
this.mThemeManager = ThemeManager.INSTANCE.get(context.getApplicationContext());
|
||||
this.mDisplayController = DisplayController.INSTANCE.get(context.getApplicationContext());
|
||||
String gridName = DeviceProfileOverrides.INSTANCE.get(context).getGridName(dbGridInfo);
|
||||
initGrid(context, gridName, dbGridInfo);
|
||||
initGrid(context, gridName, dbGridInfo, null);
|
||||
}
|
||||
|
||||
public InvariantDeviceProfile(Context context, DeviceProfileOverrides.DBGridInfo dbGridInfo,
|
||||
DeviceProfileOverrides.PreviewOverrides previewOverrides) {
|
||||
this.mPrefs = LauncherPrefs.get(context.getApplicationContext());
|
||||
this.mThemeManager = ThemeManager.INSTANCE.get(context.getApplicationContext());
|
||||
this.mDisplayController = DisplayController.INSTANCE.get(context.getApplicationContext());
|
||||
String gridName = DeviceProfileOverrides.INSTANCE.get(context).getGridName(dbGridInfo);
|
||||
initGrid(context, gridName, dbGridInfo, previewOverrides);
|
||||
}
|
||||
|
||||
private String initGrid(Context context, String gridName) {
|
||||
@@ -376,7 +385,7 @@ public class InvariantDeviceProfile {
|
||||
}
|
||||
DeviceProfileOverrides.DBGridInfo dbGridInfo = DeviceProfileOverrides.INSTANCE.get(context)
|
||||
.getGridInfo();
|
||||
initGrid(context, displayInfo, displayOption, dbGridInfo);
|
||||
initGrid(context, displayInfo, displayOption, dbGridInfo, null);
|
||||
FileLog.d(TAG, "After initGrid:"
|
||||
+ "gridName:" + gridName
|
||||
+ ", dbFile:" + dbFile
|
||||
@@ -386,6 +395,11 @@ public class InvariantDeviceProfile {
|
||||
}
|
||||
|
||||
private String initGrid(Context context, String gridName, DeviceProfileOverrides.DBGridInfo dbGridInfo) {
|
||||
return initGrid(context, gridName, dbGridInfo, null);
|
||||
}
|
||||
|
||||
private String initGrid(Context context, String gridName, DeviceProfileOverrides.DBGridInfo dbGridInfo,
|
||||
DeviceProfileOverrides.PreviewOverrides previewOverrides) {
|
||||
Info displayInfo = mDisplayController.getInfo();
|
||||
List<DisplayOption> allOptions = getPredefinedDeviceProfiles(
|
||||
context,
|
||||
@@ -407,7 +421,7 @@ public class InvariantDeviceProfile {
|
||||
if (!displayOption.grid.name.equals(gridName)) {
|
||||
mPrefs.put(GRID_NAME, displayOption.grid.name);
|
||||
}
|
||||
initGrid(context, displayInfo, displayOption, dbGridInfo);
|
||||
initGrid(context, displayInfo, displayOption, dbGridInfo, previewOverrides);
|
||||
return displayOption.grid.name;
|
||||
}
|
||||
|
||||
@@ -427,7 +441,9 @@ public class InvariantDeviceProfile {
|
||||
initGrid(context, getCurrentGridName(context));
|
||||
}
|
||||
|
||||
private void initGrid(Context context, Info displayInfo, DisplayOption displayOption, DeviceProfileOverrides.DBGridInfo dbGridInfo) {
|
||||
private void initGrid(Context context, Info displayInfo, DisplayOption displayOption,
|
||||
DeviceProfileOverrides.DBGridInfo dbGridInfo,
|
||||
DeviceProfileOverrides.PreviewOverrides previewOverrides) {
|
||||
this.closestProfile = displayOption.grid;
|
||||
|
||||
enableTwoLinesInAllApps = Flags.enableTwolineToggle()
|
||||
@@ -435,8 +451,8 @@ public class InvariantDeviceProfile {
|
||||
&& mPrefs.get(ENABLE_TWOLINE_ALLAPPS_TOGGLE);
|
||||
mLocale = context.getResources().getConfiguration().locale.toString();
|
||||
|
||||
DeviceProfileOverrides.Options overrideOptions = DeviceProfileOverrides.INSTANCE.get(context)
|
||||
.getOverrides(displayOption.grid);
|
||||
DeviceProfileOverrides.Options overrideOptions = DeviceProfileOverrides.INSTANCE.get(context)
|
||||
.getOverrides(displayOption.grid, displayInfo.getDeviceType(), previewOverrides);
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
GridOption closestProfile = displayOption.grid;
|
||||
numRows = dbGridInfo.getNumRows();
|
||||
@@ -489,7 +505,7 @@ public class InvariantDeviceProfile {
|
||||
horizontalMargin = displayOption.horizontalMargin;
|
||||
|
||||
numShownHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
|
||||
? closestProfile.numDatabaseHotseatIcons : dbGridInfo.getNumHotseatColumns();
|
||||
? closestProfile.numHotseatIcons : dbGridInfo.getNumHotseatColumns();
|
||||
numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
|
||||
? closestProfile.numDatabaseHotseatIcons : numShownHotseatIcons;
|
||||
hotseatBarBottomSpace = displayOption.hotseatBarBottomSpace;
|
||||
|
||||
@@ -729,6 +729,7 @@ public class DisplayController implements DesktopVisibilityListener {
|
||||
|
||||
public @DeviceType int getDeviceType() {
|
||||
if (mIsDesktopFormFactor) {
|
||||
Log.d("LC-DisplayController", "Device has desktop profile (Desktop)");
|
||||
return TYPE_DESKTOP;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user