diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7cc2e732..fdab5a4c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -49,31 +49,38 @@ 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"> + + android:name=".widgets.upcoming.UpcomingWidget" + android:exported="true"> + android:resource="@xml/upcoming_widget_info" /> + + + + + - + android:parentActivityName=".MainActivity" + android:windowSoftInputMode="adjustResize|stateHidden" /> + android:parentActivityName=".MainActivity" + android:windowSoftInputMode="adjustResize|stateHidden" /> + android:parentActivityName=".MainActivity" + android:windowSoftInputMode="adjustResize|stateHidden" /> - + android:label="Inbox Activity" + android:parentActivityName=".MainActivity" /> - + android:parentActivityName=".MainActivity" /> @@ -139,8 +144,9 @@ android:name=".media.CalendarActivity" android:parentActivityName=".MainActivity" /> - + + android:windowSoftInputMode="adjustResize|stateHidden" /> - + + @@ -306,22 +313,23 @@ android:exported="false" android:theme="@android:style/Theme.Translucent.NoTitleBar" /> - - - - - - + + + { + val res = executeQuery( + """{MediaListCollection(userId:$id,type:ANIME){lists{name entries{media{id,isFavourite,title{userPreferred,romaji}coverImage{medium}nextAiringEpisode{timeUntilAiring}}}}}}""", + force = true + ) + val list = mutableListOf() + 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) { diff --git a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt index ea3bb1a9..2aacbda4 100644 --- a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt +++ b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.os.Handler import android.os.Looper import android.util.TypedValue +import android.view.HapticFeedbackConstants import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -96,6 +97,7 @@ class AnimePageAdapter : RecyclerView.Adapter + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) ContextCompat.startActivity( view.context, Intent(view.context, ProfileActivity::class.java) @@ -167,7 +169,6 @@ class AnimePageAdapter : RecyclerView.Adapter + view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) ContextCompat.startActivity( view.context, Intent(view.context, ProfileActivity::class.java) @@ -164,8 +166,9 @@ class MangaPageAdapter : RecyclerView.Adapter? = null, var staff: ArrayList? = 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) diff --git a/app/src/main/java/ani/dantotsu/media/SearchActivity.kt b/app/src/main/java/ani/dantotsu/media/SearchActivity.kt index bb71c46c..d2869be4 100644 --- a/app/src/main/java/ani/dantotsu/media/SearchActivity.kt +++ b/app/src/main/java/ani/dantotsu/media/SearchActivity.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.os.Bundle import android.os.Parcelable import android.view.View +import android.view.WindowManager import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible @@ -156,7 +157,10 @@ class SearchActivity : AppCompatActivity() { } else headerAdaptor.requestFocus?.run() - if (intent.getBooleanExtra("search", false)) search() + if (intent.getBooleanExtra("search", false)) { + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED) + search() + } } } } diff --git a/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt b/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt index 0ec2d3bf..7e8143a4 100644 --- a/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt +++ b/app/src/main/java/ani/dantotsu/media/comments/CommentsFragment.kt @@ -28,6 +28,7 @@ import ani.dantotsu.connections.comments.CommentsAPI import ani.dantotsu.databinding.FragmentCommentsBinding import ani.dantotsu.loadImage import ani.dantotsu.media.MediaDetailsActivity +import ani.dantotsu.setBaseline import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.snackString @@ -73,6 +74,9 @@ class CommentsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) activity = requireActivity() as MediaDetailsActivity + + binding.commentsList.setBaseline(activity.navBar, activity.binding.commentInputLayout) + //get the media id from the intent val mediaId = arguments?.getInt("mediaId") ?: -1 mediaName = arguments?.getString("mediaName") ?: "unknown" @@ -366,6 +370,7 @@ class CommentsFragment : Fragment() { override fun onResume() { super.onResume() tag = null + binding.commentsList.setBaseline(activity.navBar, activity.binding.commentInputLayout) section.groups.forEach { if (it is CommentItem && it.containsGif()) { it.notifyChanged() diff --git a/app/src/main/java/ani/dantotsu/media/manga/mangareader/ChapterLoaderDialog.kt b/app/src/main/java/ani/dantotsu/media/manga/mangareader/ChapterLoaderDialog.kt index 6c5233b7..699f43dc 100644 --- a/app/src/main/java/ani/dantotsu/media/manga/mangareader/ChapterLoaderDialog.kt +++ b/app/src/main/java/ani/dantotsu/media/manga/mangareader/ChapterLoaderDialog.kt @@ -37,7 +37,7 @@ class ChapterLoaderDialog : BottomSheetDialogFragment() { binding.selectorAutoListContainer.visibility = View.VISIBLE binding.selectorListContainer.visibility = View.GONE - binding.selectorTitle.text = getString(R.string.loading_next_chap) + binding.selectorTitle.text = getString(R.string.loading_chap_number, chp.number) binding.selectorCancel.setOnClickListener { dismiss() } diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt index d5c2f0c7..abbe26e5 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt @@ -46,7 +46,7 @@ import kotlin.math.abs class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListener { lateinit var binding: ActivityProfileBinding private var selected: Int = 0 - private lateinit var navBar: AnimatedBottomBar + lateinit var navBar: AnimatedBottomBar override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt index d008f966..6fd425be 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt @@ -30,6 +30,7 @@ import ani.dantotsu.media.CharacterAdapter import ani.dantotsu.media.Media import ani.dantotsu.media.MediaAdaptor import ani.dantotsu.media.user.ListActivity +import ani.dantotsu.setBaseline import ani.dantotsu.setSlideIn import ani.dantotsu.setSlideUp import ani.dantotsu.util.AniMarkdown.Companion.getFullAniHTML @@ -59,6 +60,8 @@ class ProfileFragment : Fragment() { super.onViewCreated(view, savedInstanceState) activity = requireActivity() as ProfileActivity + binding.root.setBaseline(activity.navBar) + user = arguments?.getSerializableCompat("user") as Query.UserProfile viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { model.setData(user.id) @@ -144,6 +147,7 @@ class ProfileFragment : Fragment() { super.onResume() if (this::binding.isInitialized) { binding.root.requestLayout() + binding.root.setBaseline(activity.navBar) } } diff --git a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt index 2f01cac6..aaf0ed6f 100644 --- a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt @@ -17,6 +17,7 @@ import ani.dantotsu.profile.ChartBuilder.Companion.ChartPacket import ani.dantotsu.profile.ChartBuilder.Companion.ChartType import ani.dantotsu.profile.ChartBuilder.Companion.MediaType import ani.dantotsu.profile.ChartBuilder.Companion.StatType +import ani.dantotsu.setBaseline import ani.dantotsu.statusBarHeight import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType import com.xwray.groupie.GroupieAdapter @@ -49,8 +50,11 @@ class StatsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) activity = requireActivity() as ProfileActivity + user = arguments?.getSerializableCompat("user") as Query.UserProfile + binding.statisticList.setBaseline(activity.navBar) + binding.statisticList.adapter = adapter binding.statisticList.recycledViewPool.setMaxRecycledViews(0, 0) binding.statisticList.isNestedScrollingEnabled = true @@ -114,6 +118,7 @@ class StatsFragment : super.onResume() if (this::binding.isInitialized) { binding.statisticList.visibility = View.VISIBLE + binding.statisticList.setBaseline(activity.navBar) binding.root.requestLayout() if (!loadedFirstTime) { activity.lifecycleScope.launch { diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt index 7ef09eb5..f50502f1 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt @@ -18,6 +18,7 @@ import ani.dantotsu.connections.anilist.api.Activity import ani.dantotsu.databinding.FragmentFeedBinding import ani.dantotsu.media.MediaDetailsActivity import ani.dantotsu.profile.ProfileActivity +import ani.dantotsu.setBaseline import ani.dantotsu.snackString import ani.dantotsu.util.Logger import com.xwray.groupie.GroupieAdapter @@ -48,6 +49,9 @@ class FeedFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) activity = requireActivity() + + binding.listRecyclerView.setBaseline((activity as ProfileActivity).navBar) + binding.listRecyclerView.adapter = adapter binding.listRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) @@ -63,6 +67,7 @@ class FeedFragment : Fragment() { super.onResume() if (this::binding.isInitialized) { binding.root.requestLayout() + binding.listRecyclerView.setBaseline((activity as ProfileActivity).navBar) if (!loadedFirstTime) { activity.lifecycleScope.launch(Dispatchers.IO) { val nulledId = if (activityId == -1) null else activityId diff --git a/app/src/main/java/ani/dantotsu/settings/UserInterfaceSettingsActivity.kt b/app/src/main/java/ani/dantotsu/settings/UserInterfaceSettingsActivity.kt index 2c8b0e40..b803fb1b 100644 --- a/app/src/main/java/ani/dantotsu/settings/UserInterfaceSettingsActivity.kt +++ b/app/src/main/java/ani/dantotsu/settings/UserInterfaceSettingsActivity.kt @@ -77,6 +77,11 @@ class UserInterfaceSettingsActivity : AppCompatActivity() { restartApp(binding.root) } + binding.uiSettingsTrendingScroller.isChecked = PrefManager.getVal(PrefName.TrendingScroller) + binding.uiSettingsTrendingScroller.setOnCheckedChangeListener { _, isChecked -> + PrefManager.setVal(PrefName.TrendingScroller, isChecked) + } + val map = mapOf( 2f to 0.5f, 1.75f to 0.625f, diff --git a/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt b/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt index 28fb7a9a..76e80bb2 100644 --- a/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt +++ b/app/src/main/java/ani/dantotsu/settings/saving/Preferences.kt @@ -68,6 +68,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files ), BannerAnimations(Pref(Location.UI, Boolean::class, true)), LayoutAnimations(Pref(Location.UI, Boolean::class, true)), + TrendingScroller(Pref(Location.UI, Boolean::class, true)), AnimationSpeed(Pref(Location.UI, Float::class, 1f)), ListGrid(Pref(Location.UI, Boolean::class, true)), PopularMangaList(Pref(Location.UI, Boolean::class, true)), diff --git a/app/src/main/java/ani/dantotsu/util/BitmapUtil.kt b/app/src/main/java/ani/dantotsu/util/BitmapUtil.kt new file mode 100644 index 00000000..a4c4e7b6 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/util/BitmapUtil.kt @@ -0,0 +1,33 @@ +package ani.dantotsu.util + +import android.graphics.Bitmap +import android.graphics.BitmapShader +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.Shader +import android.graphics.drawable.Drawable + +class BitmapUtil { + companion object { + fun roundCorners(bitmap: Bitmap, cornerRadius: Float = 20f): Bitmap { + 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 + } + + fun convertDrawableToBitmap(drawable: Drawable, width: Int, height: Int): Bitmap { + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + drawable.setBounds(0, 0, canvas.width, canvas.height) + drawable.draw(canvas) + return bitmap + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt deleted file mode 100644 index 8cf8029a..00000000 --- a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsFactory.kt +++ /dev/null @@ -1,138 +0,0 @@ -package ani.dantotsu.widgets - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.widget.RemoteViews -import android.widget.RemoteViewsService -import ani.dantotsu.R -import ani.dantotsu.util.Logger -import java.io.InputStream -import java.net.HttpURLConnection -import java.net.URL - -class CurrentlyAiringRemoteViewsFactory(private val context: Context) : - RemoteViewsService.RemoteViewsFactory { - private var widgetItems = mutableListOf() - - 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() - } - - override fun onDataSetChanged() { - // 4 items for testing - 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" - ) - ) - } - - override fun onDestroy() { - widgetItems.clear() - } - - override fun getCount(): Int { - return widgetItems.size - } - - override fun getViewAt(position: Int): RemoteViews { - Logger.log("CurrentlyAiringRemoteViewsFactory getViewAt") - val item = widgetItems[position] - 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) - val bitmap = downloadImageAsBitmap(item.image) - //setImageViewUri(R.id.image_show_icon, Uri.parse(item.image)) - setImageViewBitmap(R.id.image_show_icon, bitmap) - } - - return rv - } - - private fun downloadImageAsBitmap(imageUrl: String): Bitmap? { - var bitmap: Bitmap? = null - 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() - // Handle the error according to your needs - } finally { - // Clean up resources - inputStream?.close() - urlConnection?.disconnect() - } - - return bitmap - } - - override fun getLoadingView(): RemoteViews { - return RemoteViews(context.packageName, R.layout.item_currently_airing_widget) - } - - override fun getViewTypeCount(): Int { - return 1 - } - - override fun getItemId(p0: Int): Long { - return p0.toLong() - } - - override fun hasStableIds(): Boolean { - return true - } -} - -data class WidgetItem(val title: String, val countdown: String, val image: String) \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt deleted file mode 100644 index 4d042b33..00000000 --- a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringRemoteViewsService.kt +++ /dev/null @@ -1,12 +0,0 @@ -package ani.dantotsu.widgets - -import android.content.Intent -import android.widget.RemoteViewsService -import ani.dantotsu.util.Logger - -class CurrentlyAiringRemoteViewsService : RemoteViewsService() { - override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { - Logger.log("CurrentlyAiringRemoteViewsFactory onGetViewFactory") - return CurrentlyAiringRemoteViewsFactory(applicationContext) - } -} diff --git a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringWidget.kt b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringWidget.kt deleted file mode 100644 index b2c3948c..00000000 --- a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringWidget.kt +++ /dev/null @@ -1,112 +0,0 @@ -package ani.dantotsu.widgets - -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.Canvas -import android.graphics.Color -import android.graphics.drawable.Drawable -import android.graphics.drawable.GradientDrawable -import android.net.Uri -import android.widget.RemoteViews -import androidx.core.content.res.ResourcesCompat -import ani.dantotsu.R - -/** - * Implementation of App Widget functionality. - * App Widget Configuration implemented in [CurrentlyAiringWidgetConfigureActivity] - */ -class CurrentlyAiringWidget : AppWidgetProvider() { - override fun onUpdate( - context: Context, - appWidgetManager: AppWidgetManager, - 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) - } - - 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) - } - super.onDeleted(context, appWidgetIds) - } - - override fun onEnabled(context: Context) { - super.onEnabled(context) - } - - override fun onDisabled(context: Context) { - 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) - - // Get the gradient drawable resource and update its start color with the user-selected color - val gradientDrawable = ResourcesCompat.getDrawable( - context.resources, - R.drawable.gradient_background, - null - ) as GradientDrawable - gradientDrawable.colors = intArrayOf(color, Color.GRAY) // End color is gray. - - // 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) - } - - // Instruct the widget manager to update the widget - appWidgetManager.updateAppWidget(appWidgetId, views) - } - - private fun convertDrawableToBitmap(drawable: Drawable): Bitmap { - val bitmap = Bitmap.createBitmap(100, 300, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - drawable.setBounds(0, 0, canvas.width, canvas.height) - drawable.draw(canvas) - return bitmap - } - } -} - -internal fun updateAppWidget( - context: Context, - 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 - appWidgetManager.updateAppWidget(appWidgetId, views) -} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringWidgetConfigureActivity.kt b/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringWidgetConfigureActivity.kt deleted file mode 100644 index 186f5151..00000000 --- a/app/src/main/java/ani/dantotsu/widgets/CurrentlyAiringWidgetConfigureActivity.kt +++ /dev/null @@ -1,110 +0,0 @@ -package ani.dantotsu.widgets - -import android.app.Activity -import android.appwidget.AppWidgetManager -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.view.View -import android.widget.EditText -import ani.dantotsu.R -import ani.dantotsu.databinding.CurrentlyAiringWidgetConfigureBinding -import ani.dantotsu.themes.ThemeManager - -/** - * The configuration screen for the [CurrentlyAiringWidget] AppWidget. - */ -class CurrentlyAiringWidgetConfigureActivity : Activity() { - 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( - 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) - finish() - } - 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) - - appWidgetText = binding.appwidgetText - 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 - ) - } - - // 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 - ) - ) - - } - -} - -private const val PREFS_NAME = "ani.dantotsu.parsers.CurrentlyAiringWidget" -private const val PREF_PREFIX_KEY = "appwidget_" - -// 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() -} - -// 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) -} - -internal fun deleteTitlePref(context: Context, appWidgetId: Int) { - val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit() - prefs.remove(PREF_PREFIX_KEY + appWidgetId) - prefs.apply() -} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/WidgetSizeProvider.kt b/app/src/main/java/ani/dantotsu/widgets/WidgetSizeProvider.kt new file mode 100644 index 00000000..3b5af9ca --- /dev/null +++ b/app/src/main/java/ani/dantotsu/widgets/WidgetSizeProvider.kt @@ -0,0 +1,40 @@ +package ani.dantotsu.widgets + +import android.appwidget.AppWidgetManager +import android.content.Context + +class WidgetSizeProvider( + private val context: Context // Do not pass Application context +) { + + private val appWidgetManager = AppWidgetManager.getInstance(context) + + fun getWidgetsSize(widgetId: Int): Pair { + val isPortrait = context.resources.configuration.orientation == 1 + val width = getWidgetWidth(isPortrait, widgetId) + val height = getWidgetHeight(isPortrait, widgetId) + val widthInPx = context.dip(width) + val heightInPx = context.dip(height) + return widthInPx to heightInPx + } + + private fun getWidgetWidth(isPortrait: Boolean, widgetId: Int): Int = + if (isPortrait) { + getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) + } else { + getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) + } + + private fun getWidgetHeight(isPortrait: Boolean, widgetId: Int): Int = + if (isPortrait) { + getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) + } else { + getWidgetSizeInDp(widgetId, AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) + } + + private fun getWidgetSizeInDp(widgetId: Int, key: String): Int = + appWidgetManager.getAppWidgetOptions(widgetId).getInt(key, 0) + + private fun Context.dip(value: Int): Int = (value * resources.displayMetrics.density).toInt() + +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt new file mode 100644 index 00000000..0991b2a4 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsFactory.kt @@ -0,0 +1,142 @@ +package ani.dantotsu.widgets.upcoming + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +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.BitmapUtil.Companion.roundCorners +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 + +class UpcomingRemoteViewsFactory(private val context: Context) : + RemoteViewsService.RemoteViewsFactory { + private var widgetItems = mutableListOf() + private var refreshing = false + private val prefs = + context.getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE) + + override fun onCreate() { + Logger.log("UpcomingRemoteViewsFactory onCreate") + 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() { + if (refreshing) return + Logger.log("UpcomingRemoteViewsFactory onDataSetChanged") + widgetItems.clear() + fillWidgetItems() + + } + + private fun fillWidgetItems() { + refreshing = true + val userId = PrefManager.getVal(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() { + widgetItems.clear() + } + + override fun getCount(): Int { + return widgetItems.size + } + + override fun getViewAt(position: Int): RemoteViews { + Logger.log("UpcomingRemoteViewsFactory getViewAt") + val item = widgetItems[position] + val titleTextColor = prefs.getInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE) + val countdownTextColor = + prefs.getInt(UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, Color.WHITE) + val rv = RemoteViews(context.packageName, R.layout.item_upcoming_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) + setImageViewBitmap(R.id.image_show_icon, bitmap) + val fillInIntent = Intent().apply { + putExtra("mediaId", item.id) + } + setOnClickFillInIntent(R.id.widget_item, fillInIntent) + } + + return rv + } + + private fun downloadImageAsBitmap(imageUrl: String): Bitmap? { + var bitmap: Bitmap? = null + 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 { roundCorners(it) } + } + + + + + override fun getLoadingView(): RemoteViews { + return RemoteViews(context.packageName, R.layout.item_upcoming_widget) + } + + override fun getViewTypeCount(): Int { + return 1 + } + + override fun getItemId(p0: Int): Long { + return p0.toLong() + } + + override fun hasStableIds(): Boolean { + return true + } +} + +data class WidgetItem(val title: String, val countdown: String, val image: String, val id: Int) \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsService.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsService.kt new file mode 100644 index 00000000..7e704fc2 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingRemoteViewsService.kt @@ -0,0 +1,12 @@ +package ani.dantotsu.widgets.upcoming + +import android.content.Intent +import android.widget.RemoteViewsService +import ani.dantotsu.util.Logger + +class UpcomingRemoteViewsService : RemoteViewsService() { + override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { + Logger.log("UpcomingRemoteViewsFactory onGetViewFactory") + return UpcomingRemoteViewsFactory(applicationContext) + } +} diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt new file mode 100644 index 00000000..a9f22130 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidget.kt @@ -0,0 +1,147 @@ +package ani.dantotsu.widgets.upcoming + +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.graphics.drawable.GradientDrawable +import android.net.Uri +import android.os.Bundle +import android.widget.RemoteViews +import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat +import ani.dantotsu.MainActivity +import ani.dantotsu.R +import ani.dantotsu.util.BitmapUtil.Companion.convertDrawableToBitmap +import ani.dantotsu.widgets.WidgetSizeProvider + +/** + * Implementation of App Widget functionality. + * App Widget Configuration implemented in [UpcomingWidgetConfigureActivity] + */ +class UpcomingWidget : AppWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray + ) { + appWidgetIds.forEach { appWidgetId -> + val rv = updateAppWidget(context, appWidgetId) + appWidgetManager.updateAppWidget(appWidgetId, rv) + } + super.onUpdate(context, appWidgetManager, appWidgetIds) + } + + override fun onDeleted(context: Context, appWidgetIds: IntArray) { + for (appWidgetId in appWidgetIds) { + context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE).edit().clear().apply() + } + super.onDeleted(context, appWidgetIds) + } + + override fun onEnabled(context: Context) { + super.onEnabled(context) + } + + override fun onDisabled(context: Context) { + super.onDisabled(context) + } + + override fun onAppWidgetOptionsChanged( + context: Context?, + appWidgetManager: AppWidgetManager?, + appWidgetId: Int, + newOptions: Bundle? + ) { + super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions) + if (context != null && appWidgetManager != null) { + val views = updateAppWidget(context, appWidgetId) + appWidgetManager.updateAppWidget(appWidgetId, views) + } + } + + companion object { + fun updateAppWidget( + context: Context, + appWidgetId: Int, + ): 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) + + val intent = Intent(context, UpcomingRemoteViewsService::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(backgroundColor, backgroundFade) + val widgetSizeProvider = WidgetSizeProvider(context) + var (width, height) = widgetSizeProvider.getWidgetsSize(appWidgetId) + if (width > 0 && height > 0) { + gradientDrawable.cornerRadius = 50f + } else { + width = 300 + height = 300 + } + + val intentTemplate = Intent(context, MainActivity::class.java) + intentTemplate.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + intentTemplate.putExtra("fromWidget", true) + + val views = RemoteViews(context.packageName, R.layout.upcoming_widget).apply { + setImageViewBitmap(R.id.backgroundView, convertDrawableToBitmap(gradientDrawable, width, height)) + 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, UpcomingWidgetConfigureActivity::class.java).apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + }, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + ) + } + return views + } + + const val PREFS_NAME = "ani.dantotsu.widgets.UpcomingWidget" + 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" + } +} + +internal fun updateAppWidget( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetId: Int +) { + val views = UpcomingWidget.updateAppWidget(context, appWidgetId) + appWidgetManager.updateAppWidget(appWidgetId, views) + appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetListView) +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigureActivity.kt b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigureActivity.kt new file mode 100644 index 00000000..f14efaa7 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/widgets/upcoming/UpcomingWidgetConfigureActivity.kt @@ -0,0 +1,195 @@ +package ani.dantotsu.widgets.upcoming + +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 androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import ani.dantotsu.R +import ani.dantotsu.databinding.UpcomingWidgetConfigureBinding +import ani.dantotsu.themes.ThemeManager +import eltos.simpledialogfragment.SimpleDialog +import eltos.simpledialogfragment.color.SimpleColorDialog + +/** + * The configuration screen for the [UpcomingWidget] AppWidget. + */ +class UpcomingWidgetConfigureActivity : AppCompatActivity(), + SimpleDialog.OnDialogResultListener { + private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + + private var onClickListener = View.OnClickListener { + val context = this@UpcomingWidgetConfigureActivity + val appWidgetManager = AppWidgetManager.getInstance(context) + + updateAppWidget( + context, + appWidgetManager, + appWidgetId, + ) + + val resultValue = Intent() + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + setResult(RESULT_OK, resultValue) + finish() + } + private lateinit var binding: UpcomingWidgetConfigureBinding + + public override fun onCreate(icicle: Bundle?) { + ThemeManager(this).applyTheme() + super.onCreate(icicle) + setResult(RESULT_CANCELED) + + binding = UpcomingWidgetConfigureBinding.inflate(layoutInflater) + setContentView(binding.root) + val prefs = getSharedPreferences(UpcomingWidget.PREFS_NAME, Context.MODE_PRIVATE) + + binding.topBackgroundButton.setOnClickListener { + val tag = UpcomingWidget.PREF_BACKGROUND_COLOR + SimpleColorDialog().title(R.string.custom_theme) + .colorPreset( + prefs.getInt( + UpcomingWidget.PREF_BACKGROUND_COLOR, + ContextCompat.getColor(this, R.color.theme) + ) + ) + .colors( + this@UpcomingWidgetConfigureActivity, + SimpleColorDialog.MATERIAL_COLOR_PALLET + ) + .setupColorWheelAlpha(true) + .allowCustom(true) + .showOutline(0x46000000) + .gridNumColumn(5) + .choiceMode(SimpleColorDialog.SINGLE_CHOICE) + .neg() + .show(this@UpcomingWidgetConfigureActivity, tag) + } + binding.bottomBackgroundButton.setOnClickListener { + val tag = UpcomingWidget.PREF_BACKGROUND_FADE + SimpleColorDialog().title(R.string.custom_theme) + .colorPreset(prefs.getInt(UpcomingWidget.PREF_BACKGROUND_FADE, Color.GRAY)) + .colors( + this@UpcomingWidgetConfigureActivity, + SimpleColorDialog.MATERIAL_COLOR_PALLET + ) + .setupColorWheelAlpha(true) + .allowCustom(true) + .showOutline(0x46000000) + .gridNumColumn(5) + .choiceMode(SimpleColorDialog.SINGLE_CHOICE) + .neg() + .show(this@UpcomingWidgetConfigureActivity, tag) + } + binding.titleColorButton.setOnClickListener { + val tag = UpcomingWidget.PREF_TITLE_TEXT_COLOR + SimpleColorDialog().title(R.string.custom_theme) + .colorPreset(prefs.getInt(UpcomingWidget.PREF_TITLE_TEXT_COLOR, Color.WHITE)) + .colors( + this@UpcomingWidgetConfigureActivity, + SimpleColorDialog.MATERIAL_COLOR_PALLET + ) + .allowCustom(true) + .showOutline(0x46000000) + .gridNumColumn(5) + .choiceMode(SimpleColorDialog.SINGLE_CHOICE) + .neg() + .show(this@UpcomingWidgetConfigureActivity, tag) + } + binding.countdownColorButton.setOnClickListener { + val tag = UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR + SimpleColorDialog().title(R.string.custom_theme) + .colorPreset( + prefs.getInt( + UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, + Color.WHITE + ) + ) + .colors( + this@UpcomingWidgetConfigureActivity, + SimpleColorDialog.MATERIAL_COLOR_PALLET + ) + .allowCustom(true) + .showOutline(0x46000000) + .gridNumColumn(5) + .choiceMode(SimpleColorDialog.SINGLE_CHOICE) + .neg() + .show(this@UpcomingWidgetConfigureActivity, tag) + } + + binding.addButton.setOnClickListener(onClickListener) + + val intent = intent + val extras = intent.extras + if (extras != null) { + appWidgetId = extras.getInt( + AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID + ) + } + + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + finish() + return + } + } + + override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean { + if (which == SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE) { + when (dialogTag) { + UpcomingWidget.PREF_BACKGROUND_COLOR -> { + getSharedPreferences( + UpcomingWidget.PREFS_NAME, + Context.MODE_PRIVATE + ).edit() + .putInt( + UpcomingWidget.PREF_BACKGROUND_COLOR, + extras.getInt(SimpleColorDialog.COLOR) + ) + .apply() + } + + UpcomingWidget.PREF_BACKGROUND_FADE -> { + getSharedPreferences( + UpcomingWidget.PREFS_NAME, + Context.MODE_PRIVATE + ).edit() + .putInt( + UpcomingWidget.PREF_BACKGROUND_FADE, + extras.getInt(SimpleColorDialog.COLOR) + ) + .apply() + } + + UpcomingWidget.PREF_TITLE_TEXT_COLOR -> { + getSharedPreferences( + UpcomingWidget.PREFS_NAME, + Context.MODE_PRIVATE + ).edit() + .putInt( + UpcomingWidget.PREF_TITLE_TEXT_COLOR, + extras.getInt(SimpleColorDialog.COLOR) + ) + .apply() + } + + UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR -> { + getSharedPreferences( + UpcomingWidget.PREFS_NAME, + Context.MODE_PRIVATE + ).edit() + .putInt( + UpcomingWidget.PREF_COUNTDOWN_TEXT_COLOR, + extras.getInt(SimpleColorDialog.COLOR) + ) + .apply() + } + + } + } + return true + } + +} \ No newline at end of file diff --git a/app/src/main/res/drawable/gradient_background.xml b/app/src/main/res/drawable/gradient_background.xml index 20e9ffd6..d4b19a1f 100644 --- a/app/src/main/res/drawable/gradient_background.xml +++ b/app/src/main/res/drawable/gradient_background.xml @@ -4,5 +4,5 @@ + android:startColor="@color/theme"/> diff --git a/app/src/main/res/layout-land/activity_profile.xml b/app/src/main/res/layout-land/activity_profile.xml index 0aefbb9d..7e01d082 100644 --- a/app/src/main/res/layout-land/activity_profile.xml +++ b/app/src/main/res/layout-land/activity_profile.xml @@ -141,11 +141,11 @@ android:layout_gravity="bottom" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" - android:layout_marginTop="210dp" + android:layout_marginTop="200dp" android:layout_marginBottom="2dp" android:backgroundTint="?attr/colorSurfaceVariant" android:baselineAligned="false" - app:cardCornerRadius="16dp"> + app:cardCornerRadius="24dp"> - - + app:cardCornerRadius="24dp"> + + + + - - - - - - -