From 898bdfcda220b611fe0ba985240181736a068c7c Mon Sep 17 00:00:00 2001 From: Akshit Sinha Date: Thu, 24 Feb 2022 12:35:36 +0530 Subject: [PATCH 1/4] "Deck Search" display updated instead of displaying the entire deck path, now only the subdeck name is displayed along with appropriate indentation. Deck and subdeck creation works just like before. --- .../ichi2/anki/dialogs/DeckSelectionDialog.kt | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt index 7d6a888ab601..cdf8b9d2ee23 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt @@ -219,17 +219,26 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { open inner class DecksArrayAdapter(deckNames: List) : RecyclerView.Adapter(), Filterable { inner class ViewHolder(val deckTextView: TextView) : RecyclerView.ViewHolder(deckTextView) { + var deckName: String = "" + fun setDeck(deck: SelectableDeck) { - deckTextView.text = deck.name + deckName = deck.name + deckTextView.text = deck.displayName } + /* + deckName and deckTextView.text are different, so that + even though the displayName will be used for display in + the recyclerView, the deckName(which is the entire deck path) + will be used in the below init functions (which require the path) + */ + init { deckTextView.setOnClickListener { - val deckName = deckTextView.text.toString() selectDeckByNameAndClose(deckName) } deckTextView.setOnLongClickListener { // creating sub deck with parent deck path - showSubDeckDialog(deckTextView.text.toString()) + showSubDeckDialog(deckName) true } } @@ -312,9 +321,14 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { */ val name: String + var displayName: String = "" + // The name to be displayed in the Recycler View + // contains only subdeck name, not "deck::subdeck" + constructor(deckId: Long, name: String) { this.deckId = deckId this.name = name + this.displayName = getDisplayName(name) } protected constructor(d: Deck) : this(d.getLong("id"), d.getString("name")) @@ -323,6 +337,24 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { name = `in`.readString()!! } + /* + The getDisplayName function takes the entire deck path as input, + and returns only the name of the deck/subdeck + */ + + private fun getDisplayName(name: String): String { + var displayName = name + var subDeckLevel: Int = name.count { "::".contains(it) } / 2 + + while (subDeckLevel > 0) { + displayName = displayName.slice(displayName.indexOf("::") + 2 until displayName.length) + subDeckLevel-- + } + displayName = "\t\t".repeat(name.count { "::".contains(it) } / 2) + displayName + + return displayName + } + /** "All decks" comes first. Then usual deck name order. */ override fun compareTo(other: SelectableDeck): Int { if (deckId == Stats.ALL_DECKS_ID) { From 122a1575a86ed167dc6418bf8dd792ace28bece1 Mon Sep 17 00:00:00 2001 From: Akshit Sinha Date: Sat, 26 Feb 2022 01:15:12 +0530 Subject: [PATCH 2/4] Optimized function and refactored comments refactored comments as suggested. Optimized function `getDisplayName()` as suggested. `displayName` is now a val not a var, and is a `get()` property. to do next: add test. --- .../ichi2/anki/dialogs/DeckSelectionDialog.kt | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt index cdf8b9d2ee23..b5f35a14153a 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt @@ -226,13 +226,6 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { deckTextView.text = deck.displayName } - /* - deckName and deckTextView.text are different, so that - even though the displayName will be used for display in - the recyclerView, the deckName(which is the entire deck path) - will be used in the below init functions (which require the path) - */ - init { deckTextView.setOnClickListener { selectDeckByNameAndClose(deckName) @@ -321,14 +314,20 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { */ val name: String - var displayName: String = "" - // The name to be displayed in the Recycler View - // contains only subdeck name, not "deck::subdeck" + /** + * The name to be displayed to the user. Contains + * only the sub-deck name with proper indentation + * rather than the entire deck name. + * Eg: foo::bar -> \t\tbar + */ + val displayName: String // TODO should be a lazy value + get() { + return getDisplayName(name) + } constructor(deckId: Long, name: String) { this.deckId = deckId this.name = name - this.displayName = getDisplayName(name) } protected constructor(d: Deck) : this(d.getLong("id"), d.getString("name")) @@ -337,20 +336,14 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { name = `in`.readString()!! } - /* - The getDisplayName function takes the entire deck path as input, - and returns only the name of the deck/subdeck + /** + * @param name the entire name(path) of the deck + * @return the deck/subdeck name to be displayed to the user */ - private fun getDisplayName(name: String): String { - var displayName = name - var subDeckLevel: Int = name.count { "::".contains(it) } / 2 - - while (subDeckLevel > 0) { - displayName = displayName.slice(displayName.indexOf("::") + 2 until displayName.length) - subDeckLevel-- - } - displayName = "\t\t".repeat(name.count { "::".contains(it) } / 2) + displayName + var nameArr = name.split("::") + var displayName = nameArr[nameArr.size - 1] + displayName = "\t\t".repeat(nameArr.size - 1) + displayName return displayName } From a13268a559d0289ffb46f0acb176820a151e9cc4 Mon Sep 17 00:00:00 2001 From: Akshit Sinha Date: Sat, 26 Feb 2022 19:33:45 +0530 Subject: [PATCH 3/4] code refactoring --- .../java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt index b5f35a14153a..cd3700b1e645 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/dialogs/DeckSelectionDialog.kt @@ -321,9 +321,7 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { * Eg: foo::bar -> \t\tbar */ val displayName: String // TODO should be a lazy value - get() { - return getDisplayName(name) - } + get() = getDisplayName(name) constructor(deckId: Long, name: String) { this.deckId = deckId @@ -342,10 +340,7 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() { */ private fun getDisplayName(name: String): String { var nameArr = name.split("::") - var displayName = nameArr[nameArr.size - 1] - displayName = "\t\t".repeat(nameArr.size - 1) + displayName - - return displayName + return "\t\t".repeat(nameArr.size - 1) + nameArr[nameArr.size - 1] } /** "All decks" comes first. Then usual deck name order. */ From 145381fcf0e01e4b85b161f771fbe3cefe1ff1bc Mon Sep 17 00:00:00 2001 From: Akshit Sinha Date: Sun, 27 Feb 2022 11:59:48 +0530 Subject: [PATCH 4/4] Added test for `displayName` --- .../anki/dialogs/DeckSelectionDialogTest.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 AnkiDroid/src/test/java/com/ichi2/anki/dialogs/DeckSelectionDialogTest.kt diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/dialogs/DeckSelectionDialogTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/dialogs/DeckSelectionDialogTest.kt new file mode 100644 index 000000000000..69ff21e9be4a --- /dev/null +++ b/AnkiDroid/src/test/java/com/ichi2/anki/dialogs/DeckSelectionDialogTest.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 Akshit Sinha + * + * 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 . + */ + +package com.ichi2.anki.dialogs + +import com.ichi2.anki.dialogs.DeckSelectionDialog.SelectableDeck +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers +import org.junit.Test + +class DeckSelectionDialogTest { + + @Test + fun verifyDeckDisplayName() { + val input = "deck::sub-deck::sub-deck2::sub-deck3" + val expected = "\t\t\t\t\t\tsub-deck3" + + val deck = SelectableDeck(1234, input) + val actual: String = deck.displayName + + assertThat(actual, Matchers.equalTo(expected)) + } +}