Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/upstream' into trunk
Browse files Browse the repository at this point in the history
  • Loading branch information
Goooler committed Aug 9, 2024
2 parents 3092a3d + d85f9e6 commit e28129f
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 168 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
open_collective: lawnchair
13 changes: 8 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import com.android.build.gradle.api.AndroidBasePlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id 'com.android.application' version "8.5.1"
id 'com.android.library' version "8.5.1" apply false
id 'com.android.test' version '8.5.1' apply false
id 'com.android.application' version "8.5.2"
id 'com.android.library' version "8.5.2" apply false
id 'com.android.test' version '8.5.2' apply false
id 'androidx.baselineprofile' version '1.2.4'
id 'org.jetbrains.kotlin.android' version "2.0.10"
id 'org.jetbrains.kotlin.plugin.compose' version "2.0.10"
Expand Down Expand Up @@ -355,7 +355,7 @@ dependencies {
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.activity:activity-compose:1.9.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4"
implementation "androidx.navigation:navigation-compose:2.8.0-beta06"
implementation "androidx.navigation:navigation-compose:2.8.0-beta07"
implementation "androidx.palette:palette-ktx:1.0.0"
implementation "androidx.slice:slice-core:1.1.0-alpha02"
def accompanistVersion = '0.34.0'
Expand Down Expand Up @@ -388,6 +388,9 @@ dependencies {

implementation 'com.airbnb.android:lottie:6.5.0'

// Compose drag and drop library
implementation 'sh.calvin.reorderable:reorderable:2.3.0'

// Smartspacer
implementation('com.kieronquinn.smartspacer:sdk-client:1.0.11') {
exclude group: "com.github.skydoves", module: "balloon"
Expand All @@ -411,7 +414,7 @@ spotless {
kotlin {
target("lawnchair/src/**/*.kt")
ktlint().customRuleSets([
"io.nlopez.compose.rules:ktlint:0.4.9",
"io.nlopez.compose.rules:ktlint:0.4.10",
]).editorConfigOverride([
"ktlint_compose_compositionlocal-allowlist": "disabled",
])
Expand Down
1 change: 1 addition & 0 deletions lawnchair/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@

<string name="acknowledgements">Acknowledgements</string>
<string name="translate">Translate</string>
<string name="donate">Donate</string>

<!--
Expand Down
13 changes: 12 additions & 1 deletion lawnchair/src/app/lawnchair/ui/preferences/about/About.kt
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private val product = listOf(
name = "Yasan Glass",
role = Role.Development,
photoUrl = "https://avatars.githubusercontent.com/u/41836211",
socialUrl = "https:/yasan.glass",
socialUrl = "https://yasan.glass",
),
)

Expand Down Expand Up @@ -298,8 +298,19 @@ fun About(
}
},
)
ClickablePreference(
label = stringResource(id = R.string.donate),
onClick = {
val webpage = Uri.parse(OPENCOLLECTIVE_FUNDING_URL)
val intent = Intent(Intent.ACTION_VIEW, webpage)
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
}
},
)
}
}
}

private const val OPENCOLLECTIVE_FUNDING_URL = "https://opencollective.com/lawnchair"
private const val CROWDIN_URL = "https://lawnchair.crowdin.com/lawnchair"
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
package app.lawnchair.ui.preferences.components

import android.view.HapticFeedbackConstants
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
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.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.DragHandle
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.CustomAccessibilityAction
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import app.lawnchair.preferences.PreferenceAdapter
import app.lawnchair.ui.preferences.components.controls.ClickablePreference
import app.lawnchair.ui.preferences.components.layout.ExpandAndShrink
import app.lawnchair.ui.preferences.components.layout.PreferenceGroup
import app.lawnchair.ui.preferences.components.layout.PreferenceGroupHeading
import app.lawnchair.ui.preferences.components.layout.PreferenceTemplate
import com.android.launcher3.R
import com.android.launcher3.Utilities
import sh.calvin.reorderable.ReorderableColumn
import sh.calvin.reorderable.ReorderableScope

data class RecentsQuickAction(
val id: Int,
val label: String,
val adapter: PreferenceAdapter<Boolean>,
val description: String? = null,
)

fun sortListByIdOrder(list: List<RecentsQuickAction>, order: String): List<RecentsQuickAction> {
val orderList = order.split(",").map { it.toInt() }
return list.sortedBy { orderList.indexOf(it.id) }
}

private const val DEFAULT_ORDER = "0,1,2,3,4"

@Composable
fun QuickActionsPreferences(
adapter: PreferenceAdapter<String>,
items: List<RecentsQuickAction>,
modifier: Modifier = Modifier,
) {
QuickActionsPreferences(
order = adapter.state.value,
onOrderChange = adapter::onChange,
items = items,
modifier = modifier,
)
}

