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

fix: keep panes settings after reload #2888

Merged
merged 8 commits into from
Nov 22, 2024

Conversation

luis-411
Copy link
Contributor

@luis-411 luis-411 commented Nov 3, 2024

This fixes the issue mentioned here: standardnotes/forum#2423

I used localStorage to save the changes made by toggeling the panes.
Also I edited the initialization of the panes array, because otherwise all three panes would show up after reload for a short time and then dissapear again depending on your settings.

Copy link
Member

@amanharwara amanharwara left a comment

Choose a reason for hiding this comment

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

Looks good for the most part. However, using local storage directly is problematic since there can be more than 1 account signed in and all of them might want to have different settings toggled.

Instead, the existing local preferences system (preferences.getLocalValue/preferences.setLocalValue) should be used.

@luis-411
Copy link
Contributor Author

Ok thank you, I see.
So I tried to implement it that way, but I think I'm missing something here.
I added ListPaneCollapsed to LocalPrefKey.ts and used it like this in PaneController.ts:

Initialize:
listPaneExplicitelyCollapsed = this.preferences.getLocalValue(LocalPrefKey.ListPaneCollapsed, false)

Toggle:
this.preferences.setLocalValue(LocalPrefKey.ListPaneCollapsed, true)

But somehow it always takes the default value provided in getLocalValue when refreshing the page.

@amanharwara
Copy link
Member

That's probably because the storage hasnt been decrypted yet. You'll want to handle the LocalPreferencesChanged event, you can look at how the ApplicationEvent.PreferencesChanged event is handled in the same file. Once you set it up that way, you can just call this.preferences.setLocalValue which will then automatically update the this.listPaneExplicitlyCollapsed properties of the class.

Copy link
Member

Choose a reason for hiding this comment

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

I think you've changed the incorrect file. .d.ts files aren't supposed to be modified directly. This whole file shouldn't be in git since it is generated from the original PrefDefaults.ts file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you, I get that, but in order to access the values in PrefDefaults.ts, I would have to add them to PrefKeys.ts and so what is the point of using LocalPrefKeys.ts? Should I just use PrefKeys.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or should I just use it like this, without the default stuff, since it is only a boolean value:
listPaneExplicitelyCollapsed = this.preferences.getLocalValue(LocalPrefKey.ListPaneCollapsed, false)

Copy link
Member

@amanharwara amanharwara Nov 12, 2024

Choose a reason for hiding this comment

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

Initially all the properties in LocalPrefKey were synced so they were in the PrefKey and so they still use PrefDefaults.

You can just create a LocalPrefDefaults similar to the PrefDefaults in the LocalPrefKey.ts file

Copy link
Member

Choose a reason for hiding this comment

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

We keep all the defaults in a constant so that there's a single source of truth in case those might need to be used somewhere else.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So do you mean in LocalPrefKey.ts add this:

export declare const LocalPrefDefaults: {
  listPaneCollapsed: false;
  navigationPaneCollapsed: false;
}

and use it like this:
listPaneExplicitelyCollapsed = this.preferences.getLocalValue(LocalPrefKey.ListPaneCollapsed, LocalPrefDefaults[LocalPrefKey.ListPaneCollapsed])

Copy link
Member

Choose a reason for hiding this comment

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

yes

@amanharwara
Copy link
Member

I tried this out locally and the setting does seem to get correctly persisted, but the actual pane removal logic doesn't seem to work on reload? If I turn off the items list, it doesn't stay turned off on reload but from logging I can see that the value has been stored correctly.

@luis-411
Copy link
Contributor Author

luis-411 commented Nov 13, 2024

Ok, I could reproduce it: I normally use Arc Browser (which is chromium based) and it works as expected. However if I try it in Chrome or Edge, I get the same behaviour as you described above.

@luis-411
Copy link
Contributor Author

I did a lot of testing and found out some inconsistencies:

First of all this is not browser related because I noticed the same behaviour for chrome and edge.
The difference is rather running the project on a "fresh" browser (e.g. using incognito tab) or on a browser where you used it before.

First weird behaviour:
After skipping the account creation, the GeneralAccountMenu pops up in the lower left corner. This window keeps appearing after every refresh even if I close it via the X or click somwhere else. Only writing something in a note or clicking on a button like on the Choose a note type button will permanently close the window and therefore turn a "fresh" browser into an "old" one.

