Skip to content

Commit 7a291a4

Browse files
committed
refactor(card-browser): move browserColumnHeadings to fragment
Issue 17901
1 parent fa0d622 commit 7a291a4

File tree

3 files changed

+66
-69
lines changed

3 files changed

+66
-69
lines changed

AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ import android.content.DialogInterface
2323
import android.content.Intent
2424
import android.os.Bundle
2525
import android.view.KeyEvent
26-
import android.view.LayoutInflater
2726
import android.view.Menu
2827
import android.view.MenuItem
2928
import android.view.SubMenu
3029
import android.view.View
31-
import android.view.ViewGroup
3230
import android.view.WindowManager
3331
import android.view.inputmethod.InputMethodManager
3432
import android.widget.BaseAdapter
@@ -56,7 +54,6 @@ import com.ichi2.anki.CollectionManager.TR
5654
import com.ichi2.anki.CollectionManager.withCol
5755
import com.ichi2.anki.android.input.ShortcutGroup
5856
import com.ichi2.anki.android.input.shortcut
59-
import com.ichi2.anki.browser.BrowserColumnSelectionFragment
6057
import com.ichi2.anki.browser.BrowserRowCollection
6158
import com.ichi2.anki.browser.CardBrowserFragment
6259
import com.ichi2.anki.browser.CardBrowserLaunchOptions
@@ -65,8 +62,6 @@ import com.ichi2.anki.browser.CardBrowserViewModel.SearchState
6562
import com.ichi2.anki.browser.CardBrowserViewModel.SearchState.Initializing
6663
import com.ichi2.anki.browser.CardBrowserViewModel.SearchState.Searching
6764
import com.ichi2.anki.browser.CardOrNoteId
68-
import com.ichi2.anki.browser.ColumnHeading
69-
import com.ichi2.anki.browser.ColumnSelectionDialogFragment
7065
import com.ichi2.anki.browser.FindAndReplaceDialogFragment
7166
import com.ichi2.anki.browser.IdsFile
7267
import com.ichi2.anki.browser.RepositionCardFragment
@@ -123,9 +118,7 @@ import com.ichi2.libanki.undoableOp
123118
import com.ichi2.ui.CardBrowserSearchView
124119
import com.ichi2.utils.LanguageUtil
125120
import com.ichi2.utils.TagsUtil.getUpdatedTags
126-
import com.ichi2.utils.dp
127121
import com.ichi2.utils.increaseHorizontalPaddingOfOverflowMenuIcons
128-
import com.ichi2.utils.updatePaddingRelative
129122
import com.ichi2.widget.WidgetStatus.updateInBackground
130123
import kotlinx.coroutines.Job
131124
import kotlinx.coroutines.launch
@@ -183,10 +176,6 @@ open class CardBrowser :
183176

184177
private var searchView: CardBrowserSearchView? = null
185178

186-
@VisibleForTesting
187-
val browserColumnHeadings: ViewGroup
188-
get() = cardBrowserFragment.browserColumnHeadings
189-
190179
private lateinit var tagsDialogFactory: TagsDialogFactory
191180
private var searchItem: MenuItem? = null
192181
private var saveSearchItem: MenuItem? = null
@@ -552,16 +541,12 @@ open class CardBrowser :
552541
// show title and hide spinner
553542
actionBarTitle.visibility = View.VISIBLE
554543
deckSpinnerSelection.setSpinnerVisibility(View.GONE)
555-
// A checkbox is added on the rows, match padding to keep the headings aligned
556-
// Due to the ripple on long press, we set padding
557-
browserColumnHeadings.updatePaddingRelative(start = 48.dp)
558544
multiSelectOnBackPressedCallback.isEnabled = true
559545
} else {
560546
Timber.d("end multiselect mode")
561547
refreshSubtitle()
562548
deckSpinnerSelection.setSpinnerVisibility(View.VISIBLE)
563549
actionBarTitle.visibility = View.GONE
564-
browserColumnHeadings.updatePaddingRelative(start = 0.dp)
565550
multiSelectOnBackPressedCallback.isEnabled = false
566551
}
567552
// reload the actionbar using the multi-select mode actionbar
@@ -589,58 +574,6 @@ open class CardBrowser :
589574
}
590575
}
591576

