Migrate to MVVM
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package org.koitharu.kotatsu.widget
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import org.koitharu.kotatsu.favourites.domain.OnFavouritesChangeListener
|
||||
import org.koitharu.kotatsu.history.domain.OnHistoryChangeListener
|
||||
import org.koitharu.kotatsu.widget.recent.RecentWidgetProvider
|
||||
import org.koitharu.kotatsu.widget.shelf.ShelfWidgetProvider
|
||||
|
||||
class WidgetUpdater(private val context: Context) : OnFavouritesChangeListener,
|
||||
OnHistoryChangeListener {
|
||||
|
||||
override fun onFavouritesChanged(mangaId: Long) {
|
||||
updateWidget(ShelfWidgetProvider::class.java)
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
updateWidget(RecentWidgetProvider::class.java)
|
||||
}
|
||||
|
||||
private fun updateWidget(cls: Class<*>) {
|
||||
val intent = Intent(context, cls)
|
||||
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
val ids = AppWidgetManager.getInstance(context)
|
||||
.getAppWidgetIds(ComponentName(context, cls))
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.koitharu.kotatsu.widget.recent
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.RemoteViewsService
|
||||
import coil.ImageLoader
|
||||
import coil.executeBlocking
|
||||
import coil.request.ImageRequest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||
import org.koitharu.kotatsu.utils.ext.requireBitmap
|
||||
import java.io.IOException
|
||||
|
||||
class RecentListFactory(
|
||||
private val context: Context,
|
||||
private val historyRepository: HistoryRepository,
|
||||
private val coil: ImageLoader
|
||||
) : RemoteViewsService.RemoteViewsFactory {
|
||||
|
||||
private val dataSet = ArrayList<Manga>()
|
||||
|
||||
override fun onCreate() {
|
||||
}
|
||||
|
||||
override fun getLoadingView() = null
|
||||
|
||||
override fun getItemId(position: Int) = dataSet[position].id
|
||||
|
||||
override fun onDataSetChanged() {
|
||||
dataSet.clear()
|
||||
val data = runBlocking { historyRepository.getList(0, 10) }
|
||||
dataSet.addAll(data)
|
||||
}
|
||||
|
||||
override fun hasStableIds() = true
|
||||
|
||||
override fun getViewAt(position: Int): RemoteViews {
|
||||
val views = RemoteViews(context.packageName, R.layout.item_recent)
|
||||
val item = dataSet[position]
|
||||
try {
|
||||
val cover = coil.executeBlocking(
|
||||
ImageRequest.Builder(context)
|
||||
.data(item.coverUrl)
|
||||
.build()
|
||||
).requireBitmap()
|
||||
views.setImageViewBitmap(R.id.imageView_cover, cover)
|
||||
} catch (e: IOException) {
|
||||
views.setImageViewResource(R.id.imageView_cover, R.drawable.ic_placeholder)
|
||||
}
|
||||
val intent = Intent()
|
||||
intent.putExtra(DetailsActivity.EXTRA_MANGA_ID, item.id)
|
||||
views.setOnClickFillInIntent(R.id.imageView_cover, intent)
|
||||
return views
|
||||
}
|
||||
|
||||
override fun getCount() = dataSet.size
|
||||
|
||||
override fun getViewTypeCount() = 1
|
||||
|
||||
override fun onDestroy() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
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.net.Uri
|
||||
import android.widget.RemoteViews
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
|
||||
class RecentWidgetProvider : AppWidgetProvider() {
|
||||
|
||||
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, DetailsActivity::class.java)
|
||||
intent.action = DetailsActivity.ACTION_MANGA_VIEW
|
||||
views.setPendingIntentTemplate(
|
||||
R.id.stackView, PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
views.setEmptyView(R.id.stackView, R.id.textView_holder)
|
||||
appWidgetManager.updateAppWidget(id, views)
|
||||
}
|
||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.stackView)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.koitharu.kotatsu.widget.recent
|
||||
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class RecentWidgetService : RemoteViewsService() {
|
||||
|
||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||
return RecentListFactory(this, get(), get())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.koitharu.kotatsu.widget.shelf
|
||||
|
||||
import android.view.ViewGroup
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter
|
||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
|
||||
class CategorySelectAdapter(onItemClickListener: OnRecyclerItemClickListener<FavouriteCategory>? = null) :
|
||||
BaseRecyclerAdapter<FavouriteCategory, Boolean>(onItemClickListener) {
|
||||
|
||||
var checkedItemId = 0L
|
||||
private set
|
||||
|
||||
fun setCheckedId(id: Long) {
|
||||
val oldId = checkedItemId
|
||||
checkedItemId = id
|
||||
val oldPos = findItemPositionById(oldId)
|
||||
val newPos = findItemPositionById(id)
|
||||
if (newPos != -1) {
|
||||
notifyItemChanged(newPos)
|
||||
}
|
||||
if (oldPos != -1) {
|
||||
notifyItemChanged(oldPos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExtra(item: FavouriteCategory, position: Int) =
|
||||
checkedItemId == item.id
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup) = CategorySelectHolder(
|
||||
parent
|
||||
)
|
||||
|
||||
override fun onGetItemId(item: FavouriteCategory) = item.id
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.koitharu.kotatsu.widget.shelf
|
||||
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.item_category_checkable.*
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.list.BaseViewHolder
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
|
||||
class CategorySelectHolder(parent: ViewGroup) :
|
||||
BaseViewHolder<FavouriteCategory, Boolean>(parent, R.layout.item_category_checkable_single) {
|
||||
|
||||
override fun onBind(data: FavouriteCategory, extra: Boolean) {
|
||||
checkedTextView.text = data.title
|
||||
checkedTextView.isChecked = extra
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package org.koitharu.kotatsu.widget.shelf
|
||||
|
||||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.activity_categories.*
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class ShelfConfigActivity : BaseActivity(), OnRecyclerItemClickListener<FavouriteCategory> {
|
||||
|
||||
private val viewModel by viewModel<FavouritesCategoriesViewModel>()
|
||||
|
||||
private lateinit var adapter: CategorySelectAdapter
|
||||
private lateinit var config: AppWidgetConfig
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_categories)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
fab_add.imageTintList = ColorStateList.valueOf(Color.WHITE)
|
||||
adapter = CategorySelectAdapter(this)
|
||||
recyclerView.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL))
|
||||
recyclerView.adapter = adapter
|
||||
fab_add.isVisible = false
|
||||
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.getInstance(this, appWidgetId)
|
||||
adapter.setCheckedId(config.categoryId)
|
||||
|
||||
viewModel.categories.observe(this, ::onCategoriesChanged)
|
||||
viewModel.onError.observe(this, ::onError)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.opt_config, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
R.id.action_done -> {
|
||||
config.categoryId = adapter.checkedItemId
|
||||
updateWidget()
|
||||
setResult(
|
||||
Activity.RESULT_OK,
|
||||
Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, config.widgetId)
|
||||
)
|
||||
finish()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onItemClick(item: FavouriteCategory, position: Int, view: View) {
|
||||
adapter.setCheckedId(item.id)
|
||||
}
|
||||
|
||||
private fun onCategoriesChanged(categories: List<FavouriteCategory>) {
|
||||
val data = ArrayList<FavouriteCategory>(categories.size + 1)
|
||||
data += FavouriteCategory(0L, getString(R.string.all_favourites), -1, Date())
|
||||
data += categories
|
||||
adapter.replaceData(data)
|
||||
}
|
||||
|
||||
private fun onError(e: Throwable) {
|
||||
Snackbar.make(recyclerView, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun updateWidget() {
|
||||
val intent = Intent(this, ShelfWidgetProvider::class.java)
|
||||
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
val ids = intArrayOf(config.widgetId)
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.koitharu.kotatsu.widget.shelf
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViews
|
||||
import android.widget.RemoteViewsService
|
||||
import coil.ImageLoader
|
||||
import coil.executeBlocking
|
||||
import coil.request.ImageRequest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.utils.ext.requireBitmap
|
||||
import java.io.IOException
|
||||
|
||||
class ShelfListFactory(
|
||||
private val context: Context,
|
||||
private val favouritesRepository: FavouritesRepository,
|
||||
private val coil: ImageLoader,
|
||||
widgetId: Int
|
||||
) : RemoteViewsService.RemoteViewsFactory {
|
||||
|
||||
private val dataSet = ArrayList<Manga>()
|
||||
private val config = AppWidgetConfig.getInstance(context, widgetId)
|
||||
|
||||
override fun onCreate() {
|
||||
}
|
||||
|
||||
override fun getLoadingView() = null
|
||||
|
||||
override fun getItemId(position: Int) = dataSet[position].id
|
||||
|
||||
override fun onDataSetChanged() {
|
||||
dataSet.clear()
|
||||
val data = runBlocking {
|
||||
val category = config.categoryId
|
||||
if (category == 0L) {
|
||||
favouritesRepository.getAllManga()
|
||||
} else {
|
||||
favouritesRepository.getManga(category)
|
||||
}
|
||||
}
|
||||
dataSet.addAll(data)
|
||||
}
|
||||
|
||||
override fun hasStableIds() = true
|
||||
|
||||
override fun getViewAt(position: Int): RemoteViews {
|
||||
val views = RemoteViews(context.packageName, R.layout.item_shelf)
|
||||
val item = dataSet[position]
|
||||
views.setTextViewText(R.id.textView_title, item.title)
|
||||
try {
|
||||
val cover = coil.executeBlocking(
|
||||
ImageRequest.Builder(context)
|
||||
.data(item.coverUrl)
|
||||
.build()
|
||||
).requireBitmap()
|
||||
views.setImageViewBitmap(R.id.imageView_cover, cover)
|
||||
} catch (e: IOException) {
|
||||
views.setImageViewResource(R.id.imageView_cover, R.drawable.ic_placeholder)
|
||||
}
|
||||
val intent = Intent()
|
||||
intent.putExtra(DetailsActivity.EXTRA_MANGA_ID, item.id)
|
||||
views.setOnClickFillInIntent(R.id.rootLayout, intent)
|
||||
return views
|
||||
}
|
||||
|
||||
override fun getCount() = dataSet.size
|
||||
|
||||
override fun getViewTypeCount() = 1
|
||||
|
||||
override fun onDestroy() = Unit
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
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.net.Uri
|
||||
import android.widget.RemoteViews
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
|
||||
class ShelfWidgetProvider : AppWidgetProvider() {
|
||||
|
||||
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, DetailsActivity::class.java)
|
||||
intent.action = DetailsActivity.ACTION_MANGA_VIEW
|
||||
views.setPendingIntentTemplate(
|
||||
R.id.gridView, PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
views.setEmptyView(R.id.gridView, R.id.textView_holder)
|
||||
appWidgetManager.updateAppWidget(id, views)
|
||||
}
|
||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.gridView)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.koitharu.kotatsu.widget.shelf
|
||||
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class ShelfWidgetService : RemoteViewsService() {
|
||||
|
||||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
|
||||
val widgetId = intent.getIntExtra(
|
||||
AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID
|
||||
)
|
||||
return ShelfListFactory(this, get(), get(), widgetId)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user