Provide a widget option (#643)

* Added Glance dependency

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Defined Glance widget

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Replaced with new worker

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

* Rename ui/widget to ui/composable, move sync widget into ui/widget; adapt strings

---------

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
Arnau Mora 2024-03-20 12:37:57 +01:00 committed by GitHub
parent c3bf95fa5c
commit 28ddf5c86a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 174 additions and 34 deletions

View File

@ -179,6 +179,10 @@ dependencies {
debugImplementation(libs.compose.ui.tooling)
implementation(libs.compose.ui.toolingPreview)
// Glance Widgets
implementation(libs.glance.base)
implementation(libs.glance.material)
// Jetpack Room
implementation(libs.room.runtime)
implementation(libs.room.base)

View File

@ -295,6 +295,18 @@
android:resource="@xml/debug_paths" />
</provider>
<!-- Widgets -->
<receiver android:name=".ui.widget.SyncButtonWidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info_sync_button" />
</receiver>
</application>
<!-- package visiblity which apps do we need to see? -->

View File

@ -53,7 +53,7 @@ import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.Constants.withStatParams
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.widget.PixelBoxes
import at.bitfire.davdroid.ui.composable.PixelBoxes
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
import com.mikepenz.aboutlibraries.util.withJson

View File

@ -89,7 +89,7 @@ import at.bitfire.davdroid.syncadapter.SyncUtils
import at.bitfire.davdroid.ui.account.AccountActivity
import at.bitfire.davdroid.ui.intro.IntroActivity
import at.bitfire.davdroid.ui.setup.LoginActivity
import at.bitfire.davdroid.ui.widget.ActionCard
import at.bitfire.davdroid.ui.composable.ActionCard
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState

View File

@ -67,11 +67,11 @@ import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage
import at.bitfire.davdroid.ui.intro.OpenSourcePage
import at.bitfire.davdroid.ui.widget.EditTextInputDialog
import at.bitfire.davdroid.ui.widget.MultipleChoiceInputDialog
import at.bitfire.davdroid.ui.widget.Setting
import at.bitfire.davdroid.ui.widget.SettingsHeader
import at.bitfire.davdroid.ui.widget.SwitchSetting
import at.bitfire.davdroid.ui.composable.EditTextInputDialog
import at.bitfire.davdroid.ui.composable.MultipleChoiceInputDialog
import at.bitfire.davdroid.ui.composable.Setting
import at.bitfire.davdroid.ui.composable.SettingsHeader
import at.bitfire.davdroid.ui.composable.SwitchSetting
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.davdroid.util.TaskUtils
import at.bitfire.ical4android.TaskProvider

View File

@ -83,7 +83,7 @@ import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.syncadapter.BaseSyncWorker
import at.bitfire.davdroid.ui.widget.CardWithImage
import at.bitfire.davdroid.ui.composable.CardWithImage
import at.bitfire.ical4android.TaskProvider
import at.bitfire.ical4android.TaskProvider.ProviderName
import at.techbee.jtx.JtxContract

View File

@ -39,8 +39,8 @@ import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.PackageChangedReceiver
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.widget.CardWithImage
import at.bitfire.davdroid.ui.widget.PermissionSwitchRow
import at.bitfire.davdroid.ui.composable.CardWithImage
import at.bitfire.davdroid.ui.composable.PermissionSwitchRow
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.ical4android.TaskProvider
import java.util.logging.Level

View File

@ -54,8 +54,8 @@ import at.bitfire.davdroid.R
import at.bitfire.davdroid.util.TaskUtils
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
import at.bitfire.davdroid.ui.widget.CardWithImage
import at.bitfire.davdroid.ui.widget.RadioWithSwitch
import at.bitfire.davdroid.ui.composable.CardWithImage
import at.bitfire.davdroid.ui.composable.RadioWithSwitch
import at.bitfire.ical4android.TaskProvider
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel

View File

@ -2,11 +2,15 @@ package at.bitfire.davdroid.ui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import at.bitfire.davdroid.ui.widget.SafeAndroidUriHandler
import at.bitfire.davdroid.ui.composable.SafeAndroidUriHandler
import com.google.accompanist.themeadapter.material.MdcTheme
val primaryGreen = Color(0xff7cb342)
val onPrimaryGreen = Color(0xfffafafa)
@Suppress("DEPRECATION")
@Composable
fun AppTheme(content: @Composable () -> Unit) {

View File

@ -81,7 +81,7 @@ import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.OneTimeSyncWorker
import at.bitfire.davdroid.ui.AppTheme
import at.bitfire.davdroid.ui.PermissionsActivity
import at.bitfire.davdroid.ui.widget.ActionCard
import at.bitfire.davdroid.ui.composable.ActionCard
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import dagger.hilt.android.AndroidEntryPoint

View File

@ -69,12 +69,12 @@ import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.syncadapter.OneTimeSyncWorker
import at.bitfire.davdroid.syncadapter.Syncer
import at.bitfire.davdroid.ui.AppTheme
import at.bitfire.davdroid.ui.widget.ActionCard
import at.bitfire.davdroid.ui.widget.EditTextInputDialog
import at.bitfire.davdroid.ui.widget.MultipleChoiceInputDialog
import at.bitfire.davdroid.ui.widget.Setting
import at.bitfire.davdroid.ui.widget.SettingsHeader
import at.bitfire.davdroid.ui.widget.SwitchSetting
import at.bitfire.davdroid.ui.composable.ActionCard
import at.bitfire.davdroid.ui.composable.EditTextInputDialog
import at.bitfire.davdroid.ui.composable.MultipleChoiceInputDialog
import at.bitfire.davdroid.ui.composable.Setting
import at.bitfire.davdroid.ui.composable.SettingsHeader
import at.bitfire.davdroid.ui.composable.SwitchSetting
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.ical4android.TaskProvider
import at.bitfire.vcard4android.GroupMethod

View File

@ -56,7 +56,7 @@ import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.Constants.withStatParams
import at.bitfire.davdroid.R
import at.bitfire.davdroid.ui.AppTheme
import at.bitfire.davdroid.ui.widget.PermissionSwitchRow
import at.bitfire.davdroid.ui.composable.PermissionSwitchRow
import at.bitfire.davdroid.util.PermissionUtils
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel

View File

@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row

View File

@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import android.text.method.LinkMovementMethod
import android.widget.AutoCompleteTextView

View File

@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box

View File

@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column

View File

@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import android.content.Context
import android.graphics.Matrix

View File

@ -1,4 +1,4 @@
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column

View File

@ -1,4 +1,4 @@
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding

View File

@ -1,4 +1,4 @@
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row

View File

@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column

View File

@ -1,4 +1,4 @@
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import android.content.Context
import android.widget.Toast

View File

@ -1,4 +1,4 @@
package at.bitfire.davdroid.ui.widget
package at.bitfire.davdroid.ui.composable
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box

View File

@ -39,7 +39,7 @@ import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.Constants.withStatParams
import at.bitfire.davdroid.R
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.widget.CardWithImage
import at.bitfire.davdroid.ui.composable.CardWithImage
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors

View File

@ -60,7 +60,7 @@ import at.bitfire.davdroid.db.WebDavMount
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.ui.AppTheme
import at.bitfire.davdroid.ui.widget.PasswordTextField
import at.bitfire.davdroid.ui.composable.PasswordTextField
import at.bitfire.davdroid.webdav.CredentialsStore
import at.bitfire.davdroid.webdav.DavDocumentsProvider
import dagger.hilt.android.AndroidEntryPoint

View File

@ -0,0 +1,92 @@
package at.bitfire.davdroid.ui.widget
import android.accounts.AccountManager
import android.content.Context
import android.widget.Toast
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.glance.ColorFilter
import androidx.glance.GlanceId
import androidx.glance.GlanceModifier
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.LocalContext
import androidx.glance.action.clickable
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.cornerRadius
import androidx.glance.appwidget.provideContent
import androidx.glance.background
import androidx.glance.layout.Alignment
import androidx.glance.layout.Row
import androidx.glance.layout.fillMaxWidth
import androidx.glance.layout.padding
import androidx.glance.layout.size
import androidx.glance.text.Text
import androidx.glance.text.TextDefaults
import androidx.glance.unit.ColorProvider
import at.bitfire.davdroid.R
import at.bitfire.davdroid.syncadapter.OneTimeSyncWorker
import at.bitfire.davdroid.ui.onPrimaryGreen
import at.bitfire.davdroid.ui.primaryGreen
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SyncButtonWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
WidgetContent()
}
}
@Composable
private fun WidgetContent() {
val context = LocalContext.current
Row(
modifier = GlanceModifier
.fillMaxWidth()
.background(primaryGreen)
.cornerRadius(16.dp)
.padding(4.dp)
.clickable {
requestSync(context)
},
verticalAlignment = Alignment.CenterVertically
) {
Image(
provider = ImageProvider(R.drawable.ic_sync),
contentDescription = context.getString(R.string.widget_sync_all_accounts),
modifier = GlanceModifier
.padding(vertical = 8.dp, horizontal = 8.dp)
.size(32.dp),
colorFilter = ColorFilter.tint(ColorProvider(onPrimaryGreen))
)
Text(
text = context.getString(R.string.widget_sync_all),
modifier = GlanceModifier
.defaultWeight()
.padding(end = 8.dp),
style = TextDefaults.defaultTextStyle.copy(
color = ColorProvider(onPrimaryGreen),
fontSize = 16.sp
)
)
}
}
private fun requestSync(context: Context) = CoroutineScope(Dispatchers.IO).launch {
val accountType = context.getString(R.string.account_type)
val accounts = AccountManager.get(context).getAccountsByType(accountType)
for (account in accounts) {
OneTimeSyncWorker.enqueueAllAuthorities(context, account, manual = true)
}
withContext(Dispatchers.Main) {
Toast.makeText(context, R.string.sync_started, Toast.LENGTH_SHORT).show()
}
}
}

