|
15 | 15 | */ |
16 | 16 | package com.ichi2.anki |
17 | 17 |
|
18 | | -import android.view.MotionEvent |
19 | | -import android.view.View |
20 | | -import android.widget.Spinner |
21 | | -import androidx.appcompat.app.AppCompatActivity |
22 | 18 | import androidx.fragment.app.Fragment |
23 | 19 | import com.ichi2.anki.CollectionManager.withCol |
24 | | -import com.ichi2.anki.common.utils.annotation.KotlinCleanup |
25 | 20 | import com.ichi2.anki.dialogs.DeckSelectionDialog |
26 | | -import com.ichi2.anki.dialogs.DeckSelectionDialog.DeckCreationListener |
27 | | -import com.ichi2.anki.libanki.Collection |
28 | 21 | import com.ichi2.anki.libanki.DeckId |
29 | | -import com.ichi2.anki.libanki.DeckNameId |
30 | 22 | import com.ichi2.anki.model.SelectableDeck |
31 | | -import com.ichi2.anki.model.SelectableDeck.Companion.fromCollection |
32 | | -import com.ichi2.anki.utils.showDialogFragmentImpl |
33 | | -import com.ichi2.anki.widgets.DeckDropDownAdapter |
34 | | -import com.ichi2.utils.FragmentManagerSupplier |
35 | | -import com.ichi2.utils.asFragmentManagerSupplier |
36 | | -import timber.log.Timber |
| 23 | + |
| 24 | +// TODO left for this class: |
| 25 | +// - extract the TextView used as the deck name into own layout for easier reuse(note: |
| 26 | +// NoteEditorFragment usage looks slightly different) |
| 27 | +// - remove duplication in *.startDeckSelection() methods code |
| 28 | +// - rename(probably DeckSelection.kt or DeckSelectionUtil.kt) and move this class to a more |
| 29 | +// suitable package(probably com.ichi2.anki.utils) |
37 | 30 |
|
38 | 31 | /** |
39 | | - * Handles expansion of a [Spinner], allowing a press to display a [DeckSelectionDialog] |
40 | | - * Responsible for filtering the decks to display in the [DeckSelectionDialog] |
41 | | - * |
42 | | - * Populates the spinner with data, and handles display of the selected deck within the spinner control |
43 | | - * |
44 | | - * @param spinner |
45 | | - * The spinner displayed in the activity. |
46 | | - * Empty at construction. After initialization, it contains in this order: |
47 | | - * 1. "All decks" if [showAllDecks] is true |
48 | | - * 2. All decks from [dropDownDecks]. |
49 | | - * @param showAllDecks Whether the deck selection should allow "All Decks" as an option |
50 | | - * @param alwaysShowDefault If true, never hide the default deck. If false, match [DeckPicker]'s logic |
51 | | - * @param showFilteredDecks whether to show filtered decks |
| 32 | + * [DeckId] constant to represent "All decks" in screens that need it(ex. browser). |
52 | 33 | */ |
53 | | -@KotlinCleanup( |
54 | | - "this class is a mess: showAllDecks, AND the adapter seems overly complicated as " + |
55 | | - "only the selected item is visible", |
56 | | -) |
57 | | -class DeckSpinnerSelection( |
58 | | - private val context: AppCompatActivity, |
59 | | - private val spinner: Spinner, |
60 | | - private val showAllDecks: Boolean, |
61 | | - private val alwaysShowDefault: Boolean, |
62 | | - private val showFilteredDecks: Boolean, |
63 | | - private val fragmentManagerSupplier: FragmentManagerSupplier = context.asFragmentManagerSupplier(), |
64 | | -) { |
65 | | - private var deckDropDownAdapter: DeckDropDownAdapter? = null |
66 | | - |
67 | | - // This should be deckDropDownAdapter.decks |
68 | | - // but this class also handles initializeNoteEditorDeckSpinner, so this can't happen yet |
69 | | - private var dropDownDecks: MutableList<DeckNameId>? = null |
70 | | - |
71 | | - /** @return All decks. */ |
72 | | - private fun computeDropDownDecks( |
73 | | - col: Collection, |
74 | | - includeFiltered: Boolean, |
75 | | - ): List<DeckNameId> = col.decks.allNamesAndIds(includeFiltered = includeFiltered) |
76 | | - |
77 | | - private fun setSpinnerListener() { |
78 | | - spinner.setOnTouchListener { _: View?, motionEvent: MotionEvent -> |
79 | | - if (motionEvent.action == MotionEvent.ACTION_UP) { |
80 | | - context.launchCatchingTask { displayDeckSelectionDialog() } |
81 | | - } |
82 | | - true |
83 | | - } |
84 | | - setSpinnerVisibility(View.VISIBLE) |
85 | | - } |
86 | | - |
87 | | - /** |
88 | | - * Move the selected deck in the spinner to [deckId]. |
89 | | - * Timber if [deckId] is not an id of a known deck. |
90 | | - * @param deckId The ID of the deck to select |
91 | | - */ |
92 | | - fun updateDeckPosition(deckId: DeckId) { |
93 | | - // TODO: This doesn't handle ALL_DECKS |
94 | | - val position = dropDownDecks?.map { it.id }?.indexOf(deckId) ?: -1 |
95 | | - if (position != -1) { |
96 | | - spinner.setSelection(position) |
97 | | - } else { |
98 | | - Timber.w("updateDeckPosition() error :: deckId=%d, position=%d", deckId, position) |
99 | | - } |
100 | | - } |
101 | | - |
102 | | - fun notifyDataSetChanged() { |
103 | | - deckDropDownAdapter!!.notifyDataSetChanged() |
104 | | - } |
105 | | - |
106 | | - fun setEnabledActionBarSpinner(enabled: Boolean) { |
107 | | - spinner.isEnabled = enabled |
108 | | - } |
109 | | - |
110 | | - fun setSpinnerVisibility(view: Int) { |
111 | | - spinner.visibility = view |
112 | | - } |
113 | | - |
114 | | - /** |
115 | | - * Iterates the drop down decks, and selects the one matching the given id. |
116 | | - * @param deckId The deck id to be selected. |
117 | | - * @param setAsCurrentDeck If true, deckId will be set as the current deck id of Collection |
118 | | - * (this means the deck selected here will continue to appear in any future Activity whose |
119 | | - * display data is loaded from Collection's current deck). If false, deckId will not be set as |
120 | | - * the current deck id of Collection. |
121 | | - * @return True if selection succeeded. |
122 | | - */ |
123 | | - suspend fun selectDeckById( |
124 | | - deckId: DeckId, |
125 | | - setAsCurrentDeck: Boolean, |
126 | | - ): Boolean = |
127 | | - if (deckId == ALL_DECKS_ID || this.dropDownDecks == null) { |
128 | | - selectAllDecks() |
129 | | - } else { |
130 | | - selectDeck(deckId, setAsCurrentDeck) |
131 | | - } |
132 | | - |
133 | | - /** |
134 | | - * select in the spinner deck with id |
135 | | - * @param deckId The deck id to search (not ALL_DECKS_ID) |
136 | | - * @param setAsCurrentDeck whether this deck should be selected in the collection (if it exists) |
137 | | - * @return whether it was found |
138 | | - */ |
139 | | - private suspend fun selectDeck( |
140 | | - deckId: DeckId, |
141 | | - setAsCurrentDeck: Boolean, |
142 | | - ): Boolean { |
143 | | - val deck = this.dropDownDecks?.withIndex()?.firstOrNull { it.value.id == deckId } ?: return false |
144 | | - val position = if (showAllDecks) deck.index + 1 else deck.index |
145 | | - spinner.setSelection(position) |
146 | | - if (setAsCurrentDeck) { |
147 | | - withCol { decks.select(deckId) } |
148 | | - } |
149 | | - return true |
150 | | - } |
151 | | - |
152 | | - /** |
153 | | - * Select all decks. Must be called only if [showAllDecks]. |
154 | | - * @return whether selection was a success. |
155 | | - */ |
156 | | - fun selectAllDecks(): Boolean { |
157 | | - if (!showAllDecks) { |
158 | | - CrashReportService.sendExceptionReport( |
159 | | - "selectAllDecks was called while `showAllDecks is false`", |
160 | | - "DeckSpinnerSelection:selectAllDecks", |
161 | | - ) |
162 | | - return false |
163 | | - } |
164 | | - spinner.setSelection(0) |
165 | | - return true |
166 | | - } |
167 | | - |
168 | | - /** |
169 | | - * Displays a [DeckSelectionDialog] |
170 | | - */ |
171 | | - suspend fun displayDeckSelectionDialog() { |
172 | | - val decks: MutableList<SelectableDeck> = fromCollection(includeFiltered = showFilteredDecks).toMutableList() |
173 | | - if (showAllDecks) { |
174 | | - decks.add(SelectableDeck.AllDecks) |
175 | | - } |
176 | | - val dialog = DeckSelectionDialog.newInstance(context.getString(R.string.search_deck), null, false, decks) |
177 | | - // TODO: retain state after onDestroy |
178 | | - dialog.deckCreationListener = DeckCreationListener { onDeckAdded(it) } |
179 | | - showDialogFragmentImpl(fragmentManagerSupplier.getFragmentManager(), dialog) |
180 | | - } |
181 | | - |
182 | | - private fun onDeckAdded(deck: DeckNameId) { |
183 | | - Timber.d("added deck %s to spinner", deck) |
184 | | - deckDropDownAdapter?.addDeck(deck) |
185 | | - dropDownDecks?.add(deck) |
186 | | - } |
187 | | - |
188 | | - companion object { |
189 | | - const val ALL_DECKS_ID = 0L |
190 | | - } |
191 | | -} |
| 34 | +const val ALL_DECKS_ID = 0L |
192 | 35 |
|
193 | 36 | /** |
194 | 37 | * Displays a [DeckSelectionDialog] for the user to select a deck, with the list of displayed decks |
|
0 commit comments