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

UpgradeCard disappears / never appears if upgrader is changed #424

Open
qwertie opened this issue Jul 9, 2024 · 2 comments
Open

UpgradeCard disappears / never appears if upgrader is changed #424

qwertie opened this issue Jul 9, 2024 · 2 comments
Labels
bug Something isn't working need more information Further information is requested UpgradeCard

Comments

@qwertie
Copy link

qwertie commented Jul 9, 2024

My app uses UpgradeCard to show when there is an upgrade available, but the message I want to show depends on whether the upgrade is mandatory. And whether the upgrade is mandatory depends on async queries to PackageInfo.fromPlatform() and to the backend server. Due to the async requests, there is a race condition between showing the UpgradeCard and choosing the correct message to show.

To deal with this, I decided to force the UpgradeCard to re-render when the message has potentially changed. Apparently this is not actually necessary, as re-rendering the parent component causes the UpgradeCard to re-render and pick up the new message even when none of its properties have changed.

Still, it was confusing that changing the upgrader parameter makes the UpgradeCard disappear (or, in case of two renders in quick succession, prevents it from showing up in the first place) given my code which looked something like this:

class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override State<StatefulWidget> createState() => MainScreenState();
}

class MainScreenState extends State<MainScreen> {
  MainScreenState() {
    PackageInfo.fromPlatform().then((packageInfo) {
      setState(() {
        _upgraderMessages.currentAppVersion = Version.parse(packageInfo.version);
      });
    });
  }

  final UpgraderMessagePicker _upgraderMessages = UpgraderMessagePicker();
  Upgrader? _upgrader;
  String? _upgraderMessageBody;

  @override
  Widget build(BuildContext context) {
    // Pick upgrader message, in case an upgrade is available
    _upgraderMessages.state = Provider.of<_____>(context, listen: true).state;
    if (_upgraderMessageBody != _upgraderMessages.body) {
      _upgraderMessageBody = _upgraderMessages.body;
      _upgrader = Upgrader(messages: _upgraderMessages, debugLogging: true);
    }

    return Scaffold(
        appBar: AppBar(title: const Text("My App")),
        body: ListView(children: [
              UpgradeCard(showIgnore: false, upgrader: _upgrader),
              const OtherStuff(),
            ])
      );
  }
}


class UpgraderMessagePicker extends UpgraderMessages with ChangeNotifier {
  Version currentAppVersion = Version(999, 0, 0);
   ...
}

I believe this happens because UpgradeCardState.initState calls Upgrader.initialize(). If UpgradeCardState.build were to call Upgrader.initialize() instead, the card would not disappear.

I was able to work around the problem by adding _upgrader!.initialize() and the end of the if (_upgraderMessageBody != _upgraderMessages.body) block. Unfortunately this has the side effect of causing a second upgrade check to happen, so in the end I figured out that I should actually send the same instance of Upgrader every time.

Other issues I noticed

  • The default upgrade message says "Version {{currentAppStoreVersion}} is now available-you have {{currentInstalledVersion}}." This is not correct English orthography. It would be better to use em dash "―" or semicolon "; " rather than a short dash "-".
  • UpgraderPlayStore throws three exceptions every time it checks for an update (one when calling additionalInfoElements.firstWhere on an empty list, and two more when calling sectionElements[0] on an empty list), which is very disruptive to the developer debugging experience.
  • The upgrade API request re-runs every time the screen is turned on, even if the UpgradeCard is invisible (whether because the user is on a different screen, or because the user asked to Ignore the update, or because of the UpgradeCard version of bug Do not pop the dialog when 'Update' is clicked. #416). I don't like this because some users have limited mobile data, and debugger keeps stopping on the exceptions too.
  • If the user clicks "Update" but doesn't actually update the app, the UpgradeCard disappears even if !showIgnore and !showLater. I tried to work around this with Upgrader.clearSavedSettings().then((_) => setState(() {})), but it didn't help.
@larryaasen larryaasen added bug Something isn't working UpgradeCard labels Sep 22, 2024
@larryaasen
Copy link
Owner

@qwertie If you want to re-render when the message changes, could you just update the upgrader state like this:

_upgrader.updateState(_upgrader.state.copyWith(messages: _upgraderMessages));

and then just keep one instance up Upgrader in variable _upgrader?

Also, when you see the exceptions, could you share the upgrader log for that so we can review them?

@larryaasen
Copy link
Owner

@qwertie I have attempted to reproduce the "disappear" issue and have not succeeded. I did create a new example to demonstrate the update of messages on a card. See this file: https://github.com/larryaasen/upgrader/blob/master/example/lib/main_card_updated.dart
Please run that example code and see if it updates messages properly without issues.

@larryaasen larryaasen added the need more information Further information is requested label Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working need more information Further information is requested UpgradeCard
Projects
None yet
Development

No branches or pull requests

2 participants