View File

@ -0,0 +1,8 @@
package at.bitfire.davdroid.ui.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class SyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = SyncButtonWidget()
}

View File

@ -490,6 +490,10 @@
<string name="sync_invalid_task">Received invalid task from server</string>
<string name="sync_invalid_resources_ignoring">Ignoring one or more invalid resources</string>
<!-- widgets -->
<string name="widget_sync_all">Sync all</string>
<string name="widget_sync_all_accounts">Sync all accounts</string>
<!-- cert4android -->
<string name="certificate_notification_connection_security">DAVx⁵: Connection security</string>
<string name="trust_certificate_unknown_certificate_found">DAVx⁵ has encountered an unknown certificate. Do you want to trust it?</string>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="100dp"
android:minHeight="30dp"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:maxResizeWidth="250dp"
android:maxResizeHeight="30dp"
android:resizeMode="horizontal"
tools:ignore="UnusedAttribute">
</appwidget-provider>

View File

@ -42,6 +42,7 @@ compose-bom = "2024.02.02"
compose-compiler = "1.5.8"
# don't update to dnsjava 3.x until API level 26 (Android 8) is the minimum API [https://github.com/bitfireAT/davx5/issues/453]
dnsjava = "2.1.9"
glance = "1.0.0"
hilt = "2.51"
jaredrummler-colorpicker = "1.1.0"
# keep in sync with * app/build.gradle.kts composeOptions.kotlinCompilerExtensionVersion
@ -103,6 +104,8 @@ compose-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
compose-ui-toolingPreview = { module = "androidx.compose.ui:ui-tooling-preview" }
dnsjava = { module = "dnsjava:dnsjava", version.ref = "dnsjava" }
glance-base = { module = "androidx.glance:glance-appwidget", version.ref = "glance" }
glance-material = { module = "androidx.glance:glance-material", version.ref = "glance" }
hilt-android-base = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" }