Second weird behaviour:
The method setPaneLayout in PaneController.ts only gets called on "old" browsers but not on "fresh" ones.
This is problematic, because it turns out the Preference behaviour only gets applied in this method but not in the beginning of PaneController.ts where the default value of getLocalValue is always used.

So i guess if you type somthing into a note, you should be able to see the intended behaviour of my implementation. I am currently looking into why setLocalValue always takes the default value and what changes after writing something in a note or pressing another button. If you have any idea please let me know and thanks for the help so far. :)

@luis-411
Copy link
Contributor Author

After some more testing, I don't know how to resolve the problem with the account menu popup, but I found, that for example in line 96 of PaneController.ts the getValue function also returns the default value:
this.setCurrentNavPanelWidth(preferences.getValue(PrefKey.TagsPanelWidth, MinimumNavPanelWidth))
The correct value is set later on in the handleEvent function.

So this is not a problem of LocalPrefKeys but rather something general and from my experience it should work just fine on "normal" accounts.
@amanharwara it would be really interesting to know if you can reproduce this behaviour and how you think this should be handled.

@amanharwara
Copy link
Member

The theme-related settings which also use LocalPrefKeys work correctly on empty workspaces, so this not working there is a bug.

I think what you'll probably want to do is instead of running this initialization logic in the constructor, you'll want to run it the first time ApplicationEvent.LocalPreferencesChanged event is run.

@amanharwara
Copy link
Member

First weird behaviour:
After skipping the account creation, the GeneralAccountMenu pops up in the lower left corner. This window keeps appearing after every refresh even if I close it via the X or click somwhere else. Only writing something in a note or clicking on a button like on the Choose a note type button will permanently close the window and therefore turn a "fresh" browser into an "old" one.

Btw this is not a bug, it's intended behavior. If the workspace is fresh, we always show the account menu on load so that the user can quickly create an account or sign in.

@luis-411
Copy link
Contributor Author

The theme-related settings which also use LocalPrefKeys work correctly on empty workspaces, so this not working there is a bug.

I think what you'll probably want to do is instead of running this initialization logic in the constructor, you'll want to run it the first time ApplicationEvent.LocalPreferencesChanged event is run.

This seems to work, thank you. I will change it and push it in a minute.

LocalPrefKey.NavigationPaneCollapsed,
LocalPrefDefaults[LocalPrefKey.NavigationPaneCollapsed],
)
const screen = this._isTabletOrMobileScreen.execute().getValue()
Copy link
Member

Choose a reason for hiding this comment

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

this will now run after every setLocalValue call, no? i think it makes more sense to have a boolean in the class to make sure this only runs once since its supposed to be initialization logic.

@amanharwara
Copy link
Member

i was talking about the whole initialization logic, not the particular line 🙂 a boolean like hasPaneInitializationLogicRun = false in the class making sure the initialization logic only runs once.

@luis-411
Copy link
Contributor Author

Ah ok sorry, that makes sense.
So like this?:

if(!this.hasPaneInitializationLogicRun) {
        if (this.isTabletOrMobile) {
          this.panes = [AppPaneId.Navigation, AppPaneId.Items]
        } else {
          if (!this.listPaneExplicitelyCollapsed && !this.navigationPaneExplicitelyCollapsed) {
            this.panes = [AppPaneId.Navigation, AppPaneId.Items, AppPaneId.Editor]
          } else if (this.listPaneExplicitelyCollapsed && this.navigationPaneExplicitelyCollapsed) {
            this.panes = [AppPaneId.Editor]
          } else if (this.listPaneExplicitelyCollapsed) {
            this.panes = [AppPaneId.Navigation, AppPaneId.Editor]
          } else {
            this.panes = [AppPaneId.Items, AppPaneId.Editor]
          }
        }
        this.hasPaneInitializationLogicRun = true
      }

should i put the const screen ... back in then or leave this extra?

@amanharwara
Copy link
Member

So like this?

yes

should i put the const screen ... back in then or leave this extra?

yes. technically the value of isTabletOrMobile should be latest, even though in this particular case the value probably wouldn't change between the construction of the class and the event. however it makes sense to always be correct.

Copy link
Member

@amanharwara amanharwara left a comment

Choose a reason for hiding this comment

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

Looks good to go now, thanks for the PR!

@amanharwara amanharwara merged commit f179631 into standardnotes:main Nov 22, 2024
5 of 7 checks passed
@luis-411 luis-411 deleted the fix-panes-after-reload branch November 22, 2024 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants