From 5c73d659fede9c731d21178cc89f575133e9569d Mon Sep 17 00:00:00 2001 From: Prateek Singh Date: Thu, 13 Oct 2022 06:47:18 +0530 Subject: [PATCH] Implemented new Notification Preference. New Notification Preference will show the list of decks as per my GSoC Proposal and dissucced on issue (#4944) --- .../NotificationsSettingsFragment.kt | 168 +++++++++++++----- .../com/ichi2/anki/preferences/Preferences.kt | 2 - .../fragment_preference_notification.xml | 38 ++++ 3 files changed, 159 insertions(+), 49 deletions(-) create mode 100644 AnkiDroid/src/main/res/layout/fragment_preference_notification.xml diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt index 999a44831703..be26b64e0e8b 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt @@ -15,64 +15,138 @@ */ package com.ichi2.anki.preferences -import android.app.AlarmManager -import android.content.Context.ALARM_SERVICE -import android.content.Intent -import androidx.preference.ListPreference -import androidx.preference.SwitchPreference +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ProgressBar +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.ichi2.anki.CollectionHelper import com.ichi2.anki.R -import com.ichi2.anki.services.BootService.Companion.scheduleNotification -import com.ichi2.anki.services.NotificationService -import com.ichi2.compat.CompatHelper -import com.ichi2.libanki.utils.TimeManager -import com.ichi2.utils.AdaptionUtil +import com.ichi2.anki.UIUtils +import com.ichi2.anki.widgets.NotificationPreferenceAdapter +import com.ichi2.async.CollectionTask +import com.ichi2.async.TaskListenerWithContext +import com.ichi2.async.TaskManager +import com.ichi2.libanki.Collection +import com.ichi2.libanki.DeckId +import com.ichi2.libanki.sched.AbstractDeckTreeNode +import com.ichi2.libanki.sched.DeckDueTreeNode +import com.ichi2.libanki.sched.TreeNode +import com.ichi2.libanki.sched.findInDeckTree +import timber.log.Timber /** * Fragment with preferences related to notifications */ -class NotificationsSettingsFragment : SettingsFragment() { - override val preferenceResource: Int - get() = R.xml.preferences_notifications - override val analyticsScreenNameConstant: String - get() = "prefs.notifications" - - override fun initSubscreen() { - if (AdaptionUtil.isXiaomiRestrictedLearningDevice) { - /** These preferences should be searchable or not based - * on this same condition at [Preferences.configureSearchBar] */ - preferenceScreen.removePreference(requirePreference(R.string.pref_notifications_vibrate_key)) - preferenceScreen.removePreference(requirePreference(R.string.pref_notifications_blink_key)) +class NotificationsSettingsFragment : Fragment() { + + private lateinit var mDeckListAdapter: NotificationPreferenceAdapter + private lateinit var mRecyclerView: RecyclerView + private lateinit var mProgressBar: ProgressBar + var dueTree: List>? = null + val col: Collection + get() = CollectionHelper.instance.getCol(requireContext())!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_preference_notification, container, false) + initViews(view) + + // create and set an adapter for the RecyclerView + mDeckListAdapter = NotificationPreferenceAdapter(layoutInflater, requireContext()).apply { + setTimeClickListener(mOnTimeClickListener) + setDeckExpanderClickListener(mDeckExpanderClickListener) + } + mRecyclerView.apply { + adapter = mDeckListAdapter + layoutManager = LinearLayoutManager(context) } - // Minimum cards due - // The number of cards that should be due today in a deck to justify adding a notification. - requirePreference(R.string.pref_notifications_minimum_cards_due_key).apply { - updateNotificationPreference(this) - setOnPreferenceChangeListener { preference, newValue -> - updateNotificationPreference(preference as ListPreference) - if ((newValue as String).toInt() < Preferences.PENDING_NOTIFICATIONS_ONLY) { - scheduleNotification(TimeManager.time, requireContext()) - } else { - val intent = CompatHelper.compat.getImmutableBroadcastIntent( - requireContext(), 0, - Intent(requireContext(), NotificationService::class.java), 0 - ) - val alarmManager = requireActivity().getSystemService(ALARM_SERVICE) as AlarmManager - alarmManager.cancel(intent) - } - true + + // Fetch Deck Data + TaskManager.launchCollectionTask( + CollectionTask.LoadDeckCounts(), + UpdateDeckListListener(this) + ) + + return view + } + + private val mOnTimeClickListener = View.OnClickListener { + TODO("Open Time picker bottom sheet.") + } + + private val mDeckExpanderClickListener = View.OnClickListener { view -> + toggleDeckExpand(view.tag as Long) + } + + @Suppress("UNCHECKED_CAST") + fun toggleDeckExpand(did: DeckId) { + if (!col.decks.children(did).isEmpty()) { + // update DB + col.decks.collapse(did) + // update stored state + val deck: List> = dueTree!! as List> + Timber.d(dueTree!!.toString() + " " + did) + findInDeckTree(deck, did)?.run { + collapsed = !collapsed } + mDeckListAdapter.buildDeckList(dueTree!!, col) + } + } + + private fun initViews(view: View) { + mRecyclerView = view.findViewById(R.id.preference_notification_rv) + mProgressBar = view.findViewById(R.id.preference_notification_progressbar) + } + + fun onDecksLoaded(result: List>?) { + Timber.i("Updating deck list UI") + // Make sure the fragment is visible + + if (result == null) { + Timber.e("null result loading deck counts") + showCollectionErrorMessage() + return } + dueTree = result.map { x -> x.unsafeCastToType() } + mDeckListAdapter.buildDeckList(dueTree!!, col) + hideProgressBar() + Timber.d("Startup - Deck List UI Completed") + } + + private fun showProgressBar() { + mRecyclerView.visibility = View.GONE + mProgressBar.visibility = View.VISIBLE } - private fun updateNotificationPreference(listPreference: ListPreference) { - val entries = listPreference.entries - val values = listPreference.entryValues - for (i in entries.indices) { - val value = values[i].toString().toInt() - if (entries[i].toString().contains("%d")) { - entries[i] = String.format(entries[i].toString(), value) + private fun hideProgressBar() { + mRecyclerView.visibility = View.VISIBLE + mProgressBar.visibility = View.GONE + } + + private fun showCollectionErrorMessage() { + UIUtils.showThemedToast(context, "Unable to Access Collection", true) + } + + private class UpdateDeckListListener(context: NotificationsSettingsFragment) : + TaskListenerWithContext>?>(context) { + override fun actualOnPreExecute(context: NotificationsSettingsFragment) { + + if (!CollectionHelper.instance.colIsOpen()) { + context.showProgressBar() } + Timber.d("Refreshing deck list") } - listPreference.entries = entries + + override fun actualOnPostExecute( + context: NotificationsSettingsFragment, + result: List>? + ) = context.onDecksLoaded(result) } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt index af0eb0451a23..058548e9c284 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt @@ -131,7 +131,6 @@ class Preferences : AnkiActivity(), SearchPreferenceResultListener { index(R.xml.preferences_sync) index(R.xml.preferences_custom_sync_server) .addBreadcrumb(R.string.pref_cat_sync) - index(R.xml.preferences_notifications) index(R.xml.preferences_appearance) index(R.xml.preferences_custom_buttons) .addBreadcrumb(R.string.pref_cat_appearance) @@ -335,7 +334,6 @@ class Preferences : AnkiActivity(), SearchPreferenceResultListener { R.xml.preferences_reviewing -> ReviewingSettingsFragment() R.xml.preferences_sync -> SyncSettingsFragment() R.xml.preferences_custom_sync_server -> CustomSyncServerSettingsFragment() - R.xml.preferences_notifications -> NotificationsSettingsFragment() R.xml.preferences_appearance -> AppearanceSettingsFragment() R.xml.preferences_controls -> ControlsSettingsFragment() R.xml.preferences_advanced -> AdvancedSettingsFragment() diff --git a/AnkiDroid/src/main/res/layout/fragment_preference_notification.xml b/AnkiDroid/src/main/res/layout/fragment_preference_notification.xml new file mode 100644 index 000000000000..135de3ba798d --- /dev/null +++ b/AnkiDroid/src/main/res/layout/fragment_preference_notification.xml @@ -0,0 +1,38 @@ + + + + + + + + + \ No newline at end of file