From fc39a07810e15f4f9366a8ddeb52d86a8d752741 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Sat, 9 May 2026 17:55:10 +1000 Subject: [PATCH 1/2] Check updates and notify users --- README.md | 41 +++++++ example/lib/main.dart | 47 +++++++- lib/src/widgets/version_widget.dart | 165 ++++++++++++++++++++++++++-- 3 files changed, 242 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index eb95884..022a206 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ access. - Visual indicator for outdated version - Network connectivity handling - Formatted date display (DD MMM YYYY) +- Optional inline discover-and-download button when a newer release is detected ## Installation @@ -75,6 +76,34 @@ VersionWidget( ) ``` +With the discover-and-download button enabled. When the widget detects +a newer release in the CHANGELOG it renders a small button to the +right of the version label. Tapping the button opens +`downloadUrl` in the default external handler (typically the system +browser or platform installer). + +```dart +VersionWidget( + version: '1.0.5', + changelogUrl: 'https://github.com/anusii/version_widget/raw/main/CHANGELOG.md', + showUpdateButton: true, + downloadUrl: 'https://example.com/downloads/myapp-latest.exe', +) +``` + +Hide the version number text but keep the update button visible +(useful when only the upgrade affordance is desired): + +```dart +VersionWidget( + version: '1.0.5', + changelogUrl: 'https://github.com/anusii/version_widget/raw/main/CHANGELOG.md', + showVersion: false, + showUpdateButton: true, + downloadUrl: 'https://example.com/downloads/myapp-latest.exe', +) +``` + ## Version Status Indicators - Grey text: Version is being checked @@ -103,11 +132,23 @@ changelog. - `version` (required): The version string to display. Must be provided. - `changelogUrl` (optional): URL to the CHANGELOG.md file +- `showVersion` (optional): Whether to show the version number text + (defaults to true). When false the text is hidden but the changelog + is still consulted so the optional update button can still appear. - `showDate` (optional): Whether to show the release date (defaults to true) - `defaultDate` (optional): Default date to show if changelog cannot be fetched (format: YYYYMMDD) - `isLatestTooltip` (optional): Custom message to show when version is latest - `notLatestTooltip` (optional): Custom message to show when newer version is available +- `showUpdateButton` (optional): Whether to show the discover-and-download + button when a newer version is detected (defaults to false). The + button is only rendered when this flag is enabled, a newer version + is found and `downloadUrl` is provided. +- `downloadUrl` (optional): URL launched when the update button is + tapped. Typically points at an installer (.exe, .apk, .dmg) or a + release page. Required for the update button to be rendered. +- `updateButtonLabel` (optional): Text label shown next to the icon on + the update button (defaults to `Update`). ## Contributing diff --git a/example/lib/main.dart b/example/lib/main.dart index 4e128a2..11c6d55 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -111,9 +111,11 @@ class MyHomePage extends StatelessWidget { 'github.com/anusii/version_widget.git\n' 'Specify an old version.\n' 'The date is from the CHANGELOG.\n' - 'Expect red version and correct date.\n' + 'Expect red version, correct date and an\n' + 'inline Update button to the right.\n' 'Font size is 18.0\n' - 'Tap the string to see the CHANGELOG.', + 'Tap the string to see the CHANGELOG.\n' + 'Tap the Update button to launch the download URL.', ), SizedBox(height: 8), VersionWidget( @@ -121,6 +123,9 @@ class MyHomePage extends StatelessWidget { changelogUrl: 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', fontSize: 18.0, + showUpdateButton: true, + downloadUrl: + 'https://github.com/anusii/version_widget/releases/latest', ), ], ), @@ -140,7 +145,8 @@ class MyHomePage extends StatelessWidget { 'github.com/gjwgit/rattle\n' 'Specifying an old version.\n' 'The date here is from the CHANGELOG.\n' - 'Expect bold red version and correct date.\n' + 'Update button is visible with a custom label\n' + 'and a Rattle download URL.\n' 'Font size is 14.0\n' 'Tap the string to see the CHANGELOG.', ), @@ -151,6 +157,10 @@ class MyHomePage extends StatelessWidget { 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', showDate: true, fontSize: 14.0, + showUpdateButton: true, + downloadUrl: + 'https://github.com/gjwgit/rattle/releases/latest', + updateButtonLabel: 'Get latest', ), ], ), @@ -244,6 +254,37 @@ class MyHomePage extends StatelessWidget { ), ), ), + + // Demonstrates hiding the version label entirely while still + // surfacing the discover-and-download button when an outdated + // version is detected. Only the Update button should appear. + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/anusii/version_widget.git\n' + 'showVersion=false, showUpdateButton=true.\n' + 'Version label is hidden but the Update\n' + 'button is still rendered when a newer\n' + 'release is detected in the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '1.0.0', + changelogUrl: + 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', + showVersion: false, + showUpdateButton: true, + downloadUrl: + 'https://github.com/anusii/version_widget/releases/latest', + ), + ], + ), + ), + ), ], ), ], diff --git a/lib/src/widgets/version_widget.dart b/lib/src/widgets/version_widget.dart index 094132c..3176d4c 100644 --- a/lib/src/widgets/version_widget.dart +++ b/lib/src/widgets/version_widget.dart @@ -1,8 +1,8 @@ /// Version widget for the app. /// -// Time-stamp: +// Time-stamp: /// -/// Copyright (C) 2024-2025, Software Innovation Institute, ANU. +/// Copyright (C) 2024-2026, Software Innovation Institute, ANU. /// /// Licensed under the MIT License (the "License"). /// @@ -24,7 +24,7 @@ // You should have received a copy of the GNU General Public License along with // this program. If not, see . /// -/// Authors: Kevin Wang. +/// Authors: Kevin Wang, Tony Chen. import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; @@ -50,17 +50,25 @@ import 'package:version_widget/src/utils/compare_versions.dart'; /// /// Styling of the version string is offered in two modes: /// -/// 1. Automatic mode: version styled with colour denoting package statu -/// (blue: up to date, red: newer version availbale, grey: version +/// 1. Automatic mode: version styled with colour denoting package status +/// (blue: up to date, red: newer version available, grey: version /// being checked). /// 2. Manual mode: user specified TextStyle(). /// +/// When a newer version is detected and [showUpdateButton] is enabled, an +/// inline action button is rendered to the right of the version text. Tapping +/// the button launches [downloadUrl] in the default external handler so the +/// user can fetch the latest installer or release page. +/// /// Example usage: /// ```dart /// VersionWidget( +/// version: '1.0.5', /// changelogUrl: 'https://github.com/anusii/version_widget/raw/main/CHANGELOG.md', /// showDate: true, /// defaultDate: '20240101', +/// showUpdateButton: true, +/// downloadUrl: 'https://example.com/downloads/myapp-latest.exe', /// ) /// ``` class VersionWidget extends StatefulWidget { @@ -75,6 +83,14 @@ class VersionWidget extends StatefulWidget { final String? changelogUrl; + /// Whether to show the version number text. + /// Defaults to true. + /// When false, the version text is hidden but version checking still occurs + /// so that the optional update button can still appear when a newer version + /// is detected. + + final bool showVersion; + /// Whether to show the release date alongside the version. /// Defaults to true. /// When false, only the version number will be displayed. @@ -106,6 +122,30 @@ class VersionWidget extends StatefulWidget { final TextStyle? userTextStyle; + /// Whether to show the discover-and-download button when a newer version is + /// detected. + /// Defaults to false (hidden). + /// The button is only rendered when all of the following are true: + /// 1. [showUpdateButton] is true + /// 2. A newer version has been detected from the CHANGELOG + /// 3. [downloadUrl] is non-null and non-empty + /// Tapping the button launches [downloadUrl] using the platform's default + /// external handler (typically the system browser) so the user can fetch + /// the latest release. + + final bool showUpdateButton; + + /// The URL to launch when the user taps the discover-and-download button. + /// Typically points at an installer (.exe, .apk, .dmg) or a release page. + /// Required for the update button to be rendered. + + final String? downloadUrl; + + /// Optional label shown next to the download icon on the update button. + /// Defaults to 'Update' when null. + + final String? updateButtonLabel; + /// Creates a new [VersionWidget]. /// The [version] parameter is required and should be the current version of the app. /// All other parameters are optional. @@ -114,12 +154,16 @@ class VersionWidget extends StatefulWidget { super.key, required this.version, this.changelogUrl, + this.showVersion = true, this.showDate = true, this.defaultDate = '20260101', this.isLatestTooltip, this.notLatestTooltip, this.fontSize = 16.0, this.userTextStyle, + this.showUpdateButton = false, + this.downloadUrl, + this.updateButtonLabel, }); @override @@ -135,7 +179,7 @@ class VersionWidget extends StatefulWidget { class _VersionWidgetState extends State { /// Indicates whether the current version is the latest version. - /// Used to determine the color of the version text (blue for latest, red for outdated). + /// Used to determine the colour of the version text (blue for latest, red for outdated). bool _isLatest = true; @@ -165,7 +209,12 @@ class _VersionWidgetState extends State { void initState() { super.initState(); _currentVersion = widget.version; - if (widget.showDate) { + + // We still want to check the changelog whenever the changelog URL is + // provided so that the update button can be surfaced even when the + // version date is intentionally hidden by the host app. + + if (widget.showDate || widget.changelogUrl != null) { _fetchChangelog(); } else { _isChecking = false; @@ -446,6 +495,88 @@ class _VersionWidgetState extends State { } } + /// Launches the configured [VersionWidget.downloadUrl] in the default + /// external handler so the user can fetch the new release. + + Future _launchDownload() async { + final downloadUrl = widget.downloadUrl; + if (downloadUrl == null || downloadUrl.isEmpty) return; + + final uri = Uri.parse(downloadUrl); + if (await canLaunchUrl(uri)) { + await launchUrl(uri, mode: LaunchMode.externalApplication); + } else { + debugPrint('Unable to launch download URL: $downloadUrl'); + } + } + + /// Builds the inline discover-and-download action button surfaced when a + /// newer release is detected. Returns null when the button should not be + /// rendered for the current state. + + Widget? _buildUpdateButton(BuildContext context) { + final downloadUrl = widget.downloadUrl; + if (!widget.showUpdateButton) return null; + if (_isChecking) return null; + if (_isLatest) return null; + if (downloadUrl == null || downloadUrl.isEmpty) return null; + + final label = widget.updateButtonLabel ?? 'Update'; + final tooltipMessage = ''' + + **New version $_latestVersion available** + + Tap to download and install the latest release. The download URL + will open in the default external handler (typically your system + browser or the relevant platform installer). + + '''; + + return Padding( + padding: const EdgeInsets.only(left: 8.0), + child: MarkdownTooltip( + message: tooltipMessage, + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: _launchDownload, + borderRadius: BorderRadius.circular(16), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 4.0, + ), + decoration: BoxDecoration( + color: Colors.red.withValues(alpha: 0.12), + border: Border.all(color: Colors.red, width: 1), + borderRadius: BorderRadius.circular(16), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.system_update_alt, + size: 16, + color: Colors.red, + ), + const SizedBox(width: 4), + Text( + label, + style: const TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ], + ), + ), + ), + ), + ), + ); + } + @override Widget build(BuildContext context) { final displayText = _isChecking @@ -470,7 +601,7 @@ class _VersionWidgetState extends State { '''; - return GestureDetector( + final versionLabel = GestureDetector( onTap: widget.changelogUrl == null ? null : () => _showChangelogDialog(context), @@ -497,5 +628,23 @@ class _VersionWidgetState extends State { ), ), ); + + final updateButton = _buildUpdateButton(context); + + // Short-circuit when neither the version label nor the update button is + // visible to keep the widget completely transparent in the host layout. + + if (!widget.showVersion && updateButton == null) { + return const SizedBox.shrink(); + } + + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (widget.showVersion) versionLabel, + if (updateButton != null) updateButton, + ], + ); } } From c6ef0c7cf649fe2a57e14c776c8dc25f75536f3a Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Sat, 9 May 2026 18:32:10 +1000 Subject: [PATCH 2/2] Fix the overflow issue --- example/lib/main.dart | 416 ++++++++++++++-------------- lib/src/widgets/version_widget.dart | 26 +- 2 files changed, 234 insertions(+), 208 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 11c6d55..3402b0d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,8 +1,8 @@ /// A demonstration of the VersionWidget app. /// -// Time-stamp: +// Time-stamp: /// -/// Copyright (C) 2025, Software Innovation Institute ANU +/// Copyright (C) 2025-2026, Software Innovation Institute ANU /// /// Licensed under the MIT License (the "License"). /// @@ -26,7 +26,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. /// -/// Authors: Kevin Wang, Graham Williams +/// Authors: Kevin Wang, Graham Williams, Tony Chen // Add the library directive as we have doc entries above. We publish the above // meta doc lines in the docs. @@ -64,230 +64,244 @@ class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { - // - return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(title), ), - body: const Row( - children: [ - Column( - children: [ - // Example 1: Up-to-date version (blue) - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/anusii/version_widget.git\n' - 'Specify the current version.\n' - 'The date is from the CHANGELOG.\n' - 'Expect blue version and correct date.\n' - 'Font size is default\n' - 'Tap the string to see the CHANGELOG.', - ), - SizedBox(height: 8), - VersionWidget( - version: '1.0.5', - changelogUrl: - 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', + body: const SingleChildScrollView( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + children: [ + // Example 1: Up-to-date version (blue). + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/anusii/version_widget.git\n' + 'Specify the current version.\n' + 'The date is from the CHANGELOG.\n' + 'Expect blue version and correct date.\n' + 'Font size is default\n' + 'Tap the string to see the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '1.0.5', + changelogUrl: + 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', + ), + ], ), - ], + ), ), - ), - ), - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/anusii/version_widget.git\n' - 'Specify an old version.\n' - 'The date is from the CHANGELOG.\n' - 'Expect red version, correct date and an\n' - 'inline Update button to the right.\n' - 'Font size is 18.0\n' - 'Tap the string to see the CHANGELOG.\n' - 'Tap the Update button to launch the download URL.', + // Example 2: Outdated version with the discover-and-download + // button enabled. The default Update label is used so all + // demo buttons read the same. + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/anusii/version_widget.git\n' + 'Specify an old version.\n' + 'The date is from the CHANGELOG.\n' + 'Expect red version, correct date and an\n' + 'inline Update button to the right.\n' + 'Font size is 18.0\n' + 'Tap the string to see the CHANGELOG.\n' + 'Tap the Update button to launch the URL.', + ), + SizedBox(height: 8), + VersionWidget( + version: '1.0.2', + changelogUrl: + 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', + fontSize: 18.0, + showUpdateButton: true, + downloadUrl: + 'https://github.com/anusii/version_widget/releases/latest', + ), + ], ), - SizedBox(height: 8), - VersionWidget( - version: '1.0.2', - changelogUrl: - 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', - fontSize: 18.0, - showUpdateButton: true, - downloadUrl: - 'https://github.com/anusii/version_widget/releases/latest', - ), - ], + ), ), - ), + ], ), - ], - ), - Column( - children: [ - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/gjwgit/rattle\n' - 'Specifying an old version.\n' - 'The date here is from the CHANGELOG.\n' - 'Update button is visible with a custom label\n' - 'and a Rattle download URL.\n' - 'Font size is 14.0\n' - 'Tap the string to see the CHANGELOG.', - ), - SizedBox(height: 8), - VersionWidget( - version: '6.5.15', - changelogUrl: - 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', - showDate: true, - fontSize: 14.0, - showUpdateButton: true, - downloadUrl: - 'https://github.com/gjwgit/rattle/releases/latest', - updateButtonLabel: 'Get latest', + ), + Expanded( + child: Column( + children: [ + // Example 3: Outdated Rattle version with the + // discover-and-download button enabled. Uses the default + // Update label for consistency with Example 2. + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/gjwgit/rattle\n' + 'Specifying an old version.\n' + 'The date here is from the CHANGELOG.\n' + 'Expect bold red version, correct date and\n' + 'the Update button targeting the Rattle\n' + 'releases page.\n' + 'Font size is 14.0\n' + 'Tap the string to see the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '6.5.15', + changelogUrl: + 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', + showDate: true, + fontSize: 14.0, + showUpdateButton: true, + downloadUrl: + 'https://github.com/gjwgit/rattle/releases/latest', + ), + ], ), - ], + ), ), - ), - ), - // An out of date version number is tested with no date but with a - // username in the CHANGELOG. - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/gjwgit/rattle\n' - 'Old version in CHANGELOG without date.\n' - 'We should thus not see a date here.\n' - 'Expect bold red version and no date.\n' - 'Font size is 12.0\n' - 'Tap the string to see the CHANGELOG.', + // Example 4: An out of date version number is tested with + // no date but with a username in the CHANGELOG. + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/gjwgit/rattle\n' + 'Old version in CHANGELOG without date.\n' + 'We should thus not see a date here.\n' + 'Expect bold red version and no date.\n' + 'Font size is 12.0\n' + 'Tap the string to see the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '6.1.14', + changelogUrl: + 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', + showDate: true, + fontSize: 12.0, + ), + ], ), - SizedBox(height: 8), - VersionWidget( - version: '6.1.14', - changelogUrl: - 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', - showDate: true, - fontSize: 12.0, - ), - ], + ), ), - ), + ], ), - ], - ), - Column( - children: [ - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/gjwgit/rattle\n' - 'Future version not in the CHANGELOG.\n' - 'We should thus not see a date here.\n' - 'Expect blue version and no date.\n' - 'Font size is 10.0\n' - 'Tap the string to see the CHANGELOG.', - ), - SizedBox(height: 8), - VersionWidget( - version: '7.0.0', - changelogUrl: - 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', - showDate: true, - fontSize: 10.0, + ), + Expanded( + child: Column( + children: [ + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/gjwgit/rattle\n' + 'Future version not in the CHANGELOG.\n' + 'We should thus not see a date here.\n' + 'Expect blue version and no date.\n' + 'Font size is 10.0\n' + 'Tap the string to see the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '7.0.0', + changelogUrl: + 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', + showDate: true, + fontSize: 10.0, + ), + ], ), - ], + ), ), - ), - ), - // An out of date version number is tested with no date but with a - // username in the CHANGELOG. - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/gjwgit/rattle\n' - 'Old version not in the CHANGELOG.\n' - 'We should thus not see a date here.\n' - 'Expect bold red version and no date.\n' - 'Font size is 8.0\n' - 'Tap the string to see the CHANGELOG.', + // Example 5: An out of date version number is tested with + // no date but with a username in the CHANGELOG. + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/gjwgit/rattle\n' + 'Old version not in the CHANGELOG.\n' + 'We should thus not see a date here.\n' + 'Expect bold red version and no date.\n' + 'Font size is 8.0\n' + 'Tap the string to see the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '5.0.0', + changelogUrl: + 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', + showDate: true, + fontSize: 8.0, + ), + ], ), - SizedBox(height: 8), - VersionWidget( - version: '5.0.0', - changelogUrl: - 'https://raw.githubusercontent.com/gjwgit/rattle/refs/heads/dev/CHANGELOG.md', - showDate: true, - fontSize: 8.0, - ), - ], + ), ), - ), - ), - // Demonstrates hiding the version label entirely while still - // surfacing the discover-and-download button when an outdated - // version is detected. Only the Update button should appear. - Card( - margin: EdgeInsets.all(8), - child: Padding( - padding: EdgeInsets.all(16), - child: Column( - children: [ - Text( - 'github.com/anusii/version_widget.git\n' - 'showVersion=false, showUpdateButton=true.\n' - 'Version label is hidden but the Update\n' - 'button is still rendered when a newer\n' - 'release is detected in the CHANGELOG.', - ), - SizedBox(height: 8), - VersionWidget( - version: '1.0.0', - changelogUrl: - 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', - showVersion: false, - showUpdateButton: true, - downloadUrl: - 'https://github.com/anusii/version_widget/releases/latest', + // Example 6: Demonstrates hiding the version label entirely + // while still surfacing the discover-and-download button + // when an outdated version is detected. Only the Update + // button should appear. + Card( + margin: EdgeInsets.all(8), + child: Padding( + padding: EdgeInsets.all(16), + child: Column( + children: [ + Text( + 'github.com/anusii/version_widget.git\n' + 'showVersion=false, showUpdateButton=true.\n' + 'Version label is hidden but the Update\n' + 'button is still rendered when a newer\n' + 'release is detected in the CHANGELOG.', + ), + SizedBox(height: 8), + VersionWidget( + version: '1.0.0', + changelogUrl: + 'https://raw.githubusercontent.com/anusii/version_widget/refs/heads/main/CHANGELOG.md', + showVersion: false, + showUpdateButton: true, + downloadUrl: + 'https://github.com/anusii/version_widget/releases/latest', + ), + ], ), - ], + ), ), - ), + ], ), - ], - ), - ], + ), + ], + ), ), ); } diff --git a/lib/src/widgets/version_widget.dart b/lib/src/widgets/version_widget.dart index 3176d4c..f8caeeb 100644 --- a/lib/src/widgets/version_widget.dart +++ b/lib/src/widgets/version_widget.dart @@ -638,13 +638,25 @@ class _VersionWidgetState extends State { return const SizedBox.shrink(); } - return Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (widget.showVersion) versionLabel, - if (updateButton != null) updateButton, - ], + return LayoutBuilder( + builder: (context, constraints) { + final hasFiniteWidth = constraints.maxWidth.isFinite; + final boundedVersionLabel = hasFiniteWidth + ? ConstrainedBox( + constraints: BoxConstraints(maxWidth: constraints.maxWidth), + child: versionLabel, + ) + : versionLabel; + + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + runSpacing: 4, + children: [ + if (widget.showVersion) boundedVersionLabel, + if (updateButton != null) updateButton, + ], + ); + }, ); } }