feat: currently airing widget

This commit is contained in:
rebelonion 2024-03-25 21:20:17 -05:00
parent 95cddbd409
commit df23b2f62f
15 changed files with 446 additions and 182 deletions

View file

@ -49,20 +49,21 @@
android:name=".App"
android:allowBackup="true"
android:banner="@mipmap/ic_banner_foreground"
android:enableOnBackInvokedCallback="true"
android:icon="${icon_placeholder}"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:enableOnBackInvokedCallback="true"
android:roundIcon="${icon_placeholder_round}"
android:supportsRtl="true"
android:theme="@style/Theme.Dantotsu"
android:usesCleartextTraffic="true"
tools:ignore="AllowBackup"
tools:targetApi="tiramisu">
<receiver
android:name=".widgets.CurrentlyAiringWidget"
android:exported="false">
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
@ -71,9 +72,15 @@
android:name="android.appwidget.provider"
android:resource="@xml/currently_airing_widget_info" />
</receiver>
<activity
android:name=".widgets.CurrentlyAiringWidgetConfigureActivity"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name=".notifications.IncognitoNotificationClickReceiver" />
<activity
android:name=".media.novel.novelreader.NovelReaderActivity"
android:configChanges="orientation|screenSize"
@ -106,27 +113,25 @@
android:parentActivityName=".MainActivity" />
<activity
android:name=".settings.ExtensionsActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name=".profile.ProfileActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name=".profile.FollowActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name=".profile.activity.FeedActivity"
android:label="Inbox Activity"
android:configChanges="orientation|screenSize|screenLayout"
android:parentActivityName=".MainActivity" >
</activity>
android:label="Inbox Activity"
android:parentActivityName=".MainActivity" />
<activity
android:name=".profile.activity.NotificationActivity"
android:label="Inbox Activity"
android:parentActivityName=".MainActivity" >
</activity>
android:parentActivityName=".MainActivity" />
<activity
android:name=".others.imagesearch.ImageSearchActivity"
android:parentActivityName=".MainActivity" />
@ -139,8 +144,9 @@
android:name=".media.CalendarActivity"
android:parentActivityName=".MainActivity" />
<activity android:name=".media.user.ListActivity" />
<activity android:name=".profile.SingleStatActivity"
android:parentActivityName=".profile.ProfileActivity"/>
<activity
android:name=".profile.SingleStatActivity"
android:parentActivityName=".profile.ProfileActivity" />
<activity
android:name=".media.manga.mangareader.MangaReaderActivity"
android:excludeFromRecents="true"
@ -152,7 +158,7 @@
android:name=".media.MediaDetailsActivity"
android:parentActivityName=".MainActivity"
android:theme="@style/Theme.Dantotsu.NeverCutout"
android:windowSoftInputMode="adjustResize|stateHidden"/>
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity android:name=".media.CharacterDetailsActivity" />
<activity android:name=".home.NoInternet" />
<activity
@ -234,7 +240,6 @@
<data android:host="discord.dantotsu.com" />
</intent-filter>
</activity>
<activity
android:name=".connections.anilist.UrlMedia"
android:configChanges="orientation|screenSize|layoutDirection"
@ -293,7 +298,9 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.ani" />
@ -306,22 +313,23 @@
android:exported="false"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<receiver android:name=".notifications.AlarmPermissionStateReceiver"
<receiver
android:name=".notifications.AlarmPermissionStateReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
</intent-filter>
</receiver>
<receiver android:name=".notifications.BootCompletedReceiver"
<receiver
android:name=".notifications.BootCompletedReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".notifications.anilist.AnilistNotificationReceiver"/>
<receiver android:name=".notifications.comment.CommentNotificationReceiver"/>
<receiver android:name=".notifications.subscription.SubscriptionNotificationReceiver"/>
<receiver android:name=".notifications.anilist.AnilistNotificationReceiver" />
<receiver android:name=".notifications.comment.CommentNotificationReceiver" />
<receiver android:name=".notifications.subscription.SubscriptionNotificationReceiver" />
<meta-data
android:name="preloaded_fonts"