@Composable
fun QuickActionsPreferences(
order: String,
onOrderChange: (String) -> Unit,
items: List<RecentsQuickAction>,
modifier: Modifier = Modifier,
) {
var orderedItems = sortListByIdOrder(items, order)

val isAnyDragging = remember { mutableStateOf(false) }
val lastItemIdIndex = remember { mutableIntStateOf(4) }

val view = LocalView.current

Column(modifier) {
PreferenceGroupHeading(
stringResource(id = R.string.recents_actions_label),
)
Surface(
modifier = Modifier.padding(horizontal = 16.dp),
shape = MaterialTheme.shapes.large,
tonalElevation = if (!isAnyDragging.value) 1.dp else 0.dp,
) {
ReorderableColumn(
modifier = Modifier,
list = orderedItems,
onSettle = { fromIndex, toIndex ->
orderedItems = orderedItems.toMutableList().apply {
add(toIndex, removeAt(fromIndex))
}.toList().also { items ->
onOrderChange(
items.map { it.id }.joinToString(separator = ","),
)
isAnyDragging.value = false
lastItemIdIndex.intValue = items.last().id
}
},
onMove = {
isAnyDragging.value = true
if (Utilities.ATLEAST_U) {
view.performHapticFeedback(HapticFeedbackConstants.SEGMENT_FREQUENT_TICK)
}
},
) { index, item, isDragging ->
key(item.id) {
val scope = this

val interactionSource = remember { MutableInteractionSource() }

Card(
elevation = if (isDragging) {
CardDefaults.elevatedCardElevation()
} else {
CardDefaults.cardElevation(
0.dp,
)
},
colors = if (isDragging) {
CardDefaults.elevatedCardColors()
} else {
CardDefaults.cardColors(
Color.Transparent,
)
},
modifier = Modifier
.semantics {
customActions = listOf(
CustomAccessibilityAction(
label = "Move up",
action = {
if (index > 0) {
orderedItems =
orderedItems
.toMutableList()
.apply {
add(index - 1, removeAt(index))
}
true
} else {
false
}
},
),
CustomAccessibilityAction(
label = "Move down",
action = {
if (index < orderedItems.size - 1) {
orderedItems =
orderedItems
.toMutableList()
.apply {
add(index + 1, removeAt(index))
}
true
} else {
false
}
},
),
)
},
) {
DraggableSwitchPreference(
checked = item.adapter.state.value,
onCheckedChange = item.adapter::onChange,
label = item.label,
description = item.description,
interactionSource = interactionSource,
dragIndicator = {
DragHandle(
interactionSource = interactionSource,
scope = scope,
)
},
)
AnimatedVisibility(visible = !isAnyDragging.value) {
if (index != lastItemIdIndex.intValue) {
HorizontalDivider()
}
}
}
}
}
}

ExpandAndShrink(visible = order != DEFAULT_ORDER) {
PreferenceGroup {
ClickablePreference(label = stringResource(id = R.string.action_reset)) {
onOrderChange(DEFAULT_ORDER)
}
}
}
}
}

@Composable
fun DraggableSwitchPreference(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
label: String,
interactionSource: MutableInteractionSource,
dragIndicator: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
description: String? = null,
) {
PreferenceTemplate(
modifier = modifier.clickable(
enabled = enabled,
onClick = {
onCheckedChange(!checked)
},
interactionSource = interactionSource,
indication = ripple(),
),
contentModifier = Modifier
.fillMaxHeight()
.padding(vertical = 16.dp)
.padding(start = 16.dp),
title = { Text(text = label) },
description = { description?.let { Text(text = it) } },
startWidget = {
dragIndicator()
},
endWidget = {
Switch(
modifier = Modifier
.padding(all = 16.dp)
.height(24.dp),
checked = checked,
onCheckedChange = onCheckedChange,
enabled = enabled,
)
},
enabled = enabled,
applyPaddings = false,
)
}

@Composable
private fun DragHandle(
scope: ReorderableScope,
interactionSource: MutableInteractionSource,
modifier: Modifier = Modifier,
) {
val view = LocalView.current
IconButton(
modifier = with(scope) {
modifier.longPressDraggableHandle(
onDragStarted = {
if (Utilities.ATLEAST_U) {
view.performHapticFeedback(HapticFeedbackConstants.DRAG_START)
}
},
onDragStopped = {
if (Utilities.ATLEAST_R) {
view.performHapticFeedback(HapticFeedbackConstants.GESTURE_END)
}
},
)
},
onClick = {},
interactionSource = interactionSource,
) {
Icon(
imageVector = Icons.Rounded.DragHandle,
contentDescription = "Drag indicator",
modifier = Modifier.width(24.dp),
)
}
}
Loading

0 comments on commit e28129f

Please sign in to comment.