Skip to content

Commit 996e543

Browse files
committed
bugfix: fixed favorites widget
1 parent 628c9c9 commit 996e543

19 files changed

Lines changed: 216 additions & 293 deletions

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ dependencies {
111111
implementation(libs.androidx.core.splashscreen)
112112
implementation(libs.androidx.appcompat)
113113
implementation(libs.androidx.material)
114+
implementation(libs.androidx.glance.appwidget)
114115
implementation(libs.androidx.navigation.compose)
115116
implementation(libs.androidx.window)
116117
implementation(libs.androidx.work.runtime.ktx)

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,14 @@
5858
</intent-filter>
5959
</receiver>
6060
<receiver
61-
android:name=".widgets.FavoritesWidget"
61+
android:name=".widgets.FavoritesGlanceWidgetReceiver"
6262
android:exported="false">
6363
<intent-filter>
6464
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
6565
</intent-filter>
66-
6766
<meta-data
6867
android:name="android.appwidget.provider"
69-
android:resource="@xml/favorites_widget_info" />
68+
android:resource="@xml/favorites_glance_widget_info" />
7069
</receiver>
7170
<receiver
7271
android:name=".receivers.TaskerReceiver"
@@ -76,9 +75,6 @@
7675
</intent-filter>
7776
</receiver>
7877

79-
<service
80-
android:name=".widgets.FavoritesWidgetService"
81-
android:permission="android.permission.BIND_REMOTEVIEWS" />
8278
<service
8379
android:name=".services.tiles.StartUpTileService"
8480
android:exported="true"

app/src/main/kotlin/com/androidvip/sysctlgui/di/PresentationModule.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import com.androidvip.sysctlgui.ui.presets.PresetsViewModel
77
import com.androidvip.sysctlgui.ui.search.SearchViewModel
88
import com.androidvip.sysctlgui.ui.settings.SettingsViewModel
99
import com.androidvip.sysctlgui.ui.user.UserParamsViewModel
10-
import com.androidvip.sysctlgui.widgets.FavoriteWidgetParamUpdater
10+
import com.androidvip.sysctlgui.widgets.UpdateFavoriteWidgetUseCase
1111
import org.koin.android.ext.koin.androidContext
1212
import org.koin.core.module.dsl.singleOf
1313
import org.koin.core.module.dsl.viewModelOf
@@ -22,5 +22,5 @@ internal val presentationModule = module {
2222
singleOf(::PresetsViewModel)
2323
viewModelOf(::UserParamsViewModel)
2424

25-
single { FavoriteWidgetParamUpdater(androidContext()).getListener() }
25+
factory { UpdateFavoriteWidgetUseCase(androidContext()) }
2626
}

app/src/main/kotlin/com/androidvip/sysctlgui/ui/main/AppNavHost.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@ import com.androidvip.sysctlgui.ui.settings.SettingsScreen
2323
import com.androidvip.sysctlgui.ui.user.UserParamsScreen
2424

2525
@Composable
26-
internal fun AppNavHost(innerPadding: PaddingValues, navController: NavHostController) {
26+
internal fun AppNavHost(
27+
innerPadding: PaddingValues,
28+
navController: NavHostController,
29+
startDestination: UiRoute = UiRoute.BrowseParams
30+
) {
2731
NavHost(
2832
modifier = Modifier.padding(innerPadding),
2933
navController = navController,
30-
startDestination = UiRoute.BrowseParams,
34+
startDestination = startDestination,
3135
enterTransition = { scaleIn(initialScale = 0.9f) + fadeIn() },
3236
exitTransition = { scaleOut(targetScale = 0.9f) + fadeOut() },
3337
popEnterTransition = { scaleIn(initialScale = 1.1f) + fadeIn() },

app/src/main/kotlin/com/androidvip/sysctlgui/ui/main/MainActivity.kt

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import androidx.activity.enableEdgeToEdge
1212
import androidx.activity.result.contract.ActivityResultContracts
1313
import androidx.compose.foundation.isSystemInDarkTheme
1414
import androidx.core.os.postDelayed
15+
import com.androidvip.sysctlgui.core.navigation.UiRoute
1516
import com.androidvip.sysctlgui.design.theme.SysctlGuiTheme
17+
import com.androidvip.sysctlgui.domain.enums.Actions
1618
import com.androidvip.sysctlgui.domain.repository.AppPrefs
1719
import org.koin.android.ext.android.inject
1820

@@ -38,37 +40,34 @@ class MainActivity : ComponentActivity() {
3840

3941
setContent {
4042
// TODO: Make the switch dynamic with the view model
41-
// TODO: Test presets
4243
// TODO: Translations
43-
// TODO: Handle shortcuts / widgets
4444
SysctlGuiTheme(
4545
darkTheme = prefs.forceDark || isSystemInDarkTheme(),
4646
contrastLevel = prefs.contrastLevel,
4747
dynamicColor = prefs.dynamicColors
4848
) {
49-
MainScreen()
49+
MainScreen(startDestination = getRouteFromIntent())
5050
}
5151
}
5252

5353
Handler(mainLooper).postDelayed(1000) {
5454
checkNotificationPermission()
5555
}
56-
57-
navigateFromIntent()
5856
}
5957

60-
private fun navigateFromIntent() {
61-
// TODO: handle intent
62-
/*val fragmentName = intent.getStringExtra(EXTRA_DESTINATION) ?: return
63-
when (fragmentName) {
64-
Actions.BrowseParams.name -> R.id.navigationBrowse
65-
Actions.ListParams.name -> R.id.navigationList
66-
Actions.ExportParams.name -> R.id.navigationExport
67-
Actions.OpenSettings.name -> R.id.navigationSettings
68-
else -> null
69-
}?.let { id ->
70-
navHost.navController.navigate(id)
71-
}*/
58+
private fun getRouteFromIntent(): UiRoute {
59+
val extraDestination = intent.getStringExtra(EXTRA_DESTINATION)
60+
?: return UiRoute.BrowseParams
61+
62+
val extraParamName = intent.getStringExtra(EXTRA_PARAM_NAME)
63+
64+
return when (extraDestination) {
65+
Actions.BrowseParams.name -> UiRoute.BrowseParams
66+
Actions.ExportParams.name -> UiRoute.Presets
67+
Actions.OpenSettings.name -> UiRoute.Settings
68+
Actions.EditParam.name -> UiRoute.EditParam(extraParamName.orEmpty())
69+
else -> UiRoute.BrowseParams
70+
}
7271
}
7372

7473
private fun checkNotificationPermission() {
@@ -83,5 +82,6 @@ class MainActivity : ComponentActivity() {
8382

8483
companion object {
8584
internal const val EXTRA_DESTINATION = "destination"
85+
internal const val EXTRA_PARAM_NAME = "paramName"
8686
}
8787
}

app/src/main/kotlin/com/androidvip/sysctlgui/ui/main/MainScreen.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ import org.koin.androidx.compose.koinViewModel
2828

2929
@OptIn(ExperimentalMaterial3Api::class)
3030
@Composable
31-
fun MainScreen(viewModel: MainViewModel = koinViewModel()) {
31+
fun MainScreen(
32+
viewModel: MainViewModel = koinViewModel(),
33+
startDestination: UiRoute = UiRoute.BrowseParams
34+
) {
3235
val state by viewModel.uiState.collectAsStateWithLifecycle()
3336
val navController = rememberNavController()
3437
val snackbarHostState = remember { SnackbarHostState() }
@@ -46,14 +49,15 @@ fun MainScreen(viewModel: MainViewModel = koinViewModel()) {
4649
}
4750
}
4851

49-
MainScreenContent(state, navController, snackbarHostState)
52+
MainScreenContent(state, navController, snackbarHostState, startDestination)
5053
}
5154

5255
@Composable
5356
private fun MainScreenContent(
5457
state: MainViewState,
5558
navController: NavHostController,
56-
snackbarHostState: SnackbarHostState
59+
snackbarHostState: SnackbarHostState,
60+
startDestination: UiRoute = UiRoute.BrowseParams
5761
) {
5862
val onBackPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
5963

@@ -92,7 +96,8 @@ private fun MainScreenContent(
9296
content = { innerPadding ->
9397
AppNavHost(
9498
innerPadding = innerPadding,
95-
navController = navController
99+
navController = navController,
100+
startDestination = startDestination
96101
)
97102
}
98103
)

app/src/main/kotlin/com/androidvip/sysctlgui/ui/params/edit/EditParamViewModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.androidvip.sysctlgui.domain.usecase.IsTaskerInstalledUseCase
1313
import com.androidvip.sysctlgui.domain.usecase.UpsertUserParamUseCase
1414
import com.androidvip.sysctlgui.helpers.UiKernelParamMapper
1515
import com.androidvip.sysctlgui.utils.BaseViewModel
16+
import com.androidvip.sysctlgui.widgets.UpdateFavoriteWidgetUseCase
1617
import kotlinx.coroutines.launch
1718

1819
class EditParamViewModel(
@@ -23,6 +24,7 @@ class EditParamViewModel(
2324
private val getRuntimeParam: GetRuntimeParamUseCase,
2425
private val getUserParam: GetUserParamByNameUseCase,
2526
private val isTaskerInstalled: IsTaskerInstalledUseCase,
27+
private val updateFavoriteWidget: UpdateFavoriteWidgetUseCase,
2628
private val appPrefs: AppPrefs
2729
) : BaseViewModel<EditParamViewEvent, EditParamViewState, EditParamViewEffect>() {
2830
private val paramName: String? = savedStateHandle.get<String>(PARAM_NAME_KEY)
@@ -80,6 +82,7 @@ class EditParamViewModel(
8082
}
8183
}
8284
previousKernelParamValue = oldParam.value
85+
updateFavoriteWidget()
8386
}.onFailure {
8487
Log.e("EditParamViewModel", "Failed to apply param", it)
8588
setEffect {

app/src/main/kotlin/com/androidvip/sysctlgui/ui/start/StartActivity.kt

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -73,40 +73,11 @@ class StartActivity : AppCompatActivity() {
7373
}
7474

7575
private fun navigate() {
76-
val shortcutNames = arrayOf(
77-
Actions.BrowseParams.name,
78-
Actions.ExportParams.name,
79-
Actions.OpenSettings.name
80-
)
81-
val nextIntent = when (intent.action) {
82-
in shortcutNames -> {
83-
Intent(this, MainActivity::class.java).apply {
84-
putExtra(MainActivity.EXTRA_DESTINATION, intent.action)
85-
}
86-
}
87-
88-
Actions.EditParam.name -> {
89-
Intent(this, MainActivity::class.java)
90-
// TODO: handle edit param intent
91-
/*Intent(this, EditKernelParamActivity::class.java).apply {
92-
putExtra(
93-
EditKernelParamActivity.EXTRA_PARAM,
94-
intent.extras!!.getParcelable<KernelParam>(
95-
EditKernelParamActivity.EXTRA_PARAM
96-
)
97-
)
98-
putExtra(
99-
EditKernelParamActivity.EXTRA_EDIT_SAVED_PARAM,
100-
intent.getBooleanExtra(
101-
EditKernelParamActivity.EXTRA_EDIT_SAVED_PARAM,
102-
false
103-
)
104-
)
105-
}*/
106-
}
107-
108-
else -> {
109-
Intent(this, MainActivity::class.java)
76+
val shortcutNames = Actions.entries.map { it.name }
77+
val nextIntent = Intent(this, MainActivity::class.java).apply {
78+
if (intent.action in shortcutNames) {
79+
putExtra(MainActivity.EXTRA_DESTINATION, intent.action)
80+
putExtras(intent.extras ?: Bundle())
11081
}
11182
}
11283

app/src/main/kotlin/com/androidvip/sysctlgui/widgets/FavoriteWidgetParamUpdater.kt

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.androidvip.sysctlgui.widgets
2+
3+
import android.content.Context
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.ui.unit.dp
6+
import androidx.compose.ui.unit.sp
7+
import androidx.glance.GlanceId
8+
import androidx.glance.GlanceModifier
9+
import androidx.glance.action.actionParametersOf
10+
import androidx.glance.action.clickable
11+
import androidx.glance.appwidget.GlanceAppWidget
12+
import androidx.glance.appwidget.action.actionRunCallback
13+
import androidx.glance.appwidget.lazy.LazyColumn
14+
import androidx.glance.appwidget.lazy.items
15+
import androidx.glance.appwidget.provideContent
16+
import androidx.glance.background
17+
import androidx.glance.layout.Alignment
18+
import androidx.glance.layout.Column
19+
import androidx.glance.layout.Spacer
20+
import androidx.glance.layout.fillMaxSize
21+
import androidx.glance.layout.fillMaxWidth
22+
import androidx.glance.layout.height
23+
import androidx.glance.layout.padding
24+
import androidx.glance.text.FontWeight
25+
import androidx.glance.text.Text
26+
import androidx.glance.text.TextStyle
27+
import androidx.glance.unit.ColorProvider
28+
import com.androidvip.sysctlgui.design.theme.onPrimaryContainerLight
29+
import com.androidvip.sysctlgui.design.theme.primaryContainerLight
30+
import com.androidvip.sysctlgui.design.theme.primaryLight
31+
import com.androidvip.sysctlgui.domain.models.KernelParam
32+
import com.androidvip.sysctlgui.domain.usecase.GetUserParamsUseCase
33+
import org.koin.core.component.KoinComponent
34+
import org.koin.core.component.inject
35+
36+
class FavoritesGlanceWidget : GlanceAppWidget(), KoinComponent {
37+
private val getUserParamsUseCase: GetUserParamsUseCase by inject()
38+
39+
override suspend fun provideGlance(context: Context, id: GlanceId) {
40+
val favoriteParams = getUserParamsUseCase().filter { it.isFavorite }
41+
42+
provideContent {
43+
FavoritesWidgetContent(params = favoriteParams)
44+
}
45+
}
46+
47+
@Composable
48+
fun FavoritesWidgetContent(params: List<KernelParam>) {
49+
Column(
50+
modifier = GlanceModifier
51+
.fillMaxSize()
52+
.background(primaryContainerLight)
53+
.padding(16.dp),
54+
horizontalAlignment = Alignment.Horizontal.Start
55+
) {
56+
Text(
57+
text = "Favorite Kernel Params",
58+
style = TextStyle(
59+
fontWeight = FontWeight.Bold,
60+
fontSize = 16.sp,
61+
color = ColorProvider(onPrimaryContainerLight)
62+
),
63+
modifier = GlanceModifier.padding(vertical = 8.dp)
64+
)
65+
Spacer(GlanceModifier.height(8.dp))
66+
67+
if (params.isEmpty()) {
68+
Text("No favorite parameters yet.")
69+
} else {
70+
LazyColumn {
71+
items(params) { param ->
72+
FavoriteItem(param = param)
73+
Spacer(GlanceModifier.height(4.dp))
74+
}
75+
}
76+
}
77+
}
78+
}
79+
80+
@Composable
81+
fun FavoriteItem(param: KernelParam) {
82+
Column(
83+
modifier = GlanceModifier
84+
.padding(vertical = 8.dp)
85+
.fillMaxWidth()
86+
.clickable(
87+
onClick = actionRunCallback<ViewKernelParamDetailsAction>(
88+
parameters = actionParametersOf(kernelParamNameKey to param.path)
89+
)
90+
)
91+
) {
92+
Text(
93+
text = param.name,
94+
style = TextStyle(
95+
fontWeight = FontWeight.Medium,
96+
color = ColorProvider(primaryLight)
97+
)
98+
)
99+
Text(
100+
text = param.value,
101+
style = TextStyle(
102+
fontWeight = FontWeight.Medium,
103+
color = ColorProvider(primaryLight)
104+
)
105+
)
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)