View file

@ -154,6 +154,7 @@ class App : MultiDexApplication() {
companion object {
private var instance: App? = null
/** Reference to the application context.
*
* USE WITH EXTREME CAUTION!**/

View file

@ -1430,6 +1430,24 @@ Page(page:$page,perPage:50) {
)
}
suspend fun getUpcomingAnime(id: String): List<Media> {
val res = executeQuery<Query.MediaListCollection>(
"""{MediaListCollection(userId:$id,type:ANIME){lists{name entries{media{id,isFavourite,title{userPreferred,romaji}coverImage{medium}nextAiringEpisode{timeUntilAiring}}}}}}""",
force = true
)
val list = mutableListOf<Media>()
res?.data?.mediaListCollection?.lists?.forEach { listEntry ->
listEntry.entries?.forEach { entry ->
entry.media?.nextAiringEpisode?.timeUntilAiring?.let {
list.add(Media(entry.media!!))
}
}
}
return list.sortedBy { it.timeUntilAiring }
.distinctBy { it.id }
.filter { it.timeUntilAiring != null }
}
suspend fun isUserFav(favType: AnilistMutations.FavType, id: Int): Boolean { //anilist isFavourite is broken, so we need to check it manually
val res = getUserProfile(Anilist.userid?: return false)
return when (favType) {

View file

@ -58,6 +58,8 @@ data class Media(
var endDate: FuzzyDate? = null,
var popularity: Int? = null,
var timeUntilAiring: Long? = null,
var characters: ArrayList<Character>? = null,
var staff: ArrayList<Author>? = null,
var prequel: Media? = null,
@ -84,7 +86,7 @@ data class Media(
name = apiMedia.title!!.english,
nameRomaji = apiMedia.title!!.romaji,
userPreferredName = apiMedia.title!!.userPreferred,
cover = apiMedia.coverImage?.large,
cover = apiMedia.coverImage?.large ?: apiMedia.coverImage?.medium,
banner = apiMedia.bannerImage,
status = apiMedia.status.toString(),
isFav = apiMedia.isFavourite!!,
@ -97,6 +99,7 @@ data class Media(
startDate = apiMedia.startDate,
endDate = apiMedia.endDate,
favourites = apiMedia.favourites,
timeUntilAiring = apiMedia.nextAiringEpisode?.timeUntilAiring?.let { it.toLong() * 1000},
anime = if (apiMedia.type == MediaType.ANIME) Anime(
totalEpisodes = apiMedia.episodes,
nextAiringEpisode = apiMedia.nextAiringEpisode?.episode?.minus(1)

View file

@ -1,12 +1,24 @@
package ani.dantotsu.widgets
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.BitmapShader
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.Shader
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.util.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
@ -14,59 +26,47 @@ import java.net.URL
class CurrentlyAiringRemoteViewsFactory(private val context: Context) :
RemoteViewsService.RemoteViewsFactory {
private var widgetItems = mutableListOf<WidgetItem>()
private var refreshing = false
private val prefs =
context.getSharedPreferences(CurrentlyAiringWidget.PREFS_NAME, Context.MODE_PRIVATE)
override fun onCreate() {
// 4 items for testing
widgetItems.clear()
Logger.log("CurrentlyAiringRemoteViewsFactory onCreate")
widgetItems = List(4) {
WidgetItem(
"Show $it",
"$it days $it hours $it minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
}.toMutableList()
fillWidgetItems()
}
private fun timeUntil(timeUntil: Long): String {
val days = timeUntil / (1000 * 60 * 60 * 24)
val hours = (timeUntil % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
val minutes = ((timeUntil % (1000 * 60 * 60 * 24)) % (1000 * 60 * 60)) / (1000 * 60)
return "$days days $hours hours $minutes minutes"
}
override fun onDataSetChanged() {
// 4 items for testing
if (refreshing) return
Logger.log("CurrentlyAiringRemoteViewsFactory onDataSetChanged")
widgetItems.clear()
widgetItems.add(
WidgetItem(
"Show 1",
"1 day 2 hours 3 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 2",
"2 days 3 hours 4 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 3",
"3 days 4 hours 5 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 4",
"4 days 5 hours 6 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
widgetItems.add(
WidgetItem(
"Show 5",
"5 days 6 hours 7 minutes",
"https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/bx14741-alxqoP4yx6WF.jpg"
)
)
fillWidgetItems()
}
private fun fillWidgetItems() {
refreshing = true
val userId = PrefManager.getVal<String>(PrefName.AnilistUserId)
runBlocking(Dispatchers.IO) {
val upcoming = Anilist.query.getUpcomingAnime(userId)
upcoming.forEach {
widgetItems.add(
WidgetItem(
it.userPreferredName,
timeUntil(it.timeUntilAiring ?: 0),
it.cover ?: "",
it.id
)
)
}
refreshing = false
}
}
override fun onDestroy() {
@ -80,12 +80,20 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context) :
override fun getViewAt(position: Int): RemoteViews {
Logger.log("CurrentlyAiringRemoteViewsFactory getViewAt")
val item = widgetItems[position]
val titleTextColor = prefs.getInt(CurrentlyAiringWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE)
val countdownTextColor =
prefs.getInt(CurrentlyAiringWidget.PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE)
val rv = RemoteViews(context.packageName, R.layout.item_currently_airing_widget).apply {
setTextViewText(R.id.text_show_title, item.title)
setTextViewText(R.id.text_show_countdown, item.countdown)
setTextColor(R.id.text_show_title, titleTextColor)
setTextColor(R.id.text_show_countdown, countdownTextColor)
val bitmap = downloadImageAsBitmap(item.image)
//setImageViewUri(R.id.image_show_icon, Uri.parse(item.image))
setImageViewBitmap(R.id.image_show_icon, bitmap)
val fillInIntent = Intent().apply {
putExtra("mediaId", item.id)
}
setOnClickFillInIntent(R.id.widget_item, fillInIntent)
}
return rv
@ -108,16 +116,27 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context) :
}
} catch (e: Exception) {
e.printStackTrace()
// Handle the error according to your needs
} finally {
// Clean up resources
inputStream?.close()
urlConnection?.disconnect()
}
return bitmap
return bitmap?.let { roundCorners(it) }
}
private fun roundCorners(bitmap: Bitmap): Bitmap {
val cornerRadius = 20f
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
paint.isAntiAlias = true
paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val rect = RectF(0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat())
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint)
return output
}
override fun getLoadingView(): RemoteViews {
return RemoteViews(context.packageName, R.layout.item_currently_airing_widget)
}
@ -135,4 +154,4 @@ class CurrentlyAiringRemoteViewsFactory(private val context: Context) :
}
}
data class WidgetItem(val title: String, val countdown: String, val image: String)
data class WidgetItem(val title: String, val countdown: String, val image: String, val id: Int)

View file

@ -12,7 +12,9 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.net.Uri
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import ani.dantotsu.MainActivity
import ani.dantotsu.R
/**
@ -26,25 +28,15 @@ class CurrentlyAiringWidget : AppWidgetProvider() {
appWidgetIds: IntArray
) {
appWidgetIds.forEach { appWidgetId ->
val intent = Intent(context, CurrentlyAiringRemoteViewsService::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
}
val rv = RemoteViews(context.packageName, R.layout.currently_airing_widget).apply {
setRemoteAdapter(R.id.widgetListView, intent)
setEmptyView(R.id.widgetListView, R.id.empty_view)
}
val rv = updateAppWidget(context, appWidgetId)
appWidgetManager.updateAppWidget(appWidgetId, rv)
}
super.onUpdate(context, appWidgetManager, appWidgetIds)
}
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
// When the user deletes the widget, delete the preference associated with it.
for (appWidgetId in appWidgetIds) {
deleteTitlePref(context, appWidgetId)
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit().clear().apply()
}
super.onDeleted(context, appWidgetIds)
}
@ -57,34 +49,65 @@ class CurrentlyAiringWidget : AppWidgetProvider() {
super.onDisabled(context)
}
companion object {
fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
color: Int
) {
// Create an intent to launch the configuration activity when the widget is clicked
val intent = Intent(context, CurrentlyAiringWidgetConfigureActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
): RemoteViews {
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
val backgroundColor =
prefs.getInt(PREF_BACKGROUND_COLOR, ContextCompat.getColor(context, R.color.theme))
val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.GRAY)
val titleTextColor = prefs.getInt(PREF_TITLE_TEXT_COLOR, Color.WHITE)
val countdownTextColor = prefs.getInt(PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE)
// Get the gradient drawable resource and update its start color with the user-selected color
val intent = Intent(context, CurrentlyAiringRemoteViewsService::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
}
val gradientDrawable = ResourcesCompat.getDrawable(
context.resources,
R.drawable.gradient_background,
null
) as GradientDrawable
gradientDrawable.colors = intArrayOf(color, Color.GRAY) // End color is gray.
gradientDrawable.colors = intArrayOf(backgroundColor, backgroundFade)
val intentTemplate = Intent(context, MainActivity::class.java)
intentTemplate.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
intentTemplate.putExtra("fromWidget", true)
// Create the RemoteViews object and set the background
val views = RemoteViews(context.packageName, R.layout.currently_airing_widget).apply {
//setImageViewBitmap(R.id.backgroundView, convertDrawableToBitmap(gradientDrawable))
//setOnClickPendingIntent(R.id.backgroundView, pendingIntent)
setImageViewBitmap(R.id.backgroundView, convertDrawableToBitmap(gradientDrawable))
setTextColor(R.id.text_show_title, titleTextColor)
setTextColor(R.id.text_show_countdown, countdownTextColor)
setTextColor(R.id.widgetTitle, titleTextColor)
setRemoteAdapter(R.id.widgetListView, intent)
setEmptyView(R.id.widgetListView, R.id.empty_view)
setPendingIntentTemplate(
R.id.widgetListView,
PendingIntent.getActivity(
context,
0,
intentTemplate,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)
)
setOnClickPendingIntent(
R.id.logoView,
PendingIntent.getActivity(
context,
1,
Intent(context, CurrentlyAiringWidgetConfigureActivity::class.java).apply {
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
},
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
)
}
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
return views
}
private fun convertDrawableToBitmap(drawable: Drawable): Bitmap {
@ -94,6 +117,12 @@ class CurrentlyAiringWidget : AppWidgetProvider() {
drawable.draw(canvas)
return bitmap
}
const val PREFS_NAME = "ani.dantotsu.widgets.CurrentlyAiringWidget"
const val PREF_BACKGROUND_COLOR = "background_color"
const val PREF_BACKGROUND_FADE = "background_fade"
const val PREF_TITLE_TEXT_COLOR = "title_text_color"
const val PREF_COUNTDOWN_TEXT_COLOR = "countdown_text_color"
}
}
@ -102,11 +131,7 @@ internal fun updateAppWidget(
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val widgetText = loadTitlePref(context, appWidgetId)
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.currently_airing_widget)
views.setTextViewText(R.id.appwidget_text, widgetText)
// Instruct the widget manager to update the widget
val views = CurrentlyAiringWidget.updateAppWidget(context, appWidgetId)
appWidgetManager.updateAppWidget(appWidgetId, views)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetListView)
}

View file

@ -1,42 +1,36 @@
package ani.dantotsu.widgets
import android.app.Activity
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import ani.dantotsu.R
import ani.dantotsu.databinding.CurrentlyAiringWidgetConfigureBinding
import ani.dantotsu.themes.ThemeManager
import eltos.simpledialogfragment.SimpleDialog
import eltos.simpledialogfragment.color.SimpleColorDialog
/**
* The configuration screen for the [CurrentlyAiringWidget] AppWidget.
*/
class CurrentlyAiringWidgetConfigureActivity : Activity() {
class CurrentlyAiringWidgetConfigureActivity : AppCompatActivity(),
SimpleDialog.OnDialogResultListener {
private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
private lateinit var appWidgetText: EditText
private var onClickListener = View.OnClickListener {
val context = this@CurrentlyAiringWidgetConfigureActivity
// When the button is clicked, store the string locally
val widgetText = appWidgetText.text.toString()
saveTitlePref(context, appWidgetId, widgetText)
// It is the responsibility of the configuration activity to update the app widget
val appWidgetManager = AppWidgetManager.getInstance(context)
//updateAppWidget(context, appWidgetManager, appWidgetId)
CurrentlyAiringWidget.updateAppWidget(
updateAppWidget(
context,
appWidgetManager,
appWidgetId,
-1
)
// Make sure we pass back the original appWidgetId
val resultValue = Intent()
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
setResult(RESULT_OK, resultValue)
@ -45,21 +39,87 @@ class CurrentlyAiringWidgetConfigureActivity : Activity() {
private lateinit var binding: CurrentlyAiringWidgetConfigureBinding
public override fun onCreate(icicle: Bundle?) {
ThemeManager(this).applyTheme()
super.onCreate(icicle)
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if the user presses the back button.
setResult(RESULT_CANCELED)
binding = CurrentlyAiringWidgetConfigureBinding.inflate(layoutInflater)
setContentView(binding.root)
val prefs = getSharedPreferences(CurrentlyAiringWidget.PREFS_NAME, Context.MODE_PRIVATE)
binding.topBackgroundButton.setOnClickListener {
val tag = CurrentlyAiringWidget.PREF_BACKGROUND_COLOR
SimpleColorDialog().title(R.string.custom_theme)
.colorPreset(
prefs.getInt(
CurrentlyAiringWidget.PREF_BACKGROUND_COLOR,
ContextCompat.getColor(this, R.color.theme)
)
)
.colors(
this@CurrentlyAiringWidgetConfigureActivity,
SimpleColorDialog.MATERIAL_COLOR_PALLET
)
.allowCustom(true)
.showOutline(0x46000000)
.gridNumColumn(5)
.choiceMode(SimpleColorDialog.SINGLE_CHOICE)
.neg()
.show(this@CurrentlyAiringWidgetConfigureActivity, tag)
}
binding.bottomBackgroundButton.setOnClickListener {
val tag = CurrentlyAiringWidget.PREF_BACKGROUND_FADE
SimpleColorDialog().title(R.string.custom_theme)
.colorPreset(prefs.getInt(CurrentlyAiringWidget.PREF_BACKGROUND_FADE, Color.GRAY))
.colors(
this@CurrentlyAiringWidgetConfigureActivity,
SimpleColorDialog.MATERIAL_COLOR_PALLET
)
.allowCustom(true)
.showOutline(0x46000000)
.gridNumColumn(5)
.choiceMode(SimpleColorDialog.SINGLE_CHOICE)
.neg()
.show(this@CurrentlyAiringWidgetConfigureActivity, tag)
}
binding.titleColorButton.setOnClickListener {
val tag = CurrentlyAiringWidget.PREF_TITLE_TEXT_COLOR
SimpleColorDialog().title(R.string.custom_theme)
.colorPreset(prefs.getInt(CurrentlyAiringWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE))
.colors(
this@CurrentlyAiringWidgetConfigureActivity,
SimpleColorDialog.MATERIAL_COLOR_PALLET
)
.allowCustom(true)
.showOutline(0x46000000)
.gridNumColumn(5)
.choiceMode(SimpleColorDialog.SINGLE_CHOICE)
.neg()
.show(this@CurrentlyAiringWidgetConfigureActivity, tag)
}
binding.countdownColorButton.setOnClickListener {
val tag = CurrentlyAiringWidget.PREF_COUNTDOWN_TEXT_COLOR
SimpleColorDialog().title(R.string.custom_theme)
.colorPreset(
prefs.getInt(
CurrentlyAiringWidget.PREF_COUNTDOWN_TEXT_COLOR,
Color.WHITE
)
)
.colors(
this@CurrentlyAiringWidgetConfigureActivity,
SimpleColorDialog.MATERIAL_COLOR_PALLET
)
.allowCustom(true)
.showOutline(0x46000000)
.gridNumColumn(5)
.choiceMode(SimpleColorDialog.SINGLE_CHOICE)
.neg()
.show(this@CurrentlyAiringWidgetConfigureActivity, tag)
}
appWidgetText = binding.appwidgetText
binding.addButton.setOnClickListener(onClickListener)
// Find the widget id from the intent.
val intent = intent
val extras = intent.extras
if (extras != null) {
@ -68,43 +128,66 @@ class CurrentlyAiringWidgetConfigureActivity : Activity() {
)
}
// If this activity was started with an intent without an app widget ID, finish with an error.
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish()
return
}
appWidgetText.setText(
loadTitlePref(
this@CurrentlyAiringWidgetConfigureActivity,
appWidgetId
)
)
}
}
override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
if (which == SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE) {
when (dialogTag) {
CurrentlyAiringWidget.PREF_BACKGROUND_COLOR -> {
getSharedPreferences(
CurrentlyAiringWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
.putInt(
CurrentlyAiringWidget.PREF_BACKGROUND_COLOR,
extras.getInt(SimpleColorDialog.COLOR)
)
.apply()
}
private const val PREFS_NAME = "ani.dantotsu.parsers.CurrentlyAiringWidget"
private const val PREF_PREFIX_KEY = "appwidget_"
CurrentlyAiringWidget.PREF_BACKGROUND_FADE -> {
getSharedPreferences(
CurrentlyAiringWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
.putInt(
CurrentlyAiringWidget.PREF_BACKGROUND_FADE,
extras.getInt(SimpleColorDialog.COLOR)
)
.apply()
}
// Write the prefix to the SharedPreferences object for this widget
internal fun saveTitlePref(context: Context, appWidgetId: Int, text: String) {
val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit()
prefs.putString(PREF_PREFIX_KEY + appWidgetId, text)
prefs.apply()
}
CurrentlyAiringWidget.PREF_TITLE_TEXT_COLOR -> {
getSharedPreferences(
CurrentlyAiringWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
.putInt(
CurrentlyAiringWidget.PREF_TITLE_TEXT_COLOR,
extras.getInt(SimpleColorDialog.COLOR)
)
.apply()
}
// Read the prefix from the SharedPreferences object for this widget.
// If there is no preference saved, get the default from a resource
internal fun loadTitlePref(context: Context, appWidgetId: Int): String {
val prefs = context.getSharedPreferences(PREFS_NAME, 0)
val titleValue = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null)
return titleValue ?: context.getString(R.string.appwidget_text)
}
CurrentlyAiringWidget.PREF_COUNTDOWN_TEXT_COLOR -> {
getSharedPreferences(
CurrentlyAiringWidget.PREFS_NAME,
Context.MODE_PRIVATE
).edit()
.putInt(
CurrentlyAiringWidget.PREF_COUNTDOWN_TEXT_COLOR,
extras.getInt(SimpleColorDialog.COLOR)
)
.apply()
}
}
}
return true
}
internal fun deleteTitlePref(context: Context, appWidgetId: Int) {
val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit()
prefs.remove(PREF_PREFIX_KEY + appWidgetId)
prefs.apply()
}

View file

@ -4,5 +4,5 @@
<gradient
android:angle="270"
android:endColor="@color/grey_20"
android:startColor="#B313DC" />
android:startColor="@color/theme"/>
</shape>

View file

@ -20,8 +20,8 @@
<ImageView
android:id="@+id/logoView"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:foregroundGravity="center_vertical"
@ -31,20 +31,24 @@
<TextView
android:id="@+id/widgetTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="0dp"
android:layout_toEndOf="@+id/logoView"
android:gravity="center_vertical"
android:gravity="center_vertical|start"
android:textAlignment="viewStart"
android:maxLines="1"
android:ellipsize="end"
android:text="@string/currently_airing"
android:textSize="18sp"
android:textSize="20sp"
android:textStyle="bold" />
<ListView
android:id="@+id/widgetListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:layout_below="@id/widgetTitle" />
<TextView
@ -52,6 +56,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:maxLines="1"
android:ellipsize="end"
android:text="@string/no_shows_to_display"
android:textColor="#ffffff"
android:textSize="20sp"

View file

@ -2,6 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="16dp">
@ -9,14 +10,103 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:labelFor="@id/appwidget_text"
android:text="@string/configure" />
<EditText
android:id="@+id/appwidget_text"
<Button
android:id="@+id/topBackgroundButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/top_background_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_round_color_picker_24"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/bottomBackgroundButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/bottom_background_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_round_color_picker_24"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/titleColorButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/title_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_round_color_picker_24"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/countdownColorButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginStart="-31dp"
android:layout_marginEnd="-31dp"
android:background="@drawable/ui_bg"
android:backgroundTint="?attr/colorSecondary"
android:backgroundTintMode="src_atop"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="31dp"
android:paddingEnd="31dp"
android:text="@string/countdown_text_color"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_round_color_picker_24"
app:iconPadding="16dp"
app:iconSize="24dp"
app:iconTint="?attr/colorPrimary" />
<Button
android:id="@+id/add_button"

View file

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="8dp">
@ -9,9 +11,10 @@
<ImageView
android:id="@+id/image_show_icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/airing_image"
android:src="@drawable/ic_launcher_foreground" />
android:layout_height="wrap_content"
app:shapeAppearanceOverlay="@style/roundedImageView"
android:contentDescription="@string/airing_image"/>
<LinearLayout
android:layout_width="0dp"
@ -25,8 +28,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_bold"
android:text="Placeholder Title"
android:text=""
android:textColor="@color/bg_white"
android:maxLines="3"
android:ellipsize="end"
android:textSize="16sp" />
<TextView
@ -34,8 +39,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins"
android:text="Placeholder Countdown"
android:textColor="@color/grey_60"
android:text=""
android:textColor="@color/bg_white"
android:textSize="14sp" />
</LinearLayout>

View file

@ -19,6 +19,7 @@
<color name="button_icon">#A9FFFFFF</color>
<color name="nav_status">#80FFFFFF</color>
<color name="fav">#ad5edd</color>
<color name="theme">#B313DC</color>
<color name="incognito">#291B65</color>
<color name="filler">#54FF8400</color>
<color name="warning">#FF0000</color>

View file

@ -11,7 +11,7 @@
<string name="discord" translatable="false">https://discord.gg/4HPZ5nAWwM</string>
<string name="github" translatable="false">https://github.com/rebelonion/Dantotsu</string>
<string name="telegram" tools:ignore="Typos" translatable="false">https://t.me/+gzBCQExtLQo1YTNh </string>
<string name="telegram" translatable="false" tools:ignore="Typos">https://t.me/+gzBCQExtLQo1YTNh </string>
<string name="coffee" translatable="false">https://www.buymeacoffee.com/rebelonion</string>
<string name="home">Home</string>
@ -811,4 +811,9 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="donate">donate :)</string>
<string name="do_it">Do it!</string>
<string name="password">Password</string>
<string name="top_background_color">Top background color</string>
<string name="bottom_background_color">Bottom Background Color</string>
<string name="countdown_text_color">Countdown Text Color</string>
<string name="title_color">Title Color</string>
<string name="placeholder">Placeholder</string>
</resources>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_widget_description"
android:configure="ani.dantotsu.widgets.CurrentlyAiringWidgetConfigureActivity"
android:initialKeyguardLayout="@layout/currently_airing_widget"
android:initialLayout="@layout/currently_airing_widget"
android:minWidth="160dp"
@ -8,7 +9,5 @@
android:previewImage="@drawable/example_appwidget_preview"
android:previewLayout="@layout/currently_airing_widget"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"></appwidget-provider>
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen"/>

View file

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_widget_description"
android:configure="ani.dantotsu.widgets.CurrentlyAiringWidgetConfigureActivity"
android:initialKeyguardLayout="@layout/currently_airing_widget"
android:initialLayout="@layout/currently_airing_widget"
android:minWidth="160dp"
android:minHeight="160dp"
android:previewImage="@drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"></appwidget-provider>
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen"/>