Profile Stats Widget (#292)
* feat: create a statistics widget * feat: mirror app color option * fix: the minimum size cut off * feat: make the stat widget decent * fix: prevent bleeding edges * fix: PREVENT BLEEDING EDGES! * fix: we didn't really need an overlay
This commit is contained in:
parent
7bcc01b94e
commit
f83d1d8d84
16 changed files with 652 additions and 2 deletions
|
@ -79,6 +79,18 @@
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".widgets.statistics.ProfileStatsWidget"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/statistics_widget_info" />
|
||||||
|
</receiver>
|
||||||
<receiver android:name=".notifications.IncognitoNotificationClickReceiver" />
|
<receiver android:name=".notifications.IncognitoNotificationClickReceiver" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -115,6 +127,14 @@
|
||||||
android:name=".settings.ExtensionsActivity"
|
android:name=".settings.ExtensionsActivity"
|
||||||
android:parentActivityName=".MainActivity"
|
android:parentActivityName=".MainActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden" />
|
android:windowSoftInputMode="adjustResize|stateHidden" />
|
||||||
|
<activity
|
||||||
|
android:name=".widgets.statistics.ProfileStatsConfigure"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".profile.ProfileActivity"
|
android:name=".profile.ProfileActivity"
|
||||||
android:parentActivityName=".MainActivity"
|
android:parentActivityName=".MainActivity"
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package ani.dantotsu.widgets.statistics
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
|
import ani.dantotsu.databinding.StatisticsWidgetConfigureBinding
|
||||||
|
|
||||||
|
import ani.dantotsu.themes.ThemeManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration screen for the [ProfileStatsWidget] AppWidget.
|
||||||
|
*/
|
||||||
|
class ProfileStatsConfigure : Activity() {
|
||||||
|
private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
|
||||||
|
|
||||||
|
private var onClickListener = View.OnClickListener {
|
||||||
|
val context = this@ProfileStatsConfigure
|
||||||
|
|
||||||
|
// It is the responsibility of the configuration activity to update the app widget
|
||||||
|
val appWidgetManager = AppWidgetManager.getInstance(context)
|
||||||
|
//updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||||
|
|
||||||
|
|
||||||
|
ProfileStatsWidget.updateAppWidget(
|
||||||
|
context,
|
||||||
|
appWidgetManager,
|
||||||
|
appWidgetId
|
||||||
|
)
|
||||||
|
|
||||||
|
// Make sure we pass back the original appWidgetId
|
||||||
|
val resultValue = Intent()
|
||||||
|
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||||
|
setResult(RESULT_OK, resultValue)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
private lateinit var binding: StatisticsWidgetConfigureBinding
|
||||||
|
|
||||||
|
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 = StatisticsWidgetConfigureBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
val typedValueSurface = TypedValue()
|
||||||
|
theme.resolveAttribute(com.google.android.material.R.attr.colorSurface, typedValueSurface, true)
|
||||||
|
val backgroundColor = typedValueSurface.data
|
||||||
|
|
||||||
|
val typedValuePrimary = TypedValue()
|
||||||
|
theme.resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValuePrimary, true)
|
||||||
|
val textColor = typedValuePrimary.data
|
||||||
|
|
||||||
|
val typedValueOutline = TypedValue()
|
||||||
|
theme.resolveAttribute(com.google.android.material.R.attr.colorOutline, typedValueOutline, true)
|
||||||
|
val subTextColor = typedValueOutline.data
|
||||||
|
|
||||||
|
getSharedPreferences(ProfileStatsWidget.PREFS_NAME, Context.MODE_PRIVATE).edit().apply {
|
||||||
|
putInt(ProfileStatsWidget.PREF_BACKGROUND_COLOR, backgroundColor)
|
||||||
|
putInt(ProfileStatsWidget.PREF_BACKGROUND_FADE, backgroundColor)
|
||||||
|
putInt(ProfileStatsWidget.PREF_TITLE_TEXT_COLOR, textColor)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.addButton.setOnClickListener(onClickListener)
|
||||||
|
|
||||||
|
// Find the widget id from the intent.
|
||||||
|
val intent = intent
|
||||||
|
val extras = intent.extras
|
||||||
|
if (extras != null) {
|
||||||
|
appWidgetId = extras.getInt(
|
||||||
|
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibly consider sorting the items or configuring colors
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val PROFILE_STATS_PREFS = "ani.dantotsu.widget.ProfileStatsWidget"
|
||||||
|
private const val PROFILE_STATS_PREFS_PREFIX = "appwidget_"
|
|
@ -0,0 +1,245 @@
|
||||||
|
package ani.dantotsu.widgets.statistics
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
|
import android.widget.RemoteViews
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import ani.dantotsu.MainActivity
|
||||||
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import ani.dantotsu.util.BitmapUtil
|
||||||
|
import ani.dantotsu.widgets.WidgetSizeProvider
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import tachiyomi.core.util.lang.launchIO
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of App Widget functionality.
|
||||||
|
*/
|
||||||
|
class ProfileStatsWidget : AppWidgetProvider() {
|
||||||
|
override fun onUpdate(
|
||||||
|
context: Context,
|
||||||
|
appWidgetManager: AppWidgetManager,
|
||||||
|
appWidgetIds: IntArray
|
||||||
|
) {
|
||||||
|
appWidgetIds.forEach { appWidgetId ->
|
||||||
|
updateAppWidget(context, appWidgetManager, appWidgetId)
|
||||||
|
}
|
||||||
|
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
|
||||||
|
super.onDeleted(context, appWidgetIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnabled(context: Context) {
|
||||||
|
super.onEnabled(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisabled(context: Context) {
|
||||||
|
super.onDisabled(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun downloadImageAsBitmap(imageUrl: String): Bitmap? {
|
||||||
|
var bitmap: Bitmap? = null
|
||||||
|
|
||||||
|
runBlocking(Dispatchers.IO) {
|
||||||
|
var inputStream: InputStream? = null
|
||||||
|
var urlConnection: HttpURLConnection? = null
|
||||||
|
try {
|
||||||
|
val url = URL(imageUrl)
|
||||||
|
urlConnection = url.openConnection() as HttpURLConnection
|
||||||
|
urlConnection.requestMethod = "GET"
|
||||||
|
urlConnection.connect()
|
||||||
|
|
||||||
|
if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
inputStream = urlConnection.inputStream
|
||||||
|
bitmap = BitmapFactory.decodeStream(inputStream)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
|
inputStream?.close()
|
||||||
|
urlConnection?.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap?.let { BitmapUtil.roundCorners(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
fun updateAppWidget(
|
||||||
|
context: Context,
|
||||||
|
appWidgetManager: AppWidgetManager,
|
||||||
|
appWidgetId: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
val backgroundColor =
|
||||||
|
prefs.getInt(PREF_BACKGROUND_COLOR, Color.parseColor("#80000000"))
|
||||||
|
val backgroundFade = prefs.getInt(PREF_BACKGROUND_FADE, Color.parseColor("#00000000"))
|
||||||
|
val titleTextColor = prefs.getInt(PREF_TITLE_TEXT_COLOR, Color.WHITE)
|
||||||
|
|
||||||
|
val gradientDrawable = ResourcesCompat.getDrawable(
|
||||||
|
context.resources,
|
||||||
|
R.drawable.linear_gradient_black,
|
||||||
|
null
|
||||||
|
) as GradientDrawable
|
||||||
|
gradientDrawable.colors = intArrayOf(backgroundColor, backgroundFade)
|
||||||
|
val widgetSizeProvider = WidgetSizeProvider(context)
|
||||||
|
var (width, height) = widgetSizeProvider.getWidgetsSize(appWidgetId)
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
gradientDrawable.cornerRadius = 64f
|
||||||
|
} else {
|
||||||
|
width = 300
|
||||||
|
height = 300
|
||||||
|
}
|
||||||
|
|
||||||
|
launchIO {
|
||||||
|
val userPref = PrefManager.getVal(PrefName.AnilistUserId, "")
|
||||||
|
val userId = if (userPref.isNotEmpty()) userPref.toInt() else Anilist.userid
|
||||||
|
?: if (Anilist.query.getUserData()) Anilist.userid else null
|
||||||
|
userId?.let {
|
||||||
|
val respond = Anilist.query.getUserProfile(it)
|
||||||
|
respond?.data?.user?.let { user ->
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
val views = RemoteViews(context.packageName, R.layout.statistics_widget).apply {
|
||||||
|
setImageViewBitmap(
|
||||||
|
R.id.backgroundView,
|
||||||
|
BitmapUtil.convertDrawableToBitmap(
|
||||||
|
gradientDrawable,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
)
|
||||||
|
)
|
||||||
|
setTextColor(R.id.topLeftItem, titleTextColor)
|
||||||
|
setTextColor(R.id.topLeftLabel, titleTextColor)
|
||||||
|
setTextColor(R.id.topRightItem, titleTextColor)
|
||||||
|
setTextColor(R.id.topRightLabel, titleTextColor)
|
||||||
|
setTextColor(R.id.bottomLeftItem, titleTextColor)
|
||||||
|
setTextColor(R.id.bottomLeftLabel, titleTextColor)
|
||||||
|
setTextColor(R.id.bottomRightItem, titleTextColor)
|
||||||
|
setTextColor(R.id.bottomRightLabel, titleTextColor)
|
||||||
|
|
||||||
|
setImageViewBitmap(
|
||||||
|
R.id.userAvatar,
|
||||||
|
user.avatar?.medium?.let { it1 -> downloadImageAsBitmap(it1) }
|
||||||
|
)
|
||||||
|
setTextViewText(
|
||||||
|
R.id.userLabel,
|
||||||
|
context.getString(R.string.user_stats, user.name)
|
||||||
|
)
|
||||||
|
|
||||||
|
setTextViewText(
|
||||||
|
R.id.topLeftItem,
|
||||||
|
user.statistics.anime.count.toString()
|
||||||
|
)
|
||||||
|
setTextViewText(
|
||||||
|
R.id.topLeftLabel,
|
||||||
|
context.getString(R.string.anime_watched)
|
||||||
|
)
|
||||||
|
|
||||||
|
setTextViewText(
|
||||||
|
R.id.topRightItem,
|
||||||
|
user.statistics.anime.episodesWatched.toString()
|
||||||
|
)
|
||||||
|
setTextViewText(
|
||||||
|
R.id.topRightLabel,
|
||||||
|
context.getString(R.string.episodes_watched)
|
||||||
|
)
|
||||||
|
|
||||||
|
setTextViewText(
|
||||||
|
R.id.bottomLeftItem,
|
||||||
|
user.statistics.manga.count.toString()
|
||||||
|
)
|
||||||
|
setTextViewText(
|
||||||
|
R.id.bottomLeftLabel,
|
||||||
|
context.getString(R.string.manga_read)
|
||||||
|
)
|
||||||
|
|
||||||
|
setTextViewText(
|
||||||
|
R.id.bottomRightItem,
|
||||||
|
user.statistics.manga.chaptersRead.toString()
|
||||||
|
)
|
||||||
|
setTextViewText(
|
||||||
|
R.id.bottomRightLabel,
|
||||||
|
context.getString(R.string.chapters_read)
|
||||||
|
)
|
||||||
|
|
||||||
|
val intent = Intent(context, ProfileActivity::class.java)
|
||||||
|
.putExtra("userId", it)
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
context, 0, intent, PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
setOnClickPendingIntent(R.id.widgetContainer, pendingIntent)
|
||||||
|
}
|
||||||
|
// Instruct the widget manager to update the widget
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
}
|
||||||
|
} ?: showLoginCascade(context, appWidgetManager, appWidgetId)
|
||||||
|
} ?: showLoginCascade(context, appWidgetManager, appWidgetId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun showLoginCascade(
|
||||||
|
context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
val views = RemoteViews(context.packageName, R.layout.statistics_widget)
|
||||||
|
|
||||||
|
views.setTextViewText(R.id.topLeftItem, "")
|
||||||
|
views.setTextViewText(
|
||||||
|
R.id.topLeftLabel,
|
||||||
|
context.getString(R.string.please)
|
||||||
|
)
|
||||||
|
|
||||||
|
views.setTextViewText(R.id.topRightItem, "")
|
||||||
|
views.setTextViewText(
|
||||||
|
R.id.topRightLabel,
|
||||||
|
context.getString(R.string.log_in)
|
||||||
|
)
|
||||||
|
|
||||||
|
views.setTextViewText(
|
||||||
|
R.id.bottomLeftItem,
|
||||||
|
context.getString(R.string.or_join)
|
||||||
|
)
|
||||||
|
views.setTextViewText(R.id.bottomLeftLabel, "")
|
||||||
|
|
||||||
|
views.setTextViewText(
|
||||||
|
R.id.bottomRightItem,
|
||||||
|
context.getString(R.string.anilist)
|
||||||
|
)
|
||||||
|
views.setTextViewText(R.id.bottomRightLabel, "")
|
||||||
|
|
||||||
|
val intent = Intent(context, MainActivity::class.java)
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
context, 0, intent, PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
views.setOnClickPendingIntent(R.id.widgetContainer, pendingIntent)
|
||||||
|
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const val PREFS_NAME = "ani.dantotsu.widgets.ResumableWidget"
|
||||||
|
const val PREF_BACKGROUND_COLOR = "background_color"
|
||||||
|
const val PREF_BACKGROUND_FADE = "background_fade"
|
||||||
|
const val PREF_TITLE_TEXT_COLOR = "title_text_color"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
BIN
app/src/main/res/drawable-nodpi/statistics_widget_preview.png
Normal file
BIN
app/src/main/res/drawable-nodpi/statistics_widget_preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
BIN
app/src/main/res/drawable-nodpi/upcoming_widget_preview.png
Normal file
BIN
app/src/main/res/drawable-nodpi/upcoming_widget_preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
13
app/src/main/res/drawable/ic_camera_roll_24.xml
Normal file
13
app/src/main/res/drawable/ic_camera_roll_24.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#000000"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M14,5c0,-1.1 -0.9,-2 -2,-2h-1L11,2c0,-0.55 -0.45,-1 -1,-1L6,1c-0.55,0 -1,0.45 -1,1v1L4,3c-1.1,0 -2,0.9 -2,2v15c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2h8L22,5h-8zM12,18h-2v-2h2v2zM12,9h-2L10,7h2v2zM16,18h-2v-2h2v2zM16,9h-2L14,7h2v2zM20,18h-2v-2h2v2zM20,9h-2L18,7h2v2z"/>
|
||||||
|
|
||||||
|
</vector>
|
27
app/src/main/res/drawable/widget_stats_rounded.xml
Normal file
27
app/src/main/res/drawable/widget_stats_rounded.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="28dp"
|
||||||
|
android:topRightRadius="28dp"
|
||||||
|
android:bottomLeftRadius="0dp"
|
||||||
|
android:bottomRightRadius="0dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:left="-2dp"
|
||||||
|
android:right="-2dp"
|
||||||
|
android:bottom="-50dp">
|
||||||
|
<shape>
|
||||||
|
<stroke android:width="2dp" android:color="@color/bg_white" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="28dp"
|
||||||
|
android:topRightRadius="28dp"
|
||||||
|
android:bottomLeftRadius="0dp"
|
||||||
|
android:bottomRightRadius="0dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
|
|
||||||
|
|
184
app/src/main/res/layout/statistics_widget.xml
Normal file
184
app/src/main/res/layout/statistics_widget.xml
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:theme="@style/Theme.Dantotsu.AppWidgetContainer"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/backgroundView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/widget_stats_rounded"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/headerLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_margin="4dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:baselineAligned="false">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/userAvatar"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/ic_dantotsu_round"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/userLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:text="@string/loading"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/widget_stats_rounded"
|
||||||
|
android:layout_below="@id/headerLayout">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:baselineAligned="false">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/topLeft"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="NestedWeights">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/topLeftItem"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:text="@string/loading"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/topLeftLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="@string/anime_watched" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/dividerTop"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/topRight"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/topRightItem"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:text="@string/loading"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/topRightLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="@string/episodes_watched"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/dividerMiddle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="2dp"
|
||||||
|
android:layout_margin="4dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/bottomLeft"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:baselineAligned="false">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="NestedWeights">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottomLeftItem"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:text="@string/loading"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottomLeftLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="@string/manga_read"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/dividerBottom"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/bottomRight"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottomRightItem"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:text="@string/loading"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bottomRightLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:text="@string/chapters_read"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
24
app/src/main/res/layout/statistics_widget_configure.xml
Normal file
24
app/src/main/res/layout/statistics_widget_configure.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<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">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:text="@string/profile_stats_widget" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/add_button"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/add_widget" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -9,6 +9,7 @@
|
||||||
<color name="bg_opp">@color/bg_black</color>
|
<color name="bg_opp">@color/bg_black</color>
|
||||||
<color name="fg">#A8000000</color>
|
<color name="fg">#A8000000</color>
|
||||||
<color name="bg_black_50" alpha="128">#80000000</color>
|
<color name="bg_black_50" alpha="128">#80000000</color>
|
||||||
|
<color name="bg_white_50" alpha="128">#80FFFFFF</color>
|
||||||
<color name="nav_bg">#fff</color>
|
<color name="nav_bg">#fff</color>
|
||||||
<color name="nav_bg_inv">#00BFAEAE</color>
|
<color name="nav_bg_inv">#00BFAEAE</color>
|
||||||
<color name="gradiant_bg_start">#ACACAC</color>
|
<color name="gradiant_bg_start">#ACACAC</color>
|
||||||
|
|
|
@ -820,6 +820,17 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
|
||||||
<string name="donate">donate :)</string>
|
<string name="donate">donate :)</string>
|
||||||
<string name="do_it">Do it!</string>
|
<string name="do_it">Do it!</string>
|
||||||
<string name="password">Password</string>
|
<string name="password">Password</string>
|
||||||
|
|
||||||
|
<string name="profile_stats_widget">Track progress directly from your home screen</string>
|
||||||
|
<string name="anime_watched">Anime Watched</string>
|
||||||
|
<string name="manga_read">Manga Read</string>
|
||||||
|
<string name="loading">Loading…</string>
|
||||||
|
<string name="user_stats">%1$s\'s Stats</string>
|
||||||
|
|
||||||
|
<string name="please">Please</string>
|
||||||
|
<string name="log_in">log in</string>
|
||||||
|
<string name="or_join">or join</string>
|
||||||
|
|
||||||
<string name="top_background_color">Top background color</string>
|
<string name="top_background_color">Top background color</string>
|
||||||
<string name="bottom_background_color">Bottom Background Color</string>
|
<string name="bottom_background_color">Bottom Background Color</string>
|
||||||
<string name="countdown_text_color">Countdown Text Color</string>
|
<string name="countdown_text_color">Countdown Text Color</string>
|
||||||
|
|
15
app/src/main/res/xml-v31/statistics_widget_info.xml
Normal file
15
app/src/main/res/xml-v31/statistics_widget_info.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:description="@string/profile_stats_widget"
|
||||||
|
android:initialKeyguardLayout="@layout/statistics_widget"
|
||||||
|
android:initialLayout="@layout/statistics_widget"
|
||||||
|
android:targetCellWidth="3"
|
||||||
|
android:targetCellHeight="2"
|
||||||
|
android:minResizeWidth="180dp"
|
||||||
|
android:minResizeHeight="110dp"
|
||||||
|
android:previewImage="@drawable/statistics_widget_preview"
|
||||||
|
android:previewLayout="@layout/statistics_widget"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:updatePeriodMillis="86400000"
|
||||||
|
android:widgetCategory="home_screen"
|
||||||
|
android:configure="ani.dantotsu.widgets.statistics.ProfileStatsConfigure" />
|
|
@ -6,7 +6,7 @@
|
||||||
android:initialLayout="@layout/upcoming_widget"
|
android:initialLayout="@layout/upcoming_widget"
|
||||||
android:minWidth="160dp"
|
android:minWidth="160dp"
|
||||||
android:minHeight="80dp"
|
android:minHeight="80dp"
|
||||||
android:previewImage="@drawable/example_appwidget_preview"
|
android:previewImage="@drawable/upcoming_widget_preview"
|
||||||
android:previewLayout="@layout/upcoming_widget"
|
android:previewLayout="@layout/upcoming_widget"
|
||||||
android:resizeMode="horizontal|vertical"
|
android:resizeMode="horizontal|vertical"
|
||||||
android:updatePeriodMillis="3600000"
|
android:updatePeriodMillis="3600000"
|
||||||
|
|
14
app/src/main/res/xml/statistics_widget_info.xml
Normal file
14
app/src/main/res/xml/statistics_widget_info.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:description="@string/profile_stats_widget"
|
||||||
|
android:initialKeyguardLayout="@layout/statistics_widget"
|
||||||
|
android:initialLayout="@layout/statistics_widget"
|
||||||
|
android:minWidth="180dp"
|
||||||
|
android:minHeight="110dp"
|
||||||
|
android:minResizeWidth="180dp"
|
||||||
|
android:minResizeHeight="110dp"
|
||||||
|
android:previewImage="@drawable/statistics_widget_preview"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:updatePeriodMillis="86400000"
|
||||||
|
android:widgetCategory="home_screen"
|
||||||
|
android:configure="ani.dantotsu.widgets.statistics.ProfileStatsConfigure" />
|
|
@ -6,7 +6,7 @@
|
||||||
android:initialLayout="@layout/upcoming_widget"
|
android:initialLayout="@layout/upcoming_widget"
|
||||||
android:minWidth="160dp"
|
android:minWidth="160dp"
|
||||||
android:minHeight="80dp"
|
android:minHeight="80dp"
|
||||||
android:previewImage="@drawable/example_appwidget_preview"
|
android:previewImage="@drawable/upcoming_widget_preview"
|
||||||
android:resizeMode="horizontal|vertical"
|
android:resizeMode="horizontal|vertical"
|
||||||
android:updatePeriodMillis="3600000"
|
android:updatePeriodMillis="3600000"
|
||||||
android:widgetCategory="home_screen"/>
|
android:widgetCategory="home_screen"/>
|
Loading…
Add table
Add a link
Reference in a new issue