Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added widget with just a sync icon #1340

Open
wants to merge 6 commits into
base: main-ose
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,27 @@
</receiver>

<!-- Widgets -->
<receiver android:name=".ui.widget.SyncButtonWidgetReceiver"
<receiver android:name=".ui.widget.LabeledSyncButtonWidgetReceiver"
android:label="@string/widget_labeled_sync_label"
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" />
android:resource="@xml/widget_info_labeled_sync_button" />
</receiver>
<receiver android:name=".ui.widget.IconSyncButtonWidgetReceiver"
android:label="@string/widget_icon_sync_label"
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_icon_sync_button" />
</receiver>

</application>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/

package at.bitfire.davdroid.ui.widget

import android.content.Context
import android.widget.Toast
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
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.Box
import androidx.glance.layout.fillMaxSize
import androidx.glance.layout.size
import androidx.glance.unit.ColorProvider
import at.bitfire.davdroid.R
import at.bitfire.davdroid.ui.M3ColorScheme
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent

/**
* A widget with a "Sync all" button displaying just an icon to indicate the action.
*/
class IconSyncButtonWidget : GlanceAppWidget() {

// Hilt over @AndroidEntryPoint is not available for widgets
@EntryPoint
@InstallIn(SingletonComponent::class)
interface SyncButtonWidgetEntryPoint {
fun model(): SyncWidgetModel
}


override suspend fun provideGlance(context: Context, id: GlanceId) {
// initial data
val entryPoint = EntryPointAccessors.fromApplication<SyncButtonWidgetEntryPoint>(context)
val model = entryPoint.model()

// will be called when the widget is updated
provideContent {
WidgetContent(model)
}
}

@Composable
private fun WidgetContent(model: SyncWidgetModel) {
val context = LocalContext.current

Box(
modifier = GlanceModifier
.size(50.dp)
.background(ColorProvider(M3ColorScheme.primaryLight))
.cornerRadius(25.dp)
.clickable {
model.requestSync()
Toast.makeText(context, R.string.sync_started, Toast.LENGTH_SHORT).show()
},
contentAlignment = Alignment.Center,
) {
Image(
provider = ImageProvider(R.drawable.ic_sync),
contentDescription = context.getString(R.string.widget_sync_all_accounts),
modifier = GlanceModifier.fillMaxSize().size(32.dp),
colorFilter = ColorFilter.tint(
ColorProvider(M3ColorScheme.onPrimaryLight)
)
)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ package at.bitfire.davdroid.ui.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver

class SyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = SyncButtonWidget()
class IconSyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = IconSyncButtonWidget()
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,23 @@ import androidx.glance.layout.size
import androidx.glance.text.Text
import androidx.glance.text.TextDefaults
import androidx.glance.unit.ColorProvider
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.bitfire.davdroid.R
import at.bitfire.davdroid.repository.AccountRepository
import at.bitfire.davdroid.sync.worker.SyncWorkerManager
import at.bitfire.davdroid.ui.M3ColorScheme
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject

/**
* A widget with a "Sync all" button.
* A widget with a "Sync all" button displaying an icon and a label.
*/
class SyncButtonWidget : GlanceAppWidget() {
class LabeledSyncButtonWidget : GlanceAppWidget() {

// Hilt over @AndroidEntryPoint is not available for widgets
@EntryPoint
@InstallIn(SingletonComponent::class)
interface SyncButtonWidgetEntryPoint {
fun model(): Model
fun model(): SyncWidgetModel
}


Expand All @@ -68,7 +60,7 @@ class SyncButtonWidget : GlanceAppWidget() {
}

@Composable
private fun WidgetContent(model: Model) {
private fun WidgetContent(model: SyncWidgetModel) {
val context = LocalContext.current

Row(
Expand Down Expand Up @@ -105,18 +97,4 @@ class SyncButtonWidget : GlanceAppWidget() {
}
}


class Model @Inject constructor(
private val accountRepository: AccountRepository,
@ApplicationContext val context: Context,
private val syncWorkerManager: SyncWorkerManager
): ViewModel() {

fun requestSync() = viewModelScope.launch(Dispatchers.Default) {
for (account in accountRepository.getAll())
syncWorkerManager.enqueueOneTimeAllAuthorities(account, manual = true)
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/

package at.bitfire.davdroid.ui.widget

import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver

class LabeledSyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = LabeledSyncButtonWidget()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/

package at.bitfire.davdroid.ui.widget

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import at.bitfire.davdroid.repository.AccountRepository
import at.bitfire.davdroid.sync.worker.SyncWorkerManager
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject

class SyncWidgetModel @Inject constructor(
private val accountRepository: AccountRepository,
@ApplicationContext val context: Context,
private val syncWorkerManager: SyncWorkerManager
): ViewModel() {

fun requestSync() = viewModelScope.launch(Dispatchers.Default) {
for (account in accountRepository.getAll())
syncWorkerManager.enqueueOneTimeAllAuthorities(account, manual = true)
}

}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/shape_rounded_primary.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
-->

<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/primaryColor"/>
<corners android:radius="15dp"/>
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
21 changes: 21 additions & 0 deletions app/src/main/res/layout/widget_preview_icon_sync_button.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:background="@drawable/shape_rounded_primary">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/widget_sync_all_accounts"
android:src="@drawable/ic_sync"
android:padding="4dp"
app:tint="@android:color/white" />

</LinearLayout>
28 changes: 28 additions & 0 deletions app/src/main/res/layout/widget_preview_labeled_sync_button.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="150dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:gravity="center_vertical"
android:background="@drawable/shape_rounded_primary">

<ImageView
android:layout_width="24dp"
android:layout_height="match_parent"
android:contentDescription="@string/widget_sync_all_accounts"
android:src="@drawable/ic_sync"
android:padding="4dp"
app:tint="@android:color/white" />

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:text="@string/widget_sync_all"/>

</LinearLayout>
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,10 @@
<!-- widgets -->
<string name="widget_sync_all">Sync all</string>
<string name="widget_sync_all_accounts">Sync all accounts</string>
<string name="widget_labeled_sync_label">Labeled Sync Button</string>
<string name="widget_labeled_sync_description">A simple button for running synchronization manually with an icon and a label.</string>
<string name="widget_icon_sync_label">Icon Sync Button</string>
<string name="widget_icon_sync_description">A circular button for running synchronization manually.</string>

<!-- cert4android -->

Expand Down
13 changes: 13 additions & 0 deletions app/src/main/res/xml/widget_info_icon_sync_button.xml
Original file line number Diff line number Diff line change
@@ -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="30dp"
android:minHeight="50dp"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:resizeMode="none"
android:previewLayout="@layout/widget_preview_icon_sync_button"
android:description="@string/widget_icon_sync_description"
tools:ignore="UnusedAttribute">
</appwidget-provider>
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
android:maxResizeWidth="250dp"
android:maxResizeHeight="30dp"
android:resizeMode="horizontal"
android:previewLayout="@layout/widget_preview_labeled_sync_button"
android:description="@string/widget_labeled_sync_description"
tools:ignore="UnusedAttribute">
</appwidget-provider>