Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DeckOption request the user to confirm whether to discard only if there are local changes #17315

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Arthur-Milchior
Copy link
Member

NF: Simplify the usage of bridgeCommand in PageFragment
bridgeCommand is the general process by which Anki's webview send
command to the webview's owner. In Anki, it's interpreted by
Python. In AnkiDroid it must be interpreted by Kotlin.

Currently, the only bridgeCommand we listen to are in
CongratsPage. And I'm really thankful @BrayanDSO for creating this
first usage!

When anki 24.10 beta 2 is used in ankidroid, the DeckOptions will also
send bridgeCommand. And, I expect that when we'll use more webview,
more bridgeCommand will arrive.

So, I decided to generalize Brayan's code and ensure that there is a
simple map that any PageFragment can override that would allow to
declare its bridgeCommand without needing to add copy
CongratsPage's code.

I tested this manually, and the CongratsPage's button still works.

Copy link
Member

@mikehardy mikehardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love the idea, implementation seems good but will defer to anyone better at Kotlin for taste and to Brayan for idea-consistency with what he was thinking

@mikehardy mikehardy added Needs Second Approval Has one approval, one more approval to merge Anki Ecosystem Compatibility labels Oct 27, 2024
david-allison

This comment was marked as resolved.

@david-allison david-allison added the Needs Author Reply Waiting for a reply from the original author label Oct 28, 2024
@david-allison
Copy link
Member

@voczi FYI

Copy link
Member

@BrayanDSO BrayanDSO left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works for me, but I agree with David's comments.

And, I expect that when we'll use more webview, more bridgeCommand will arrive.

About that, @dae himself said that he wants to avoid bridgeCommand in new code.

If this is new code and still uses bridgeCommand, I'm honestly disappointed.

@Arthur-Milchior
Copy link
Member Author

I was referring to https://github.com/ankitects/anki/pull/3410/files , which introduces changes in svelte I wanted to use (and then I realize that, even if it’s available in ankidroid-backend, it’s not in ankidroid yet).

It does not introduce new bridgeCommand (i recalled it did, I was wrong). It still uses the deckOptionsReady to state that the webview is available to let python knows that it can send request to the webview about whether the data was modified.
I would have appreciated to use it.

But I guess I can just ignore this bridge command, assume that when the page is loaded, it can accept request. And any result that is not a boolean means the page was not loaded so we can’t close it.

Still, given that bridgeCommand already exists and does not seems to be going to be deleted soon, I still suspect this PR is useful.

I’ll apply David’s change when I’m on my home computer

@Arthur-Milchior
Copy link
Member Author

oh, I finally figured out why I was confused. New bridge commands were added in https://github.com/ankitects/anki/pull/3495/files
And I need it to fix a bug in ankidroid

@Arthur-Milchior
Copy link
Member Author

So I applied @david-allison 's requested change, and then added an extra commit to solve the deck option issue.

If we eventually move away from the bridge, this will need to be updated.

@Arthur-Milchior Arthur-Milchior changed the title NF: Simplify the usage of bridgeCommand in PageFragment DeckOption request the user to confirm whether to discard only if there are local changes Nov 8, 2024
@Arthur-Milchior Arthur-Milchior removed Needs Author Reply Waiting for a reply from the original author Needs Second Approval Has one approval, one more approval to merge labels Nov 8, 2024
@Arthur-Milchior
Copy link
Member Author

Given the extra commit, I removed @mikehardy 's approval.
The nice thing here being that this show why the first two commit is useful. It's not only for code cleanliness

@Arthur-Milchior Arthur-Milchior force-pushed the bridgeCommand branch 2 times, most recently from c02bb90 to 90cdf03 Compare November 9, 2024 03:55
@Arthur-Milchior
Copy link
Member Author

Does anyone know whether PageFragments actually load their webcontent in RobolectricTest ?
Trying to run the test with the debugger, it seems clear that the BridgeCommand is not executed. I don't know whether it is because we should wait more or because the js part is not executed.

I tried adding


            runBlocking{
                delay(2000)
            }

after pressing back, and it does not solve anything. So I assume it's a problem with the JS part

@mikehardy
Copy link
Member

As discussed on Discord, the WebView is a "shadow" (that is: fake) implementation in robolectric.
The APIs are there but they largely do nothing. No content is loaded, javascript is definitely not executed.
For WebView-related tests where the WebView is expected to actually do things, it needs to be an androidTest on device

@Arthur-Milchior
Copy link
Member Author

I removed the unit test then. There is no relevant way to do them. Unless I I start to mock the webview behavior, and that does not seems interesting things to do. In particular because this would break as soon as the deck option's TS code change

