Skip to content

Commit

Permalink
Merge branch 'ankidroid:main' into refactor-Tags-Dialog-Material-Dial…
Browse files Browse the repository at this point in the history
…og-to-Alert-Dialog
  • Loading branch information
neeldoshii authored Feb 7, 2024
2 parents f4ea733 + 219bf2e commit 954ae70
Show file tree
Hide file tree
Showing 263 changed files with 1,582 additions and 1,363 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
git remote set-url origin git@github.com:$GITHUB_REPOSITORY
shell: bash

- uses: webfactory/ssh-agent@v0.8.0
- uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

Expand Down
12 changes: 9 additions & 3 deletions AnkiDroid/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ android {
//
// This ensures the correct ordering between the various types of releases (dev < alpha < beta < release) which is
// needed for upgrades to be offered correctly.
versionCode=21700201
versionName="2.17beta1"
versionCode=21700202
versionName="2.17beta2"
minSdk 23 // also in testlib/build.gradle.kts
// After #13695: change .tests_emulator.yml
targetSdk 33 // also in [api|testlib]/build.gradle.kts and ../robolectricDownloader.gradle
Expand Down Expand Up @@ -393,8 +393,14 @@ dependencies {
testImplementation 'org.apache.commons:commons-exec:1.4.0' // obtaining the OS
testImplementation("androidx.fragment:fragment-testing:$fragments_version")
// in a JvmTest we need org.json.JSONObject to not be mocked
testImplementation 'org.json:json:20231013'
testImplementation 'org.json:json:20240205'
testImplementation 'io.github.ivanshafran:shared-preferences-mock:1.2.4'
testImplementation "androidx.test:runner:$androidx_test_version"
testImplementation "androidx.test:rules:$androidx_test_version"
testImplementation "androidx.test.espresso:espresso-core:$espresso_version"
testImplementation("androidx.test.espresso:espresso-contrib:$espresso_version") {
exclude module: "protobuf-lite"
}

androidTestImplementation project(':testlib')

Expand Down
5 changes: 5 additions & 0 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,11 @@
android:name="com.ichi2.anki.SingleFragmentActivity"
android:exported="false"
/>
<activity
android:name="com.ichi2.anki.ImageOcclusionActivity"
android:exported="false"
android:configChanges="orientation|screenSize"
/>
<activity
android:name="com.ichi2.anki.CardTemplatePreviewer"
android:label="@string/preview_title"
Expand Down
15 changes: 8 additions & 7 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.ichi2.anki.browser.CardBrowserColumn.Companion.COLUMN2_KEYS
import com.ichi2.anki.browser.CardBrowserLaunchOptions
import com.ichi2.anki.browser.CardBrowserViewModel
import com.ichi2.anki.browser.CardBrowserViewModel.*
import com.ichi2.anki.browser.PreviewerIdsFile
import com.ichi2.anki.browser.SaveSearchResult
import com.ichi2.anki.browser.SharedPreferencesLastDeckIdRepository
import com.ichi2.anki.browser.toCardBrowserLaunchOptions
Expand Down Expand Up @@ -1224,14 +1225,14 @@ open class CardBrowser :

private fun onPreview() {
val intentData = viewModel.previewIntentData
onPreviewCardsActivityResult.launch(getPreviewIntent(intentData.index, intentData.cardList))
onPreviewCardsActivityResult.launch(getPreviewIntent(intentData.index, intentData.previewerIdsFile))
}

private fun getPreviewIntent(index: Int, selectedCardIds: LongArray): Intent {
private fun getPreviewIntent(index: Int, previewerIdsFile: PreviewerIdsFile): Intent {
return if (sharedPrefs().getBoolean("new_previewer", false)) {
Previewer2Destination(index, selectedCardIds).toIntent(this)
Previewer2Destination(index, previewerIdsFile).toIntent(this)
} else {
PreviewDestination(index, selectedCardIds).toIntent(this)
PreviewDestination(index, previewerIdsFile).toIntent(this)
}
}

Expand Down Expand Up @@ -1891,7 +1892,7 @@ open class CardBrowser :
*/
private fun createViewModel() = ViewModelProvider(
viewModelStore,
CardBrowserViewModel.factory(AnkiDroidApp.instance.sharedPrefsLastDeckIdRepository),
CardBrowserViewModel.factory(AnkiDroidApp.instance.sharedPrefsLastDeckIdRepository, cacheDir),
defaultViewModelCreationExtras
)[CardBrowserViewModel::class.java]

Expand Down Expand Up @@ -2282,8 +2283,8 @@ private fun Sequence<CardId>.toCardCache(isInCardMode: CardsOrNotes): Sequence<C
return this.mapIndexed { idx, cid -> CardBrowser.CardCache(cid, this@Collection, idx, isInCardMode) }
}

class Previewer2Destination(val currentIndex: Int, val selectedCardIds: LongArray)
class Previewer2Destination(val currentIndex: Int, val previewerIdsFile: PreviewerIdsFile)

@CheckResult
fun Previewer2Destination.toIntent(context: Context) =
PreviewerFragment.getIntent(context, selectedCardIds, currentIndex)
PreviewerFragment.getIntent(context, previewerIdsFile, currentIndex)
10 changes: 10 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardTemplatePreviewer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ package com.ichi2.anki
import android.os.Bundle
import android.view.View
import com.ichi2.anki.UIUtils.showThemedToast
import com.ichi2.anki.cardviewer.Gesture
import com.ichi2.anki.cardviewer.PreviewLayout
import com.ichi2.anki.cardviewer.PreviewLayout.Companion.createAndDisplay
import com.ichi2.anki.cardviewer.ViewerCommand
import com.ichi2.annotations.NeedsTest
import com.ichi2.libanki.Card
import com.ichi2.libanki.Collection
Expand Down Expand Up @@ -98,6 +100,7 @@ open class CardTemplatePreviewer : AbstractFlashcardViewer() {
closeCardTemplatePreviewer()
}
}
setNavigationBarColor(R.attr.showAnswerColor)
showBackIcon()
// Ensure navigation drawer can't be opened. Various actions in the drawer cause crashes.
disableDrawerSwipe()
Expand Down Expand Up @@ -271,6 +274,13 @@ open class CardTemplatePreviewer : AbstractFlashcardViewer() {
showBackIcon()
}

override fun executeCommand(which: ViewerCommand, fromGesture: Gesture?): Boolean {
if (which == ViewerCommand.SHOW_ANSWER) {
return super.executeCommand(which, fromGesture)
}
return false
}

protected fun getCard(col: Collection, cardListIndex: Long): Card {
return PreviewerCard(col, cardListIndex)
}
Expand Down
20 changes: 9 additions & 11 deletions AnkiDroid/src/main/java/com/ichi2/anki/CoroutineHelpers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import com.ichi2.utils.show
import com.ichi2.utils.title
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -56,6 +55,8 @@ import net.ankiweb.rsdroid.exceptions.BackendInterruptedException
import net.ankiweb.rsdroid.exceptions.BackendNetworkException
import net.ankiweb.rsdroid.exceptions.BackendSyncException
import timber.log.Timber
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

Expand All @@ -65,11 +66,11 @@ import kotlin.coroutines.suspendCoroutine
* Other errors should ideally be handled in the block.
*/
fun CoroutineScope.launchCatching(
dispatcher: CoroutineDispatcher = Dispatchers.Default,
context: CoroutineContext = EmptyCoroutineContext,
errorMessageHandler: suspend (String) -> Unit,
block: suspend () -> Unit
): Job {
return launch(dispatcher) {
return launch(context) {
try {
block()
} catch (cancellationException: CancellationException) {
Expand All @@ -90,12 +91,9 @@ interface OnErrorListener {
val onError: MutableSharedFlow<String>
}

fun <T> T.launchCatching(
dispatcher: CoroutineDispatcher = Dispatchers.Default,
block: suspend T.() -> Unit
): Job where T : ViewModel, T : OnErrorListener {
fun <T> T.launchCatchingIO(block: suspend T.() -> Unit): Job where T : ViewModel, T : OnErrorListener {
return viewModelScope.launchCatching(
dispatcher,
Dispatchers.IO,
{ onError.emit(it) },
{ block() }
)
Expand All @@ -111,7 +109,7 @@ fun <T> T.launchCatching(
* If not, add a comment explaining why, or refactor to have a method that returns
* a non-null localized message.
*/
suspend fun <T> FragmentActivity.runCatchingTask(
suspend fun <T> FragmentActivity.runCatching(
errorMessage: String? = null,
block: suspend () -> T?
): T? {
Expand Down Expand Up @@ -198,7 +196,7 @@ fun FragmentActivity.launchCatchingTask(
block: suspend CoroutineScope.() -> Unit
): Job {
return lifecycle.coroutineScope.launch {
runCatchingTask(errorMessage) { block() }
runCatching(errorMessage) { block() }
}
}

Expand All @@ -208,7 +206,7 @@ fun Fragment.launchCatchingTask(
block: suspend CoroutineScope.() -> Unit
): Job {
return lifecycle.coroutineScope.launch {
requireActivity().runCatchingTask(errorMessage) { block() }
requireActivity().runCatching(errorMessage) { block() }
}
}

Expand Down
14 changes: 12 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import anki.collection.OpChanges
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
import com.ichi2.anki.CollectionHelper.CollectionIntegrityStorageCheck
Expand Down Expand Up @@ -198,7 +199,6 @@ open class DeckPicker :
lateinit var recyclerView: RecyclerView
private lateinit var recyclerViewLayoutManager: LinearLayoutManager
private lateinit var deckListAdapter: DeckAdapter
private val snackbarShowHideCallback = Snackbar.Callback()
lateinit var exportingDelegate: ActivityExportingDelegate
private lateinit var noDecksPlaceholder: LinearLayout
lateinit var pullToSyncWrapper: SwipeRefreshLayout
Expand All @@ -213,8 +213,19 @@ open class DeckPicker :
// flag asking user to do a full sync which is used in upgrade path
private var recommendFullSync = false

var activeSnackBar: Snackbar? = null
private val activeSnackbarCallback = object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
override fun onShown(transientBottomBar: Snackbar?) {
activeSnackBar = transientBottomBar
}

override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
activeSnackBar = null
}
}
override val baseSnackbarBuilder: SnackbarBuilder = {
anchorView = findViewById<FloatingActionButton>(R.id.fab_main)
addCallback(activeSnackbarCallback)
}

// flag keeping track of when the app has been paused
Expand Down Expand Up @@ -1841,7 +1852,6 @@ open class DeckPicker :
@NeedsTest("14608: Ensure that the deck options refer to the selected deck")
private suspend fun handleDeckSelection(did: DeckId, selectionType: DeckSelectionType) {
fun showEmptyDeckSnackbar() = showSnackbar(R.string.empty_deck) {
addCallback(snackbarShowHideCallback)
setAction(R.string.menu_add) { addNote() }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class DeckPickerFloatingActionMenu(
get() = studyOptionsFrame != null

private fun showFloatingActionMenu() {
deckPicker.activeSnackBar?.dismiss()
linearLayout.alpha = 0.5f
studyOptionsFrame?.let { it.alpha = 0.5f }
isFABOpen = true
Expand Down
42 changes: 42 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/ImageOcclusionActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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 androidx.fragment.app.Fragment
import kotlin.reflect.KClass
import kotlin.reflect.jvm.jvmName

/**
* Handles adding and editing Image Occlusion cards.
*
* Based in [SingleFragmentActivity], but with `configChanges="orientation|screenSize"`
* to avoid unwanted activity recreations
*/
class ImageOcclusionActivity : SingleFragmentActivity() {

companion object {

fun getIntent(context: Context, fragmentClass: KClass<out Fragment>, arguments: Bundle? = null): Intent {
return Intent(context, ImageOcclusionActivity::class.java).apply {
putExtra(FRAGMENT_NAME_EXTRA, fragmentClass.jvmName)
putExtra(FRAGMENT_ARGS_EXTRA, arguments)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ import androidx.drawerlayout.widget.ClosableDrawerLayout
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.color.MaterialColors
import com.google.android.material.navigation.NavigationView
import com.ichi2.anim.ActivityTransitionAnimation.Direction.*
import com.ichi2.anki.dialogs.HelpDialog
import com.ichi2.anki.dialogs.help.HelpDialog
import com.ichi2.anki.preferences.Preferences
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.workarounds.FullDraggableContainerFix
import com.ichi2.compat.CompatHelper
import com.ichi2.libanki.CardId
import com.ichi2.utils.HandlerUtils
import com.ichi2.utils.IntentUtil
import com.ichi2.utils.KotlinCleanup
import timber.log.Timber

Expand Down Expand Up @@ -323,12 +323,13 @@ abstract class NavigationDrawerActivity :

R.id.nav_help -> {
Timber.i("Navigating to help")
showDialogFragment(HelpDialog.createInstance())
showDialogFragment(HelpDialog.newHelpInstance())
}

R.id.support_ankidroid -> {
Timber.i("Navigating to support AnkiDroid")
showDialogFragment(HelpDialog.createInstanceForSupportAnkiDroid(this))
val canRateApp = IntentUtil.canOpenIntent(this, AnkiDroidApp.getMarketIntent(this))
showDialogFragment(HelpDialog.newSupportInstance(canRateApp))
}
}
}
Expand Down
11 changes: 8 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -984,15 +984,16 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags
/**
* Change the note type from oldModel to newModel, handling the case where a full sync will be required
*/
@NeedsTest("test changing note type")
private fun changeNoteType(oldNotetype: NotetypeJson, newNotetype: NotetypeJson) = launchCatchingTask {
if (!userAcceptsSchemaChange()) return@launchCatchingTask

val noteId = mEditorNote!!.id
undoableOp {
notetypes.change(oldNotetype, noteId, newNotetype, mModelChangeFieldMap!!, mModelChangeCardMap!!)
// refresh the note object to reflect the database changes
mEditorNote!!.load()
}
// refresh the note object to reflect the database changes
withCol { mEditorNote!!.load() }
// close note editor
closeNoteEditor()
}
Expand Down Expand Up @@ -2009,7 +2010,11 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags
}

private val currentlySelectedNotetype: NotetypeJson?
get() = getColUnsafe.notetypes.get(mAllModelIds!![mNoteTypeSpinner!!.selectedItemPosition])
get() = mNoteTypeSpinner?.selectedItemPosition?.let { position ->
mAllModelIds?.get(position)?.let { modelId ->
getColUnsafe.notetypes.get(modelId)
}
}

/**
* Update all the field EditText views based on the currently selected note type and the mModelChangeFieldMap
Expand Down
Loading

0 comments on commit 954ae70

Please sign in to comment.