diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b10f2b619..d637034bc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -148,13 +148,21 @@
android:name="org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity"
android:label="@string/manage_categories" />
+
+
+
+
+
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt
index 082266b54..5ba52e13d 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppWidgetConfig.kt
@@ -1,15 +1,38 @@
package org.koitharu.kotatsu.core.prefs
+import android.appwidget.AppWidgetProvider
import android.content.Context
+import android.os.Build
import androidx.core.content.edit
private const val CATEGORY_ID = "cat_id"
+private const val BACKGROUND = "bg"
-class AppWidgetConfig(context: Context, val widgetId: Int) {
+class AppWidgetConfig(
+ context: Context,
+ cls: Class,
+ val widgetId: Int,
+) {
- private val prefs = context.getSharedPreferences("appwidget_$widgetId", Context.MODE_PRIVATE)
+ private val prefs = context.getSharedPreferences("appwidget_${cls.simpleName}_$widgetId", Context.MODE_PRIVATE)
var categoryId: Long
get() = prefs.getLong(CATEGORY_ID, 0L)
set(value) = prefs.edit { putLong(CATEGORY_ID, value) }
+
+ var hasBackground: Boolean
+ get() = prefs.getBoolean(BACKGROUND, Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
+ set(value) = prefs.edit { putBoolean(BACKGROUND, value) }
+
+ fun clear() {
+ prefs.edit { clear() }
+ }
+
+ fun copyFrom(other: AppWidgetConfig) {
+ prefs.edit {
+ clear()
+ putLong(CATEGORY_ID, other.categoryId)
+ putBoolean(BACKGROUND, other.hasBackground)
+ }
+ }
}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseAppWidgetProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseAppWidgetProvider.kt
new file mode 100644
index 000000000..cddc4af55
--- /dev/null
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseAppWidgetProvider.kt
@@ -0,0 +1,51 @@
+package org.koitharu.kotatsu.core.ui
+
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProvider
+import android.content.Context
+import android.widget.RemoteViews
+import androidx.annotation.CallSuper
+import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
+
+abstract class BaseAppWidgetProvider : AppWidgetProvider() {
+
+ @CallSuper
+ override fun onUpdate(
+ context: Context,
+ appWidgetManager: AppWidgetManager,
+ appWidgetIds: IntArray
+ ) {
+ appWidgetIds.forEach { id ->
+ val config = AppWidgetConfig(context, javaClass, id)
+ val views = onUpdateWidget(context, config)
+ appWidgetManager.updateAppWidget(id, views)
+ }
+ }
+
+ override fun onDeleted(context: Context, appWidgetIds: IntArray) {
+ super.onDeleted(context, appWidgetIds)
+ for (id in appWidgetIds) {
+ AppWidgetConfig(context, javaClass, id).clear()
+ }
+ }
+
+ override fun onRestored(context: Context, oldWidgetIds: IntArray, newWidgetIds: IntArray) {
+ super.onRestored(context, oldWidgetIds, newWidgetIds)
+ if (oldWidgetIds.size != newWidgetIds.size) {
+ return
+ }
+ for (i in oldWidgetIds.indices) {
+ val oldId = oldWidgetIds[i]
+ val newId = newWidgetIds[i]
+ val oldConfig = AppWidgetConfig(context, javaClass, oldId)
+ val newConfig = AppWidgetConfig(context, javaClass, newId)
+ newConfig.copyFrom(oldConfig)
+ oldConfig.clear()
+ }
+ }
+
+ protected abstract fun onUpdateWidget(
+ context: Context,
+ config: AppWidgetConfig,
+ ): RemoteViews
+}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeMutex2.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeMutex2.kt
new file mode 100644
index 000000000..ebcf0e63d
--- /dev/null
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/CompositeMutex2.kt
@@ -0,0 +1,43 @@
+package org.koitharu.kotatsu.core.util
+
+import androidx.collection.ArrayMap
+import kotlinx.coroutines.sync.Mutex
+
+class CompositeMutex2 : Set {
+
+ private val delegates = ArrayMap()
+
+ override val size: Int
+ get() = delegates.size
+
+ override fun contains(element: T): Boolean {
+ return delegates.containsKey(element)
+ }
+
+ override fun containsAll(elements: Collection): Boolean {
+ return elements.all { x -> delegates.containsKey(x) }
+ }
+
+ override fun isEmpty(): Boolean {
+ return delegates.isEmpty
+ }
+
+ override fun iterator(): Iterator {
+ return delegates.keys.iterator()
+ }
+
+ suspend fun lock(element: T) {
+ val mutex = synchronized(delegates) {
+ delegates.getOrPut(element) {
+ Mutex()
+ }
+ }
+ mutex.lock()
+ }
+
+ fun unlock(element: T) {
+ synchronized(delegates) {
+ delegates.remove(element)?.unlock()
+ }
+ }
+}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt
index 3a317dd07..9dd997814 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentListFactory.kt
@@ -55,6 +55,7 @@ class RecentListFactory(
.data(item.coverUrl)
.size(coverSize)
.tag(item.source)
+ .tag(item)
.transformations(transformation)
.build(),
).getDrawableOrThrow().toBitmap()
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetConfigActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetConfigActivity.kt
new file mode 100644
index 000000000..aba7d594d
--- /dev/null
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetConfigActivity.kt
@@ -0,0 +1,74 @@
+package org.koitharu.kotatsu.widget.recent
+
+import android.app.Activity
+import android.appwidget.AppWidgetManager
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.core.graphics.Insets
+import androidx.core.view.updatePadding
+import dagger.hilt.android.AndroidEntryPoint
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
+import org.koitharu.kotatsu.core.ui.BaseActivity
+import org.koitharu.kotatsu.databinding.ActivityAppwidgetRecentBinding
+import com.google.android.material.R as materialR
+
+@AndroidEntryPoint
+class RecentWidgetConfigActivity :
+ BaseActivity(),
+ View.OnClickListener {
+
+ private lateinit var config: AppWidgetConfig
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(ActivityAppwidgetRecentBinding.inflate(layoutInflater))
+ supportActionBar?.run {
+ setDisplayHomeAsUpEnabled(true)
+ setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
+ }
+ viewBinding.buttonDone.setOnClickListener(this)
+ val appWidgetId = intent?.getIntExtra(
+ AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID,
+ ) ?: AppWidgetManager.INVALID_APPWIDGET_ID
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finishAfterTransition()
+ return
+ }
+ config = AppWidgetConfig(this, RecentWidgetProvider::class.java, appWidgetId)
+ viewBinding.switchBackground.isChecked = config.hasBackground
+ }
+
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.button_done -> {
+ config.hasBackground = viewBinding.switchBackground.isChecked
+ updateWidget()
+ setResult(
+ Activity.RESULT_OK,
+ Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId),
+ )
+ finish()
+ }
+ }
+ }
+
+ override fun onWindowInsetsChanged(insets: Insets) {
+ viewBinding.root.updatePadding(
+ left = insets.left,
+ right = insets.right,
+ bottom = insets.bottom,
+ top = insets.top,
+ )
+ }
+
+ private fun updateWidget() {
+ val intent = Intent(this, RecentWidgetProvider::class.java)
+ intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
+ val ids = intArrayOf(config.widgetId)
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
+ sendBroadcast(intent)
+ }
+}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt
index dbeec5e2c..c94e449b9 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/recent/RecentWidgetProvider.kt
@@ -2,43 +2,52 @@ package org.koitharu.kotatsu.widget.recent
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
-import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
+import android.graphics.Color
import android.net.Uri
import android.widget.RemoteViews
import androidx.core.app.PendingIntentCompat
import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
+import org.koitharu.kotatsu.core.ui.BaseAppWidgetProvider
import org.koitharu.kotatsu.reader.ui.ReaderActivity
-class RecentWidgetProvider : AppWidgetProvider() {
+class RecentWidgetProvider : BaseAppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
- appWidgetIds.forEach { id ->
- val views = RemoteViews(context.packageName, R.layout.widget_recent)
- val adapter = Intent(context, RecentWidgetService::class.java)
- adapter.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
- adapter.data = Uri.parse(adapter.toUri(Intent.URI_INTENT_SCHEME))
- views.setRemoteAdapter(R.id.stackView, adapter)
- val intent = Intent(context, ReaderActivity::class.java)
- intent.action = ReaderActivity.ACTION_MANGA_READ
- views.setPendingIntentTemplate(
- R.id.stackView,
- PendingIntentCompat.getActivity(
- context,
- 0,
- intent,
- PendingIntent.FLAG_UPDATE_CURRENT,
- true,
- ),
- )
- views.setEmptyView(R.id.stackView, R.id.textView_holder)
- appWidgetManager.updateAppWidget(id, views)
- }
+ super.onUpdate(context, appWidgetManager, appWidgetIds)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.stackView)
}
+
+ override fun onUpdateWidget(context: Context, config: AppWidgetConfig): RemoteViews {
+ val views = RemoteViews(context.packageName, R.layout.widget_recent)
+ if (!config.hasBackground) {
+ views.setInt(R.id.widget_root, "setBackgroundColor", Color.TRANSPARENT)
+ } else {
+ views.setInt(R.id.widget_root, "setBackgroundResource", R.drawable.bg_appwidget_root)
+ }
+ val adapter = Intent(context, RecentWidgetService::class.java)
+ adapter.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId)
+ adapter.data = Uri.parse(adapter.toUri(Intent.URI_INTENT_SCHEME))
+ views.setRemoteAdapter(R.id.stackView, adapter)
+ val intent = Intent(context, ReaderActivity::class.java)
+ intent.action = ReaderActivity.ACTION_MANGA_READ
+ views.setPendingIntentTemplate(
+ R.id.stackView,
+ PendingIntentCompat.getActivity(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT,
+ true,
+ ),
+ )
+ views.setEmptyView(R.id.stackView, R.id.textView_holder)
+ return views
+ }
}
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfListFactory.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfListFactory.kt
index 38230a0df..4f66f82b1 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfListFactory.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfListFactory.kt
@@ -14,6 +14,7 @@ import kotlinx.coroutines.runBlocking
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.MangaIntent
import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
+import org.koitharu.kotatsu.core.ui.image.TrimTransformation
import org.koitharu.kotatsu.core.util.ext.getDrawableOrThrow
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.parsers.model.Manga
@@ -27,7 +28,7 @@ class ShelfListFactory(
) : RemoteViewsService.RemoteViewsFactory {
private val dataSet = ArrayList()
- private val config = AppWidgetConfig(context, widgetId)
+ private val config = AppWidgetConfig(context, ShelfWidgetProvider::class.java, widgetId)
private val transformation = RoundedCornersTransformation(
context.resources.getDimension(R.dimen.appwidget_corner_radius_inner),
)
@@ -66,7 +67,8 @@ class ShelfListFactory(
.data(item.coverUrl)
.size(coverSize)
.tag(item.source)
- .transformations(transformation)
+ .tag(item)
+ .transformations(transformation, TrimTransformation())
.build(),
).getDrawableOrThrow().toBitmap()
}.onSuccess { cover ->
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetConfigActivity.kt
similarity index 85%
rename from app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt
rename to app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetConfigActivity.kt
index e51c3c912..aee292134 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetConfigActivity.kt
@@ -8,7 +8,6 @@ import android.view.View
import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.core.graphics.Insets
-import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import dagger.hilt.android.AndroidEntryPoint
@@ -19,14 +18,14 @@ import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
-import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding
+import org.koitharu.kotatsu.databinding.ActivityAppwidgetShelfBinding
import org.koitharu.kotatsu.widget.shelf.adapter.CategorySelectAdapter
import org.koitharu.kotatsu.widget.shelf.model.CategoryItem
import com.google.android.material.R as materialR
@AndroidEntryPoint
-class ShelfConfigActivity :
- BaseActivity(),
+class ShelfWidgetConfigActivity :
+ BaseActivity(),
OnListItemClickListener,
View.OnClickListener {
@@ -37,16 +36,14 @@ class ShelfConfigActivity :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(ActivityCategoriesBinding.inflate(layoutInflater))
+ setContentView(ActivityAppwidgetShelfBinding.inflate(layoutInflater))
supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
}
adapter = CategorySelectAdapter(this)
viewBinding.recyclerView.adapter = adapter
- viewBinding.buttonDone.isVisible = true
viewBinding.buttonDone.setOnClickListener(this)
- viewBinding.fabAdd.hide()
val appWidgetId = intent?.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID,
@@ -55,8 +52,9 @@ class ShelfConfigActivity :
finishAfterTransition()
return
}
- config = AppWidgetConfig(this, appWidgetId)
+ config = AppWidgetConfig(this, ShelfWidgetProvider::class.java, appWidgetId)
viewModel.checkedId = config.categoryId
+ viewBinding.switchBackground.isChecked = config.hasBackground
viewModel.content.observe(this, this::onContentChanged)
viewModel.onError.observeEvent(this, SnackbarErrorObserver(viewBinding.recyclerView, null))
@@ -66,6 +64,7 @@ class ShelfConfigActivity :
when (v.id) {
R.id.button_done -> {
config.categoryId = viewModel.checkedId
+ config.hasBackground = viewBinding.switchBackground.isChecked
updateWidget()
setResult(
Activity.RESULT_OK,
@@ -81,11 +80,6 @@ class ShelfConfigActivity :
}
override fun onWindowInsetsChanged(insets: Insets) {
- viewBinding.fabAdd.updateLayoutParams {
- rightMargin = topMargin + insets.right
- leftMargin = topMargin + insets.left
- bottomMargin = topMargin + insets.bottom
- }
viewBinding.recyclerView.updatePadding(
left = insets.left,
right = insets.right,
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt
index 00bcd2651..5246ecd3f 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/shelf/ShelfWidgetProvider.kt
@@ -2,43 +2,52 @@ package org.koitharu.kotatsu.widget.shelf
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
-import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
+import android.graphics.Color
import android.net.Uri
import android.widget.RemoteViews
import androidx.core.app.PendingIntentCompat
import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
+import org.koitharu.kotatsu.core.ui.BaseAppWidgetProvider
import org.koitharu.kotatsu.reader.ui.ReaderActivity
-class ShelfWidgetProvider : AppWidgetProvider() {
+class ShelfWidgetProvider : BaseAppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
- appWidgetIds.forEach { id ->
- val views = RemoteViews(context.packageName, R.layout.widget_shelf)
- val adapter = Intent(context, ShelfWidgetService::class.java)
- adapter.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id)
- adapter.data = Uri.parse(adapter.toUri(Intent.URI_INTENT_SCHEME))
- views.setRemoteAdapter(R.id.gridView, adapter)
- val intent = Intent(context, ReaderActivity::class.java)
- intent.action = ReaderActivity.ACTION_MANGA_READ
- views.setPendingIntentTemplate(
- R.id.gridView,
- PendingIntentCompat.getActivity(
- context,
- 0,
- intent,
- PendingIntent.FLAG_UPDATE_CURRENT,
- true,
- ),
- )
- views.setEmptyView(R.id.gridView, R.id.textView_holder)
- appWidgetManager.updateAppWidget(id, views)
- }
+ super.onUpdate(context, appWidgetManager, appWidgetIds)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.gridView)
}
+
+ override fun onUpdateWidget(context: Context, config: AppWidgetConfig): RemoteViews {
+ val views = RemoteViews(context.packageName, R.layout.widget_shelf)
+ if (!config.hasBackground) {
+ views.setInt(R.id.widget_root, "setBackgroundColor", Color.TRANSPARENT)
+ } else {
+ views.setInt(R.id.widget_root, "setBackgroundResource", R.drawable.bg_appwidget_root)
+ }
+ val adapter = Intent(context, ShelfWidgetService::class.java)
+ adapter.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId)
+ adapter.data = Uri.parse(adapter.toUri(Intent.URI_INTENT_SCHEME))
+ views.setRemoteAdapter(R.id.gridView, adapter)
+ val intent = Intent(context, ReaderActivity::class.java)
+ intent.action = ReaderActivity.ACTION_MANGA_READ
+ views.setPendingIntentTemplate(
+ R.id.gridView,
+ PendingIntentCompat.getActivity(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT,
+ true,
+ ),
+ )
+ views.setEmptyView(R.id.gridView, R.id.textView_holder)
+ return views
+ }
}
diff --git a/app/src/main/res/drawable-v31/bg_appwidget_card.xml b/app/src/main/res/drawable-v31/bg_appwidget_card.xml
new file mode 100644
index 000000000..4cff15c71
--- /dev/null
+++ b/app/src/main/res/drawable-v31/bg_appwidget_card.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable-v31/bg_appwidget_root.xml b/app/src/main/res/drawable-v31/bg_appwidget_root.xml
new file mode 100644
index 000000000..cb7dbf180
--- /dev/null
+++ b/app/src/main/res/drawable-v31/bg_appwidget_root.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg_appwidget_card.xml b/app/src/main/res/drawable/bg_appwidget_card.xml
index 35a460504..b18a84c01 100644
--- a/app/src/main/res/drawable/bg_appwidget_card.xml
+++ b/app/src/main/res/drawable/bg_appwidget_card.xml
@@ -3,5 +3,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
-
-
\ No newline at end of file
+
+
diff --git a/app/src/main/res/drawable/bg_appwidget_root.xml b/app/src/main/res/drawable/bg_appwidget_root.xml
new file mode 100644
index 000000000..189ce5e53
--- /dev/null
+++ b/app/src/main/res/drawable/bg_appwidget_root.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_appwidget_recent.xml b/app/src/main/res/layout/activity_appwidget_recent.xml
new file mode 100644
index 000000000..7bb6d288e
--- /dev/null
+++ b/app/src/main/res/layout/activity_appwidget_recent.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_appwidget_shelf.xml b/app/src/main/res/layout/activity_appwidget_shelf.xml
new file mode 100644
index 000000000..8fae4aa9a
--- /dev/null
+++ b/app/src/main/res/layout/activity_appwidget_shelf.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_shelf.xml b/app/src/main/res/layout/item_shelf.xml
index b7d427b8b..b4f554bcc 100644
--- a/app/src/main/res/layout/item_shelf.xml
+++ b/app/src/main/res/layout/item_shelf.xml
@@ -5,7 +5,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
- android:theme="@style/Theme.Kotatsu.AppWidgetContainer">
+ android:theme="@style/Theme.Kotatsu.AppWidgetContainer"
+ tools:layout_width="116dp">
diff --git a/app/src/main/res/layout/widget_recent.xml b/app/src/main/res/layout/widget_recent.xml
index e79d63786..ebdc9b9ef 100644
--- a/app/src/main/res/layout/widget_recent.xml
+++ b/app/src/main/res/layout/widget_recent.xml
@@ -1,14 +1,16 @@
+ android:theme="@style/Theme.Kotatsu.AppWidgetContainer"
+ tools:background="@drawable/bg_appwidget_root">
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/widget_shelf.xml b/app/src/main/res/layout/widget_shelf.xml
index 3e3f7d869..1aa5e345e 100644
--- a/app/src/main/res/layout/widget_shelf.xml
+++ b/app/src/main/res/layout/widget_shelf.xml
@@ -1,21 +1,25 @@
+ android:clipToOutline="true"
+ android:outlineProvider="background"
+ android:theme="@style/Theme.Kotatsu.AppWidgetContainer"
+ tools:background="?android:attr/colorBackground">
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-v31/dimens.xml b/app/src/main/res/values-v31/dimens.xml
index e99ffda56..55a2f111a 100644
--- a/app/src/main/res/values-v31/dimens.xml
+++ b/app/src/main/res/values-v31/dimens.xml
@@ -1,4 +1,5 @@
@android:dimen/system_app_widget_inner_radius
-
\ No newline at end of file
+ @android:dimen/system_app_widget_background_radius
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 265cd5081..8d81e290d 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -54,7 +54,8 @@
24dp
8dp
- 8dp
+ 20dp
+ 28dp
44dp
diff --git a/app/src/main/res/xml/widget_recent.xml b/app/src/main/res/xml/widget_recent.xml
index 476c83cda..2277181fc 100644
--- a/app/src/main/res/xml/widget_recent.xml
+++ b/app/src/main/res/xml/widget_recent.xml
@@ -2,6 +2,7 @@