For some reason I don't understand, when I am in the deck picker, with instrumented tests, long click fail to open the menu. I don't know whether it just entirely fail to be registered, or whether the instrumented test don't open the menu for some reason.
In any case, opening the menu of actions from deck is too hard, so I would prefer not to block this useful feature, unless someone is competent enough with espresso/instrumented test to help me understand what's wrong with it

@Arthur-Milchior Arthur-Milchior force-pushed the bridgeCommand branch 2 times, most recently from 66092be to 38bbf5d Compare November 11, 2024 08:16
@Arthur-Milchior
Copy link
Member Author

Rebased on top of #17419 so that I can reuse some deck picker instrumented tests function

@Arthur-Milchior Arthur-Milchior removed the Needs Author Reply Waiting for a reply from the original author label Nov 11, 2024
@BrayanDSO
Copy link
Member

Please add some around my GitHub nickname in the NF: Simplify the usage of bridgeCommand in PageFragment
commit description, so I don't get a ping every time you force push. i.e. use @BrayanDSO, not @BrayanDSO

@Arthur-Milchior
Copy link
Member Author

Done, sorry

@Arthur-Milchior Arthur-Milchior force-pushed the bridgeCommand branch 2 times, most recently from 06efeab to 7a57ae0 Compare November 11, 2024 21:05
Copy link
Member

@david-allison david-allison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main question is regarding functionality + manual testing

And potential issues two classes with the same JavaScriptInterface, I'd avoid this by renaming the "ankidroid" interface we add in DeckOptions

Really appreciate the effort which went into re-testing this, thanks!!


@Before
fun before() {
assumeFalse("Test flaky in CI - #9282, skipping", wasBuiltOnCI())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue is closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reopened it. There are still multiple disabled tests referring to this issue

}

@Test
fun testDeckOptionsWithChangeShowAlert() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test has no assertions, and is therefore difficult to understand the intention

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually there are assertions in openDeckOptions.
But the most important one is that the click can occurs, which means the buttons indeed exists. I don't know exactly how to state this with assertion


// Close without change
pressBack()
assertWebViewDoesNotExists()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you want to assert that either: the fragment/activity is no longer loaded, or the user has gone back to the previous screen.

The WebView not existing doesn't seem to be a good proxy for this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that at first. But somehow searching for the presence of a view whose id is R.layout.page_fragment does not work. It is never found. Instead, the log displaying the current view on the screen just shows me a WebView without PageFragment anywhere

* 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it should be in a utility package

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Actually it was done in the PR #17419 that I use in two PRs.

try {
check(viewAssertion)
return
} catch (e: Throwable) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: is this a bug. I would expect a ViewNotFound to be retried, but an assertion failure should exit the loop

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I suggest moving the discussion to #17419. As this is the commit that is common to two PRs where I need to do instrumented test.

This function is not changed at all. If it must be corrected, I think this is out of scope here.
What mattered to me is that I could use it without having to be in a subclass of InstrumentedTest

import org.junit.Rule
import org.junit.Test

class DeckOptionsTest : InstrumentedTest() {
Copy link
Member

@david-allison david-allison Nov 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️

These tests don't seem to handle either of the following cases. Did you manually test these:

  • User navigated to the Anki Manual via a link, and pressed 'back'
    • WebView should navigate back to options (changes are persisted), options should remain open
  • User opened up a modal on the svelte page and pressed 'back'
    • modal should close, options should remain open

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently html generated by svelte has no id. It's pretty hard to select something at least if I want to be sure that random change in svelte code won't break the test.
As far as I can tell, it's not even tested upstream.

I manually tested it. When the manual or a link from it is opened, and I press back, either on the screen or the phone button, the deck options remain open and the manual get closed.

I asked about test upstream. Maybe I'll have to ask permission to add id. Right now, I don't think writing those test is worth it.

I also remove `OnPageFinishedCallback` because I don't really see the
point in this list in Kotlin. I keep the interface as it's used in AbstractFlashcardViewer.
The names were far from clear
`bridgeCommand` is the general process by which Anki's webview send
command to the webview's owner. In Anki, it's interpreted by
Python. In AnkiDroid it must be interpreted by Kotlin.

Currently, the only `bridgeCommand` we listen to are in
CongratsPage. And I'm really thankful `@BrayanDSO` for creating this
first usage!

When anki 24.10 beta 2 is used in ankidroid, the DeckOptions will also
send `bridgeCommand`. And, I expect that when we'll use more webview,
more `bridgeCommand` will arrive.

So, I decided to generalize Brayan's code and ensure that there is a
simple map that any PageFragment can override that would allow to
declare its `bridgeCommand` without needing to add copy
`CongratsPage`'s code.

I tested this manually, and the CongratsPage's button still works.
This use a recent change introduced upstream.

Unit test can't run the webview. So it has to be replaced by
instrumented tests.

Test fails on CI while working locally, so I have to assume it's not
CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants