Skip to content

Commit

Permalink
feature: Allow changing deck name in statistics screen
Browse files Browse the repository at this point in the history
  • Loading branch information
criticalAY committed Feb 24, 2024
1 parent f145def commit 9d2531b
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 3 deletions.
3 changes: 3 additions & 0 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@
android:exported="false"
android:configChanges="orientation|screenSize"
/>
<activity android:name="com.ichi2.anki.StatisticsActivity"
android:exported="false"
android:configChanges="orientation|screenSize" />
<activity
android:name="com.ichi2.anki.previewer.PreviewerActivity"
android:exported="false"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2024 Ashish Yadav <mailtoashish693@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.anki

import androidx.annotation.MainThread
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.button.MaterialButton
import com.ichi2.anki.dialogs.DeckSelectionDialog
import com.ichi2.anki.dialogs.DeckSelectionDialog.SelectableDeck.Companion.fromCollection
import com.ichi2.anki.widgets.DeckDropDownAdapter
import com.ichi2.libanki.Collection
import com.ichi2.libanki.DeckNameId
import com.ichi2.utils.FragmentManagerSupplier
import com.ichi2.utils.asFragmentManagerSupplier
import timber.log.Timber

/**
* Handles deck selection using a MaterialButton.
* Decks are selected from a dialog displayed when the MaterialButton is clicked.
*
* @param context The context of the Activity
* @param materialButton The MaterialButton used for deck selection.
* @param showAllDecks Indicates whether to show all decks including filtered ones.
*/
class DeckMaterialButtonSelection(
private val context: AppCompatActivity,
private val materialButton: MaterialButton,
private val showAllDecks: Boolean
) {

private val fragmentManagerSupplier: FragmentManagerSupplier = context.asFragmentManagerSupplier()

private var deckDropDownAdapter: DeckDropDownAdapter? = null

private lateinit var dropDownDecks: MutableList<DeckNameId>

@MainThread
fun initializeNoteEditorDeckMaterialButton(col: Collection) {
dropDownDecks = computeDropDownDecks(col).toMutableList()
setMaterialButtonListener()
}

private fun computeDropDownDecks(col: Collection): List<DeckNameId> =
col.decks.allNamesAndIds(includeFiltered = false)

private fun setMaterialButtonListener() {
materialButton.setOnClickListener {
context.launchCatchingTask { displayDeckSelectionDialog() }
}
}

private suspend fun displayDeckSelectionDialog() {
val decks = fromCollection(includeFiltered = false).toMutableList()
if (showAllDecks) {
decks.add(
DeckSelectionDialog.SelectableDeck(
ALL_DECKS_ID,
context.resources.getString(R.string.card_browser_all_decks)
)
)
}
val dialog = DeckSelectionDialog.newInstance(context.getString(R.string.search_deck), null, false, decks)
dialog.deckCreationListener = DeckSelectionDialog.DeckCreationListener { onDeckAdded(it) }
AnkiActivity.showDialogFragment(fragmentManagerSupplier.getFragmentManager(), dialog)
}

private fun onDeckAdded(deck: DeckNameId) {
Timber.d("added deck %s to MaterialButton", deck)
deckDropDownAdapter?.addDeck(deck)
dropDownDecks.add(deck)
}

companion object {
const val ALL_DECKS_ID = 0L
}
}
79 changes: 79 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/StatisticsActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 Ashish Yadav <mailtoashish693@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.anki

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import com.google.android.material.button.MaterialButton
import com.ichi2.anki.dialogs.DeckSelectionDialog
import com.ichi2.libanki.Collection
import com.ichi2.libanki.DeckId
import kotlin.reflect.KClass
import kotlin.reflect.jvm.jvmName

/**
* Handles changing of deck in Statistics webview
*
* Based in [SingleFragmentActivity], but with `configChanges="orientation|screenSize"`
* to avoid unwanted activity recreations
*/
class StatisticsActivity : SingleFragmentActivity(), DeckSelectionDialog.DeckSelectionListener {

private var deckMaterialSelection: DeckMaterialButtonSelection? = null
var deckId: DeckId = 0
var deckNameLive = MutableLiveData<String>()
private var collection: Collection? = null

override fun onCollectionLoaded(col: Collection) {
super.onCollectionLoaded(col)
collection = col
}

fun setupDeckSelector(button: MaterialButton) {
button.visibility = View.VISIBLE
startLoadingCollection()
deckMaterialSelection = DeckMaterialButtonSelection(
this,
button,
showAllDecks = true
).apply {
collection?.let { initializeNoteEditorDeckMaterialButton(it) }
}
}

override fun onDeckSelected(deck: DeckSelectionDialog.SelectableDeck?) {
if (deck == null) {
return
}
deckNameLive.value = deck.name
deckId = deck.deckId
}

companion object {

fun getIntent(context: Context, fragmentClass: KClass<out Fragment>, arguments: Bundle? = null): Intent {
return Intent(context, StatisticsActivity::class.java).apply {
putExtra(FRAGMENT_NAME_EXTRA, fragmentClass.jvmName)
putExtra(FRAGMENT_ARGS_EXTRA, arguments)
}
}
}
}
27 changes: 25 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/pages/Statistics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ import android.print.PrintAttributes
import android.print.PrintManager
import android.view.View
import androidx.core.content.ContextCompat.getSystemService
import androidx.lifecycle.Observer
import com.google.android.material.appbar.MaterialToolbar
import com.ichi2.anki.CollectionManager
import com.ichi2.anki.R
import com.ichi2.anki.SingleFragmentActivity
import com.ichi2.anki.StatisticsActivity
import com.ichi2.anki.utils.getTimestamp
import com.ichi2.libanki.utils.TimeManager

Expand All @@ -47,6 +48,28 @@ class Statistics : PageFragment() {
true
}
}
(activity as? StatisticsActivity)?.setupDeckSelector(view.findViewById(R.id.change_deck_button))

(activity as? StatisticsActivity)?.deckNameLive?.observe(
viewLifecycleOwner,
Observer { deck ->
changeDeck(deck)
}
)
}

/**
* This method is a workaround to change the deck in the webview by finding the text box and
* replacing the deck name with the selected deck name from the dialog and updating the stats
**/
private fun changeDeck(selectedDeck: String) {
val javascriptCode = """
var textBox = [].slice.call(document.getElementsByTagName('input'), 0).filter(x => x.type == "text")[0];
textBox.value = "deck:$selectedDeck";
textBox.dispatchEvent(new Event("input", { bubbles: true }));
textBox.dispatchEvent(new Event("change"));
""".trimIndent()
webView.evaluateJavascript(javascriptCode, null)
}

/**Prepares and initiates a printing task for the content(stats) displayed in the WebView.
Expand All @@ -66,7 +89,7 @@ class Statistics : PageFragment() {

companion object {
fun getIntent(context: Context): Intent {
return SingleFragmentActivity.getIntent(context, Statistics::class)
return StatisticsActivity.getIntent(context, Statistics::class)
}
}
}
11 changes: 10 additions & 1 deletion AnkiDroid/src/main/res/layout/page_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible"/>

<com.google.android.material.button.MaterialButton
android:id="@+id/change_deck_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/card_browser_change_deck"
android:visibility="gone" />

</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ object ActivityList {
get(PermissionsActivity::class.java),
get(SingleFragmentActivity::class.java),
get(ImageOcclusionActivity::class.java),
get(StatisticsActivity::class.java),
get(PreviewerActivity::class.java)
)
}
Expand Down

0 comments on commit 9d2531b

Please sign in to comment.