revanced-manager icon indicating copy to clipboard operation
revanced-manager copied to clipboard

fix: Update dialog shows dev version & loading gets stuck in certain circumstances

Open kitadai31 opened this issue 10 months ago • 5 comments

This PR fix these ~~two~~ three issues related to the Manager update dialog.

Issue 1

Dev version is shown in the "Show update" or "Show changelog" dialog when the current latest version is dev.

completes #1774

Cause

add49e1 only checks the past releases, so the latest dev version is still shown

Solution

Make GitHubAPI.getLatestManagerVersion() find the latest non-dev release and return it.

Issue 2

If the Manager version is too old (more than 30 releases), the update dialog gets stuck loading.

Cause

The api (https://api.github.com/repos/ReVanced/revanced-manager/releases) returns only recent 30 releases. However, the current implementation doesn't consider it. If the api response doesn't include the current Manager version, a while statement in GitHubAPI.getLatestManagerVersion() ( that searches current version) accesses out of range index and causes error.

Solution

Check the list range

As of today, this issue affects all versions prior to 1.18.0. ~~Discord supporters should know this issue 😕~~

Issue 3 (Added 2024/03/31)

In changelogs, version name line is duplicated

Cause

d414a91f40bb4bce6c37944f63635348d1f05aaa changed changelog format to contain version name

Solution

Not to append version name when output changelogs

kitadai31 avatar Mar 27 '24 07:03 kitadai31

I think this PR needs a review by @TheAabedKhan. Would you review please?

kitadai31 avatar Mar 27 '24 07:03 kitadai31

Thank you. I checked that it fixes the issues.

However, ?per_page=100 caused bad performance when the changelogs are long. (even on release build, Snapdragon 845 phone) It took 1.5 seconds to open the changelog and scroll is very laggy. Therefore, I think it would be reasonable to limit it to default 30 releases.

Also, I want to a question. I'm interested in this.

  1. Linear iteration
  2. Early termination
  3. Reduced loop iterations

I think this code will also work:

int updates = 0;
while (releases[updates]['tag_name'] != currentVersion) {
  updates++;
  if (updates == releases.length) {
    break;
  }
  releases[0].update(
    'body',
    (value) =>
        value +
        '\n' +
        '# ' +
        releases[updates]['tag_name'] +
        '\n' +
        releases[updates]['body'],
  );
}

Is it really more efficient to first count the number with a while loop and then do a for loop rather than processing it in one iteration? (Sorry for the off-topic general computer science question.)

kitadai31 avatar Mar 27 '24 16:03 kitadai31

It took 1.5 seconds to open the changelog and scroll is very laggy.

Couldn't feel any difference on my device. However, you can try reducing the number until you are satisfied with the performance or remove the parameter if you like.

Is it really more efficient to first count the number with a while loop and then do a for loop rather than processing it in one iteration?

You're correct that in terms of pure iteration, it would be more efficient to process everything in one iteration rather than counting first and then iterating again. Also, while we are on it, how about accumulating release notes separately before updating the body of the first release? This will reduce the number of update operations on the body of the first release.

final StringBuffer releaseNotes = StringBuffer();
while (releases[updates]['tag_name'] != currentVersion) {
  updates++;
  if (updates == releases.length) {
    break;
  }
  releaseNotes.writeln('# ${releases[updates]['tag_name']}');
  releaseNotes.writeln(releases[updates]['body']);
}
releases[0].update(
  'body',
  (value) => value + '\n' + releaseNotes.toString(),
);
return releases[0];

TheAabedKhan avatar Mar 27 '24 17:03 TheAabedKhan

It's more readable than two loops! Thank you for the advice.

I just came up with an idea.

version

This version string in UpdateConfirmationSheet can be obtained from a field HomeViewModel.latestManagerVersion instead of GitHubAPI.getLatestManagerReleases(). This value is more accurate than get from https://api.github.com/repos/ReVanced/revanced-manager/releases?per_page=XXX, because the possibility exists that all releases from this API are pre-release. (lack of my test cases before making a PR)

Then, the method Future<Map<String, dynamic>?> getLatestManagerRelease(String repoName) don't have to provide the latest version string, so it can be more simple and less-responsibility method like Future<String?> getManagerChangelogs() I will do this tomorrow.

kitadai31 avatar Mar 27 '24 18:03 kitadai31

Changes

update_confirmation_sheet.dart:

  • Change version string reference from snapshot.data!['tag_name'] to model.latestPatchesVersion
  • Use FutureBuilder only for the changelog part
    • This allows users to update manager even when failed to connect GitHub API

home_viewmodel.dart:

  • Make String? _latestManagerVersion and String? _latestPatchesVersion instance variables public in order to be used in update_confirmation_sheet
  • Remove initializing with empty strings because I want to guarantee that the variable holds the latest version string
  • Change methods which used in update_confirmation_sheet

github_api.dart:

  • Future<Map<String, dynamic>?> getLatestManagerRelease(String repoName) now returns the changelogs only and renamed to Future<String?> getManagerChangelogs()
  • Set to ?per_page=50
  • Don't append the version name header while generating changelogs (Refer to the added issue 3)

kitadai31 avatar Mar 31 '24 14:03 kitadai31