592-
fun showColumnSelectionDialog(selectedColumn: ColumnHeading) {
593-
Timber.d("Fetching available columns for: ${selectedColumn.label}")
594-
595-
// Prevent multiple dialogs from opening
596-
if (supportFragmentManager.findFragmentByTag(ColumnSelectionDialogFragment.TAG) != null) {
597-
Timber.d("ColumnSelectionDialog is already shown, ignoring duplicate click.")
598-
return
599-
}
600-
601-
lifecycleScope.launch {
602-
val (_, availableColumns) = viewModel.previewColumnHeadings(viewModel.cardsOrNotes)
603-
604-
if (availableColumns.isEmpty()) {
605-
Timber.w("No available columns to replace ${selectedColumn.label}")
606-
showSnackbar(R.string.no_columns_available)
607-
return@launch
608-
}
609-
610-
val dialog = ColumnSelectionDialogFragment.newInstance(selectedColumn)
611-
dialog.show(supportFragmentManager, ColumnSelectionDialogFragment.TAG)
612-
}
613-
}
614-
615-
fun onColumnNamesChanged(columnCollection: List<ColumnHeading>) {
616-
Timber.d("column names changed")
617-
browserColumnHeadings.removeAllViews()
618-
619-
val layoutInflater = LayoutInflater.from(browserColumnHeadings.context)
620-
for (column in columnCollection) {
621-
Timber.d("setting up column %s", column)
622-
layoutInflater.inflate(R.layout.browser_column_heading, browserColumnHeadings, false).apply {
623-
val columnView = this as TextView
624-
columnView.text = column.label
625-
626-
// Attach click listener to open the selection dialog
627-
columnView.setOnClickListener {
628-
Timber.d("Clicked column: ${column.label}")
629-
showColumnSelectionDialog(column)
630-
}
631-
632-
// Attach long press listener to open the manage column dialog
633-
columnView.setOnLongClickListener {
634-
Timber.d("Long-pressed column: ${column.label}")
635-
val dialog = BrowserColumnSelectionFragment.createInstance(viewModel.cardsOrNotes)
636-
dialog.show(supportFragmentManager, null)
637-
true
638-
}
639-
browserColumnHeadings.addView(columnView)
640-
}
641-
}
642-
}
643-
644577
fun onSelectedCardUpdated(unit: Unit) {
645578
if (fragmented) {
646579
loadNoteEditorFragmentIfFragmented()
@@ -657,7 +590,6 @@ open class CardBrowser :
657590
viewModel.flowOfIsInMultiSelectMode.launchCollectionInLifecycleScope(::isInMultiSelectModeChanged)
658591
viewModel.flowOfCardsUpdated.launchCollectionInLifecycleScope(::cardsUpdatedChanged)
659592
viewModel.flowOfSearchState.launchCollectionInLifecycleScope(::searchStateChanged)
660-
viewModel.flowOfColumnHeadings.launchCollectionInLifecycleScope(::onColumnNamesChanged)
661593
viewModel.cardSelectionEventFlow.launchCollectionInLifecycleScope(::onSelectedCardUpdated)
662594
}
663595

AnkiDroid/src/main/java/com/ichi2/anki/browser/CardBrowserFragment.kt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package com.ichi2.anki.browser
1818

1919
import android.os.Bundle
20+
import android.view.LayoutInflater
2021
import android.view.View
2122
import android.view.ViewGroup
23+
import android.widget.TextView
2224
import androidx.annotation.VisibleForTesting
2325
import androidx.core.content.ContextCompat
2426
import androidx.core.view.isVisible
@@ -39,9 +41,12 @@ import com.ichi2.anki.browser.CardBrowserViewModel.SearchState.Initializing
3941
import com.ichi2.anki.browser.CardBrowserViewModel.SearchState.Searching
4042
import com.ichi2.anki.common.utils.android.isRobolectric
4143
import com.ichi2.anki.launchCatchingTask
44+
import com.ichi2.anki.snackbar.showSnackbar
4245
import com.ichi2.anki.ui.attachFastScroller
4346
import com.ichi2.libanki.ChangeManager
4447
import com.ichi2.utils.HandlerUtils
48+
import com.ichi2.utils.dp
49+
import com.ichi2.utils.updatePaddingRelative
4550
import kotlinx.coroutines.flow.Flow
4651
import kotlinx.coroutines.launch
4752
import kotlinx.coroutines.runBlocking
@@ -114,6 +119,14 @@ class CardBrowserFragment :
114119
}
115120

116121
fun isInMultiSelectModeChanged(inMultiSelect: Boolean) {
122+
if (inMultiSelect) {
123+
// A checkbox is added on the rows, match padding to keep the headings aligned
124+
// Due to the ripple on long press, we set padding
125+
browserColumnHeadings.updatePaddingRelative(start = 48.dp)
126+
} else {
127+
browserColumnHeadings.updatePaddingRelative(start = 0.dp)
128+
}
129+
117130
// update adapter to remove check boxes
118131
cardsAdapter.notifyDataSetChanged()
119132
autoScrollTo(viewModel.lastSelectedPosition, viewModel.oldCardTopOffset)
@@ -137,13 +150,42 @@ class CardBrowserFragment :
137150
cardsAdapter.notifyDataSetChanged()
138151
}
139152

153+
fun onColumnNamesChanged(columnCollection: List<ColumnHeading>) {
154+
Timber.d("column names changed")
155+
browserColumnHeadings.removeAllViews()
156+
157+
val layoutInflater = LayoutInflater.from(browserColumnHeadings.context)
158+
for (column in columnCollection) {
159+
Timber.d("setting up column %s", column)
160+
val columnView = layoutInflater.inflate(R.layout.browser_column_heading, browserColumnHeadings, false) as TextView
161+
162+
columnView.text = column.label
163+
164+
// Attach click listener to open the selection dialog
165+
columnView.setOnClickListener {
166+
Timber.d("Clicked column: ${column.label}")
167+
showColumnSelectionDialog(column)
168+
}
169+
170+
// Attach long press listener to open the manage column dialog
171+
columnView.setOnLongClickListener {
172+
Timber.d("Long-pressed column: ${column.label}")
173+
val dialog = BrowserColumnSelectionFragment.createInstance(viewModel.cardsOrNotes)
174+
dialog.show(parentFragmentManager, null)
175+
true
176+
}
177+
browserColumnHeadings.addView(columnView)
178+
}
179+
}
180+
140181
viewModel.flowOfIsTruncated.launchCollectionInLifecycleScope(::onIsTruncatedChanged)
141182
viewModel.flowOfSelectedRows.launchCollectionInLifecycleScope(::onSelectedRowsChanged)
142183
viewModel.flowOfActiveColumns.launchCollectionInLifecycleScope(::onColumnsChanged)
143184
viewModel.flowOfCardsUpdated.launchCollectionInLifecycleScope(::cardsUpdatedChanged)
144185
viewModel.flowOfIsInMultiSelectMode.launchCollectionInLifecycleScope(::isInMultiSelectModeChanged)
145186
viewModel.flowOfSearchState.launchCollectionInLifecycleScope(::searchStateChanged)
146187
viewModel.rowLongPressFocusFlow.launchCollectionInLifecycleScope(::onSelectedRowUpdated)
188+
viewModel.flowOfColumnHeadings.launchCollectionInLifecycleScope(::onColumnNamesChanged)
147189
viewModel.flowOfCardStateChanged.launchCollectionInLifecycleScope(::onCardsMarkedEvent)
148190
}
149191

@@ -164,6 +206,29 @@ class CardBrowserFragment :
164206
}
165207
}
166208

209+
private fun showColumnSelectionDialog(selectedColumn: ColumnHeading) {
210+
Timber.d("Fetching available columns for: ${selectedColumn.label}")
211+
212+
// Prevent multiple dialogs from opening
213+
if (parentFragmentManager.findFragmentByTag(ColumnSelectionDialogFragment.TAG) != null) {
214+
Timber.d("ColumnSelectionDialog is already shown, ignoring duplicate click.")
215+
return
216+
}
217+
218+
lifecycleScope.launch {
219+
val (_, availableColumns) = viewModel.previewColumnHeadings(viewModel.cardsOrNotes)
220+
221+
if (availableColumns.isEmpty()) {
222+
Timber.w("No available columns to replace ${selectedColumn.label}")
223+
showSnackbar(R.string.no_columns_available)
224+
return@launch
225+
}
226+
227+
val dialog = ColumnSelectionDialogFragment.newInstance(selectedColumn)
228+
dialog.show(parentFragmentManager, ColumnSelectionDialogFragment.TAG)
229+
}
230+
}
231+
167232
// TODO: Move this to ViewModel and test
168233
@VisibleForTesting
169234
fun onTap(id: CardOrNoteId) =

AnkiDroid/src/test/java/com/ichi2/anki/CardBrowserTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1726,7 +1726,7 @@ val CardBrowser.isShowingSelectNone: Boolean
17261726

17271727
val CardBrowser.columnHeadingViews
17281728
get() =
1729-
this.browserColumnHeadings.children
1729+
this.cardBrowserFragment.browserColumnHeadings.children
17301730
.filterIsInstance<TextView>()
17311731
.toList()
17321732

0 commit comments

Comments
 (0)