From 5f418cbf64a479b6795e4506c9716812a23f7962 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Mon, 8 Aug 2022 19:43:15 -0700 Subject: [PATCH 01/13] feat: Add about window demo --- example/lib/home_page.dart | 5 ++++ example/lib/pages/about_dialog_page.dart | 30 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 example/lib/pages/about_dialog_page.dart diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index e1e5344..fe4a807 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -1,3 +1,4 @@ +import 'package:example/pages/about_dialog_page.dart'; import 'package:example/pages/avatar_page.dart'; import 'package:example/pages/counter_page.dart'; import 'package:example/pages/flap_page.dart'; @@ -182,6 +183,9 @@ class _MyHomePageState extends State { ), AdwSidebarItem( label: 'Style Classes', + ), + AdwSidebarItem( + label: 'About Window', ) ], onSelected: (index) => setState(() => _currentIndex = index), @@ -198,6 +202,7 @@ class _MyHomePageState extends State { const ViewSwitcherPage(), const SettingsPage(), const StyleClassesPage(), + const AboutDialogPage(), ], ), ); diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart new file mode 100644 index 0000000..123bf98 --- /dev/null +++ b/example/lib/pages/about_dialog_page.dart @@ -0,0 +1,30 @@ +import 'package:example/pages/run_demo_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:libadwaita/libadwaita.dart'; + +class AboutDialogPage extends StatelessWidget { + const AboutDialogPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return DemoScreen( + image: const Icon( + Icons.view_sidebar_rounded, + size: 130, + ), + title: 'About Dialog', + description: 'Something something', + footer: AdwButton.pill( + child: const Text('Run the demo'), + onPressed: () { + showDialog( + context: context, + builder: (context) => const AdwAboutWindow( + appIcon: Icon(Icons.mp), + ), + ); + }, + ), + ); + } +} From 309d9924380c18bd927f76c6e3d65de3d47e20ff Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Mon, 8 Aug 2022 20:21:50 -0700 Subject: [PATCH 02/13] feat(dialog): Make dialog take a child More flexibility --- lib/src/widgets/gtk/dialog.dart | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/src/widgets/gtk/dialog.dart b/lib/src/widgets/gtk/dialog.dart index 6835bd5..948ecbc 100644 --- a/lib/src/widgets/gtk/dialog.dart +++ b/lib/src/widgets/gtk/dialog.dart @@ -15,7 +15,7 @@ class GtkDialog extends StatelessWidget { this.constraints, this.height, this.width, - required this.children, + required this.child, }) : super(key: key); final HeaderBarStyle? headerBarStyle; @@ -28,7 +28,7 @@ class GtkDialog extends StatelessWidget { final AdwControls? controls; final EdgeInsets? padding; - final List children; + final Widget child; final BoxConstraints? constraints; final double? height; @@ -65,13 +65,7 @@ class GtkDialog extends StatelessWidget { ), ), Flexible( - child: SingleChildScrollView( - padding: padding, - child: Column( - mainAxisSize: MainAxisSize.min, - children: children, - ), - ), + child: child, ), ], ), From 431e55817d82061ab49b4284d902be7d2364e87d Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Mon, 8 Aug 2022 23:59:08 -0700 Subject: [PATCH 03/13] feat(action_row): Allow changing title text style --- lib/src/widgets/adw/action_row.dart | 9 ++++++++- lib/src/widgets/gtk/dialog.dart | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/widgets/adw/action_row.dart b/lib/src/widgets/adw/action_row.dart index 73312a2..be1f32f 100644 --- a/lib/src/widgets/adw/action_row.dart +++ b/lib/src/widgets/adw/action_row.dart @@ -6,6 +6,7 @@ class AdwActionRow extends StatelessWidget { this.start, this.end, required this.title, + this.titleStyle, this.onActivated, this.subtitle, this.horizontalTitleGap = 8, @@ -23,6 +24,9 @@ class AdwActionRow extends StatelessWidget { /// The title of this row final String title; + /// The [TextStyle] of the title + final TextStyle? titleStyle; + /// The subtitle of this row final String? subtitle; @@ -53,7 +57,10 @@ class AdwActionRow extends StatelessWidget { ? SizedBox(height: double.infinity, child: start) : null, onTap: onActivated, - title: Text(title), + title: Text( + title, + style: titleStyle, + ), subtitle: subtitle != null && subtitle!.isNotEmpty ? Text(subtitle!) : null, trailing: end, diff --git a/lib/src/widgets/gtk/dialog.dart b/lib/src/widgets/gtk/dialog.dart index 948ecbc..32e371d 100644 --- a/lib/src/widgets/gtk/dialog.dart +++ b/lib/src/widgets/gtk/dialog.dart @@ -65,7 +65,7 @@ class GtkDialog extends StatelessWidget { ), ), Flexible( - child: child, + child: child, ), ], ), From 8b2c57b5e73a884af1836c62ccdcbfc57dd823c3 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Tue, 9 Aug 2022 15:19:32 -0700 Subject: [PATCH 04/13] feat: Initial about dialog/window rework * Values are hardcoded for now, but will add customization later --- example/lib/home_page.dart | 66 ++-- example/lib/pages/about_dialog_page.dart | 2 +- lib/src/widgets/adw/about_window.dart | 468 ++++++++++++++--------- 3 files changed, 320 insertions(+), 216 deletions(-) diff --git a/example/lib/home_page.dart b/example/lib/home_page.dart index fe4a807..ce9f3fa 100644 --- a/example/lib/home_page.dart +++ b/example/lib/home_page.dart @@ -115,38 +115,40 @@ class _MyHomePageState extends State { top: 10, bottom: 10, ), - onPressed: () => showDialog( - context: context, - builder: (ctx) => AdwAboutWindow( - issueTrackerLink: - 'https://github.com/gtk-flutter/libadwaita/issues', - appIcon: Image.asset('assets/logo.png'), - actions: AdwActions( - onClose: Navigator.of(context).pop, - onHeaderDrag: appWindow?.startDragging, - onDoubleTap: appWindow?.maximizeOrRestore, - ), - credits: [ - AdwPreferencesGroup.credits( - title: 'Developers', - children: developers.entries - .map( - (e) => AdwActionRow( - title: e.key, - onActivated: () => launchUrl( - Uri.parse('https://github.com/${e.value}'), - ), - ), - ) - .toList(), - ), - ], - copyright: 'Copyright 2021-2022 Gtk-Flutter Developers', - license: const Text( - 'GNU LGPL-3.0, This program comes with no warranty.', - ), - ), - ), + onPressed: () { + // showDialog( + // context: context, + // builder: (ctx) => AdwAboutWindow( + // issueTrackerLink: + // 'https://github.com/gtk-flutter/libadwaita/issues', + // appIcon: Image.asset('assets/logo.png'), + // actions: AdwActions( + // onClose: Navigator.of(context).pop, + // onHeaderDrag: appWindow?.startDragging, + // onDoubleTap: appWindow?.maximizeOrRestore, + // ), + // credits: [ + // AdwPreferencesGroup.credits( + // title: 'Developers', + // children: developers.entries + // .map( + // (e) => AdwActionRow( + // title: e.key, + // onActivated: () => launchUrl( + // Uri.parse('https://github.com/${e.value}'), + // ), + // ), + // ) + // .toList(), + // ), + // ], + // copyright: 'Copyright 2021-2022 Gtk-Flutter Developers', + // license: const Text( + // 'GNU LGPL-3.0, This program comes with no warranty.', + // ), + // ), + // ); + }, child: const Text( 'About this Demo', style: TextStyle(fontSize: 15), diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart index 123bf98..bdcd5da 100644 --- a/example/lib/pages/about_dialog_page.dart +++ b/example/lib/pages/about_dialog_page.dart @@ -20,7 +20,7 @@ class AboutDialogPage extends StatelessWidget { showDialog( context: context, builder: (context) => const AdwAboutWindow( - appIcon: Icon(Icons.mp), + // appIcon: Icon(Icons.mp), ), ); }, diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index ff5d764..3204ccc 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; import 'package:libadwaita/libadwaita.dart'; -import 'package:libadwaita_core/libadwaita_core.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:url_launcher/url_launcher.dart'; /// The About window for your app in libadwaita style /// Use this with [showDialog] and onPressed / onTap / onActivated @@ -19,199 +16,304 @@ import 'package:url_launcher/url_launcher.dart'; /// ), /// ``` class AdwAboutWindow extends StatefulWidget { - const AdwAboutWindow({ - Key? key, - required this.appIcon, - this.appName, - this.appVersion, - this.nextPageIcon, - this.launchEndIcon, - this.width = 360, - @Deprecated('headerbar is deprecated, use the properties separately') - AdwHeaderBar? Function(Widget?)? headerbar, - this.headerBarStyle, - this.start, - this.end, - this.actions, - this.controls, - this.copyright, - this.issueTrackerLink, - this.license, - this.credits, - }) : super(key: key); - - final HeaderBarStyle? headerBarStyle; - - final List? start; - final List? end; - - final AdwActions? actions; - final AdwControls? controls; - - /// The width of the about window dialog - final double width; - - /// The app icon to show in the about window - final Widget appIcon; - - /// The app name to show in the about window, not required - final String? appName; - - /// The app version to show in the about window, not required - final String? appVersion; - - /// The end icon of The Credits and Legal button, - /// defaults to chevron_right Material Icon - final Widget? nextPageIcon; - - /// The end icon of Report an issue button - final Widget? launchEndIcon; - - /// The Copyright notice for Legal Screen - final String? copyright; - - /// The link for the issue tracker - final String? issueTrackerLink; - - /// The License for the app - final Text? license; - - /// The content's of Credits screen - final List? credits; + const AdwAboutWindow({Key? key}) : super(key: key); @override State createState() => _AdwAboutWindowState(); } class _AdwAboutWindowState extends State { - int currentPage = 0; + late GlobalKey navigatorKey; + late GlobalKey routeKey; + + String currentRoute = ''; + + @override + void initState() { + navigatorKey = GlobalKey(); + routeKey = GlobalKey(); + super.initState(); + } + + bool isVisible(String name) { + return name != "/" && name != ""; + } + + void goTo(String route, BuildContext context) { + setState(() { + Navigator.of(context).pushNamed(route); + }); + } + @override Widget build(BuildContext context) { - const commonPadding = EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, + return GtkDialog( + width: 0, + start: [ + AnimatedOpacity( + opacity: isVisible(currentRoute) ? 1 : 0, + duration: const Duration(milliseconds: 300), + child: AdwHeaderButton( + icon: const Icon( + Icons.chevron_left, + size: 24, + ), + onPressed: () { + navigatorKey.currentState?.pop(); + setState(() { + currentRoute = '/'; + }); + }, + ), + ) + ], + child: Navigator( + key: navigatorKey, + initialRoute: '/', + onGenerateRoute: (settings) { + currentRoute = settings.name ?? ''; + + Widget page = Builder( + builder: (context) => _AdwAboutDialogHome( + goTo: (name) => goTo(name, context), + ), + ); + + switch (settings.name) { + case '/': + break; + case '/new': + page = const _AdwAboutDialogPatchNotes(); + break; + } + + return PageRouteBuilder( + pageBuilder: (context, _, __) => page, + transitionsBuilder: + (context, animation, secondaryAnimation, child) { + const begin = Offset(1, 0); + const end = Offset.zero; + const curve = Curves.ease; + + final tween = + Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + settings: settings, + ); + }, + ), ); - final leading = currentPage != 0 - ? AdwHeaderButton( - icon: const Icon(Icons.chevron_left), - onPressed: () => setState(() => currentPage = 0), - ) - : const SizedBox(); - final text = currentPage != 0 - ? Text(currentPage == 1 ? 'Credits' : 'Legal') - : const SizedBox(); - - return FutureBuilder( - future: PackageInfo.fromPlatform(), - builder: (context, snapshot) { - final data = snapshot.hasData ? snapshot.data : null; - final isNotNull = data != null; - return GtkDialog( - constraints: BoxConstraints( - maxWidth: widget.width, - minHeight: 350, - maxHeight: 400, + } +} + +class _AdwAboutDialogHome extends StatelessWidget { + const _AdwAboutDialogHome({Key? key, required this.goTo}) : super(key: key); + + final Function(String) goTo; + + @override + Widget build(BuildContext context) { + return ListView( + padding: const EdgeInsets.symmetric(horizontal: 8), + children: [ + Align( + child: Container( + margin: const EdgeInsets.symmetric(vertical: 3), + child: Image.asset( + 'assets/logo.png', + width: 100, + ), + ), + ), + const SizedBox( + height: 5, + ), + Align( + child: const Text( + "Typeset", + style: const TextStyle( + fontSize: 26, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox( + height: 8, + ), + Align( + child: const Text( + "Angela Avery", + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w300, + ), + ), + ), + const SizedBox( + height: 12, + ), + Align( + child: AdwButton.pill( + padding: const EdgeInsets.only( + top: 6, + bottom: 8, + left: 18, + right: 18, + ), + textStyle: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + backgroundColor: Theme.of(context).colorScheme.secondary, + child: const Text('1.2.3'), ), - title: text, - start: [ - leading, - if (widget.start != null) ...widget.start!, + ), + const SizedBox(height: 20), + AdwPreferencesGroup( + children: [ + AdwActionRow( + title: 'What\'s new', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () { + goTo("/new"); + }, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), + ), + AdwActionRow( + title: 'Details', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () {}, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), + ), + ], + ), + const SizedBox(height: 8), + AdwPreferencesGroup( + children: [ + AdwActionRow( + title: 'Support Questions', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () {}, + end: const Icon( + Icons.open_in_new_rounded, + size: 16, + ), + ), + AdwActionRow( + title: 'Report an issue', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () {}, + end: const Icon( + Icons.open_in_new_rounded, + size: 16, + ), + ), ], - end: widget.end ?? [], - actions: widget.actions ?? - AdwActions( - onClose: Navigator.of(context).pop, + ), + const SizedBox(height: 8), + AdwPreferencesGroup( + children: [ + AdwActionRow( + title: 'Credits', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () {}, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), + ), + AdwActionRow( + title: 'Legal', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () {}, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, ), - controls: widget.controls, - headerBarStyle: widget.headerBarStyle ?? - const HeaderBarStyle( - isTransparent: true, + ), + AdwActionRow( + title: 'Acknowledgements', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, ), - padding: commonPadding, - children: currentPage == 0 - ? [ - Container( - margin: const EdgeInsets.symmetric(vertical: 3), - width: 80, - child: widget.appIcon, - ), - Text( - widget.appName ?? (isNotNull ? data!.appName : '---'), - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 6), - AdwPreferencesGroup( - children: [ - AdwActionRow( - title: 'Version', - end: Text( - widget.appVersion ?? - (isNotNull ? data!.version : '0'), - ), - ), - if (widget.issueTrackerLink != null) - AdwActionRow( - title: 'Report an issue', - onActivated: () => launchUrl( - Uri.parse(widget.issueTrackerLink!), - ), - end: widget.launchEndIcon ?? - const Icon( - Icons.open_in_new_outlined, - size: 20, - ), - ), - ], - ), - if ((widget.credits != null) || - widget.copyright != null || - widget.license != null) ...[ - const SizedBox(height: 8), - AdwPreferencesGroup( - children: [ - if (widget.credits != null) - AdwActionRow( - title: 'Credits', - onActivated: () => setState(() => currentPage = 1), - end: widget.nextPageIcon ?? - const Icon( - Icons.chevron_right, - ), - ), - if (widget.copyright != null || widget.license != null) - AdwActionRow( - title: 'Legal', - onActivated: () => setState(() => currentPage = 2), - end: widget.nextPageIcon ?? - const Icon( - Icons.chevron_right, - ), - ), - ], - ), - ], - ] - : currentPage == 1 - ? widget.credits! - .map( - (e) => Padding( - padding: const EdgeInsets.only( - bottom: 10, - ), - child: e, - ), - ) - .toList() - : [ - if (widget.copyright != null) Text(widget.copyright!), - const SizedBox(height: 5), - if (widget.license != null) widget.license!, - ], - ); - }, + onActivated: () {}, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), + ), + ], + ), + const SizedBox( + height: 8, + ) + ], + ); + } +} + +class _AdwAboutDialogPatchNotes extends StatelessWidget { + const _AdwAboutDialogPatchNotes({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).dialogBackgroundColor, + height: double.infinity, + child: ListView( + padding: EdgeInsets.symmetric(horizontal: 12), + children: [ + Text( + "Version 1.2.0", + style: TextStyle( + fontWeight: FontWeight.w500, + ), + ), + SizedBox( + height: 16, + ), + Text(""" +This release adds the following features: + +• Added a way to export fonts. +• Better support for monospace fonts. +• Added a way to preview italic text. +• Bug fixes and performance improvements. +• Translation updates. + """), + ], + ), ); } } From cc8c58151be136f3250f4d9369f5dd832e8cec64 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Tue, 9 Aug 2022 19:32:36 -0700 Subject: [PATCH 05/13] refactor(dialog): Change how width and height is applied More flexible this way --- lib/src/widgets/gtk/dialog.dart | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/src/widgets/gtk/dialog.dart b/lib/src/widgets/gtk/dialog.dart index 32e371d..130c4d6 100644 --- a/lib/src/widgets/gtk/dialog.dart +++ b/lib/src/widgets/gtk/dialog.dart @@ -38,14 +38,11 @@ class GtkDialog extends StatelessWidget { Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: ConstrainedBox( - constraints: constraints ?? - BoxConstraints( - maxWidth: width ?? 600, - maxHeight: height ?? 600, - ), + child: SizedBox( + width: width ?? 600, + height: height ?? 600, + child: ClipRRect( + borderRadius: BorderRadius.circular(12), child: Column( mainAxisSize: MainAxisSize.min, children: [ From 4df0a1cd04994903eb8dc8c87f2dd93e2c611275 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Tue, 9 Aug 2022 19:33:03 -0700 Subject: [PATCH 06/13] feat(about_window): Set width to 300 --- lib/src/widgets/adw/about_window.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 3204ccc..8112c82 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -48,7 +48,7 @@ class _AdwAboutWindowState extends State { @override Widget build(BuildContext context) { return GtkDialog( - width: 0, + width: 300, start: [ AnimatedOpacity( opacity: isVisible(currentRoute) ? 1 : 0, From 5e1536555ec498c73e83537529980c060a89c643 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Tue, 9 Aug 2022 19:34:18 -0700 Subject: [PATCH 07/13] about_window: Remove unused key --- lib/src/widgets/adw/about_window.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 8112c82..1cfab01 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -24,14 +24,12 @@ class AdwAboutWindow extends StatefulWidget { class _AdwAboutWindowState extends State { late GlobalKey navigatorKey; - late GlobalKey routeKey; String currentRoute = ''; @override void initState() { navigatorKey = GlobalKey(); - routeKey = GlobalKey(); super.initState(); } From 9d83b9e1482e28f4f2a4974afc940fd9afda02f3 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Tue, 9 Aug 2022 19:39:25 -0700 Subject: [PATCH 08/13] feat(about_window): Absorb pointer events from back button when not being shown --- lib/src/widgets/adw/about_window.dart | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 1cfab01..adfe006 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -51,17 +51,20 @@ class _AdwAboutWindowState extends State { AnimatedOpacity( opacity: isVisible(currentRoute) ? 1 : 0, duration: const Duration(milliseconds: 300), - child: AdwHeaderButton( - icon: const Icon( - Icons.chevron_left, - size: 24, + child: AbsorbPointer( + absorbing: !isVisible(currentRoute), + child: AdwHeaderButton( + icon: const Icon( + Icons.chevron_left, + size: 24, + ), + onPressed: () { + navigatorKey.currentState?.pop(); + setState(() { + currentRoute = '/'; + }); + }, ), - onPressed: () { - navigatorKey.currentState?.pop(); - setState(() { - currentRoute = '/'; - }); - }, ), ) ], From 22c46f88386e1dde18be1fdf260c0c9a2f72c80f Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Wed, 10 Aug 2022 11:48:38 -0700 Subject: [PATCH 09/13] feat: Add details page support --- example/lib/pages/about_dialog_page.dart | 13 +- .../about_window/about_window_details.dart | 6 + lib/src/models/models.dart | 1 + lib/src/widgets/adw/about_window.dart | 115 +++++++++++++----- 4 files changed, 103 insertions(+), 32 deletions(-) create mode 100644 lib/src/models/about_window/about_window_details.dart diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart index bdcd5da..c624cb4 100644 --- a/example/lib/pages/about_dialog_page.dart +++ b/example/lib/pages/about_dialog_page.dart @@ -15,12 +15,19 @@ class AboutDialogPage extends StatelessWidget { title: 'About Dialog', description: 'Something something', footer: AdwButton.pill( - child: const Text('Run the demo'), + child: const Text('Run the demo'), onPressed: () { showDialog( context: context, - builder: (context) => const AdwAboutWindow( - // appIcon: Icon(Icons.mp), + builder: (context) => AdwAboutWindow( + details: AboutWindowDetails( + comments: + "Typeset is an app that doesn't exist and is used as an example content for this about window.", + links: { + 'Website': 'https://example.org', + 'Documentation': 'https://example.org', + }, + ), ), ); }, diff --git a/lib/src/models/about_window/about_window_details.dart b/lib/src/models/about_window/about_window_details.dart new file mode 100644 index 0000000..e673489 --- /dev/null +++ b/lib/src/models/about_window/about_window_details.dart @@ -0,0 +1,6 @@ +class AboutWindowDetails { + AboutWindowDetails({this.comments, this.links}); + + final String? comments; + final Map? links; +} diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart index 5a9cbb4..8ed1fe6 100644 --- a/lib/src/models/models.dart +++ b/lib/src/models/models.dart @@ -1,2 +1,3 @@ +export 'about_window/about_window_details.dart'; export 'view_switcher_data.dart'; export 'view_switcher_policy.dart'; diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index adfe006..5b0e88c 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -16,7 +16,9 @@ import 'package:libadwaita/libadwaita.dart'; /// ), /// ``` class AdwAboutWindow extends StatefulWidget { - const AdwAboutWindow({Key? key}) : super(key: key); + const AdwAboutWindow({Key? key, this.details}) : super(key: key); + + final AboutWindowDetails? details; @override State createState() => _AdwAboutWindowState(); @@ -34,7 +36,7 @@ class _AdwAboutWindowState extends State { } bool isVisible(String name) { - return name != "/" && name != ""; + return name != '/' && name != ''; } void goTo(String route, BuildContext context) { @@ -77,6 +79,7 @@ class _AdwAboutWindowState extends State { Widget page = Builder( builder: (context) => _AdwAboutDialogHome( goTo: (name) => goTo(name, context), + details: widget.details, ), ); @@ -86,6 +89,9 @@ class _AdwAboutWindowState extends State { case '/new': page = const _AdwAboutDialogPatchNotes(); break; + case '/details': + page = _AdwAboutDialogDetails(details: widget.details!); + break; } return PageRouteBuilder( @@ -113,9 +119,11 @@ class _AdwAboutWindowState extends State { } class _AdwAboutDialogHome extends StatelessWidget { - const _AdwAboutDialogHome({Key? key, required this.goTo}) : super(key: key); + const _AdwAboutDialogHome({Key? key, required this.goTo, this.details}) + : super(key: key); final Function(String) goTo; + final AboutWindowDetails? details; @override Widget build(BuildContext context) { @@ -134,10 +142,10 @@ class _AdwAboutDialogHome extends StatelessWidget { const SizedBox( height: 5, ), - Align( - child: const Text( - "Typeset", - style: const TextStyle( + const Align( + child: Text( + 'Typeset', + style: TextStyle( fontSize: 26, fontWeight: FontWeight.bold, ), @@ -146,10 +154,10 @@ class _AdwAboutDialogHome extends StatelessWidget { const SizedBox( height: 8, ), - Align( - child: const Text( - "Angela Avery", - style: const TextStyle( + const Align( + child: Text( + 'Angela Avery', + style: TextStyle( fontSize: 14, fontWeight: FontWeight.w300, ), @@ -179,31 +187,34 @@ class _AdwAboutDialogHome extends StatelessWidget { AdwPreferencesGroup( children: [ AdwActionRow( - title: 'What\'s new', + title: "What's new", titleStyle: const TextStyle( fontWeight: FontWeight.normal, fontSize: 13, ), onActivated: () { - goTo("/new"); + goTo('/new'); }, end: const Icon( Icons.arrow_forward_ios, size: 16, ), ), - AdwActionRow( - title: 'Details', - titleStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 13, + if (details != null) + AdwActionRow( + title: 'Details', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () { + goTo('/details'); + }, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), ), - onActivated: () {}, - end: const Icon( - Icons.arrow_forward_ios, - size: 16, - ), - ), ], ), const SizedBox(height: 8), @@ -293,10 +304,10 @@ class _AdwAboutDialogPatchNotes extends StatelessWidget { color: Theme.of(context).dialogBackgroundColor, height: double.infinity, child: ListView( - padding: EdgeInsets.symmetric(horizontal: 12), - children: [ + padding: const EdgeInsets.symmetric(horizontal: 12), + children: const [ Text( - "Version 1.2.0", + 'Version 1.2.0', style: TextStyle( fontWeight: FontWeight.w500, ), @@ -304,7 +315,8 @@ class _AdwAboutDialogPatchNotes extends StatelessWidget { SizedBox( height: 16, ), - Text(""" + Text( + ''' This release adds the following features: • Added a way to export fonts. @@ -312,7 +324,52 @@ This release adds the following features: • Added a way to preview italic text. • Bug fixes and performance improvements. • Translation updates. - """), + ''', + ), + ], + ), + ); + } +} + +class _AdwAboutDialogDetails extends StatelessWidget { + const _AdwAboutDialogDetails({Key? key, required this.details}) + : super(key: key); + + final AboutWindowDetails details; + + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).dialogBackgroundColor, + height: double.infinity, + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + children: [ + if (details.comments != null) + Text( + details.comments!, + ), + const SizedBox(height: 16), + AdwPreferencesGroup( + children: details.links?.entries + .map( + (entry) => AdwActionRow( + title: entry.key, + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () {}, + end: const Icon( + Icons.open_in_new, + size: 16, + ), + ), + ) + .toList() ?? + [], + ) ], ), ); From 2cf4767bc0ea6b6bf37a6c072a03408d6ffd14bb Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Thu, 11 Aug 2022 16:07:24 -0700 Subject: [PATCH 10/13] feat: Add troubleshooting links support --- example/lib/pages/about_dialog_page.dart | 2 + lib/src/widgets/adw/about_window.dart | 94 ++++++++++++++++-------- 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart index c624cb4..fa2139b 100644 --- a/example/lib/pages/about_dialog_page.dart +++ b/example/lib/pages/about_dialog_page.dart @@ -20,6 +20,8 @@ class AboutDialogPage extends StatelessWidget { showDialog( context: context, builder: (context) => AdwAboutWindow( + supportUrl: 'https://example.org', + issueUrl: 'https://example.org', details: AboutWindowDetails( comments: "Typeset is an app that doesn't exist and is used as an example content for this about window.", diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 5b0e88c..461dae5 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:libadwaita/libadwaita.dart'; +import 'package:url_launcher/url_launcher_string.dart'; /// The About window for your app in libadwaita style /// Use this with [showDialog] and onPressed / onTap / onActivated @@ -16,9 +17,16 @@ import 'package:libadwaita/libadwaita.dart'; /// ), /// ``` class AdwAboutWindow extends StatefulWidget { - const AdwAboutWindow({Key? key, this.details}) : super(key: key); + const AdwAboutWindow({ + Key? key, + this.details, + this.supportUrl, + this.issueUrl, + }) : super(key: key); final AboutWindowDetails? details; + final String? supportUrl; + final String? issueUrl; @override State createState() => _AdwAboutWindowState(); @@ -80,6 +88,8 @@ class _AdwAboutWindowState extends State { builder: (context) => _AdwAboutDialogHome( goTo: (name) => goTo(name, context), details: widget.details, + supportUrl: widget.supportUrl, + issueUrl: widget.issueUrl, ), ); @@ -119,11 +129,22 @@ class _AdwAboutWindowState extends State { } class _AdwAboutDialogHome extends StatelessWidget { - const _AdwAboutDialogHome({Key? key, required this.goTo, this.details}) - : super(key: key); + const _AdwAboutDialogHome({ + Key? key, + required this.goTo, + this.details, + this.supportUrl, + this.issueUrl, + }) : super(key: key); final Function(String) goTo; final AboutWindowDetails? details; + final String? supportUrl; + final String? issueUrl; + + bool hasTroubleshooting() { + return supportUrl != null || issueUrl != null; + } @override Widget build(BuildContext context) { @@ -217,35 +238,46 @@ class _AdwAboutDialogHome extends StatelessWidget { ), ], ), - const SizedBox(height: 8), - AdwPreferencesGroup( - children: [ - AdwActionRow( - title: 'Support Questions', - titleStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 13, - ), - onActivated: () {}, - end: const Icon( - Icons.open_in_new_rounded, - size: 16, - ), - ), - AdwActionRow( - title: 'Report an issue', - titleStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 13, - ), - onActivated: () {}, - end: const Icon( - Icons.open_in_new_rounded, - size: 16, + if (hasTroubleshooting()) + Column( + children: [ + const SizedBox(height: 8), + AdwPreferencesGroup( + children: [ + if (supportUrl != null) + AdwActionRow( + title: 'Support Questions', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () { + launchUrlString(supportUrl!); + }, + end: const Icon( + Icons.open_in_new_rounded, + size: 16, + ), + ), + if (issueUrl != null) + AdwActionRow( + title: 'Report an issue', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () { + launchUrlString(issueUrl!); + }, + end: const Icon( + Icons.open_in_new_rounded, + size: 16, + ), + ), + ], ), - ), - ], - ), + ], + ), const SizedBox(height: 8), AdwPreferencesGroup( children: [ From ed23a6a5dd7eda56fc0474d527a54308a748e08a Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Tue, 16 Aug 2022 17:00:55 -0700 Subject: [PATCH 11/13] feat: Add credits support --- example/lib/pages/about_dialog_page.dart | 12 ++ .../about_window/about_window_person.dart | 6 + lib/src/models/models.dart | 1 + lib/src/widgets/adw/about_window.dart | 107 +++++++++++++++++- 4 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 lib/src/models/about_window/about_window_person.dart diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart index fa2139b..1d868ed 100644 --- a/example/lib/pages/about_dialog_page.dart +++ b/example/lib/pages/about_dialog_page.dart @@ -22,6 +22,18 @@ class AboutDialogPage extends StatelessWidget { builder: (context) => AdwAboutWindow( supportUrl: 'https://example.org', issueUrl: 'https://example.org', + developers: [ + AboutWindowPerson( + name: 'Angela Avery', + url: 'mailto:angela@example.com', + ), + ], + designers: [ + AboutWindowPerson( + name: 'Ben Dover', + url: 'mailto:ben@dover.com', + ), + ], details: AboutWindowDetails( comments: "Typeset is an app that doesn't exist and is used as an example content for this about window.", diff --git a/lib/src/models/about_window/about_window_person.dart b/lib/src/models/about_window/about_window_person.dart new file mode 100644 index 0000000..55c796a --- /dev/null +++ b/lib/src/models/about_window/about_window_person.dart @@ -0,0 +1,6 @@ +class AboutWindowPerson { + AboutWindowPerson({required this.name, this.url}); + + final String name; + final String? url; +} diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart index 8ed1fe6..207e5a1 100644 --- a/lib/src/models/models.dart +++ b/lib/src/models/models.dart @@ -1,3 +1,4 @@ export 'about_window/about_window_details.dart'; +export 'about_window/about_window_person.dart'; export 'view_switcher_data.dart'; export 'view_switcher_policy.dart'; diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 461dae5..76f36dd 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:libadwaita/libadwaita.dart'; +import 'package:libadwaita/src/models/about_window/about_window_person.dart'; import 'package:url_launcher/url_launcher_string.dart'; /// The About window for your app in libadwaita style @@ -22,11 +23,21 @@ class AdwAboutWindow extends StatefulWidget { this.details, this.supportUrl, this.issueUrl, + this.developers, + this.designers, + this.artists, + this.documentors, + this.translators, }) : super(key: key); final AboutWindowDetails? details; final String? supportUrl; final String? issueUrl; + final List? developers; + final List? designers; + final List? artists; + final List? documentors; + final List? translators; @override State createState() => _AdwAboutWindowState(); @@ -102,6 +113,15 @@ class _AdwAboutWindowState extends State { case '/details': page = _AdwAboutDialogDetails(details: widget.details!); break; + case '/credits': + page = _AdwAboutDialogCredits( + artists: widget.artists, + developers: widget.developers, + designers: widget.designers, + documentors: widget.documentors, + translators: widget.translators, + ); + break; } return PageRouteBuilder( @@ -268,7 +288,7 @@ class _AdwAboutDialogHome extends StatelessWidget { ), onActivated: () { launchUrlString(issueUrl!); - }, + }, end: const Icon( Icons.open_in_new_rounded, size: 16, @@ -287,7 +307,9 @@ class _AdwAboutDialogHome extends StatelessWidget { fontWeight: FontWeight.normal, fontSize: 13, ), - onActivated: () {}, + onActivated: () { + goTo('/credits'); + }, end: const Icon( Icons.arrow_forward_ios, size: 16, @@ -407,3 +429,84 @@ class _AdwAboutDialogDetails extends StatelessWidget { ); } } + +class _AdwAboutDialogCredits extends StatelessWidget { + const _AdwAboutDialogCredits({ + Key? key, + this.developers, + this.designers, + this.artists, + this.documentors, + this.translators, + }) : super(key: key); + + final List? developers; + final List? designers; + final List? artists; + final List? documentors; + final List? translators; + + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).dialogBackgroundColor, + height: double.infinity, + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + children: [ + if (developers != null) + _CreditSection(type: 'Developed by', people: developers!), + if (designers != null) + _CreditSection(type: 'Design by', people: designers!), + if (artists != null) + _CreditSection(type: 'Artwork by', people: artists!), + if (documentors != null) + _CreditSection(type: 'Documented by', people: documentors!), + if (translators != null) + _CreditSection(type: 'Translated by', people: translators!), + ], + ), + ); + } +} + +class _CreditSection extends StatelessWidget { + const _CreditSection({Key? key, required this.type, required this.people}) + : super(key: key); + + final String type; + final List people; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 5, + ), + child: AdwPreferencesGroup.credits( + title: type, + children: [ + ...people + .map( + (e) => AdwActionRow( + title: e.name, + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: + e.url != null ? () => launchUrlString(e.url!) : null, + end: e.url != null + ? const Icon( + Icons.open_in_new, + size: 16, + ) + : null, + ), + ) + .toList() + ], + ), + ); + } +} From 9d9aa6705f35f9b61d8b626686ae63c9a7d68809 Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Fri, 19 Aug 2022 17:07:52 -0700 Subject: [PATCH 12/13] feat: Add acknowledgements section support --- example/lib/pages/about_dialog_page.dart | 10 +++ .../about_window_acknowledgement_section.dart | 8 +++ lib/src/models/models.dart | 2 + lib/src/widgets/adw/about_window.dart | 69 +++++++++++++++---- 4 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 lib/src/models/about_window/about_window_acknowledgement_section.dart diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart index 1d868ed..de13225 100644 --- a/example/lib/pages/about_dialog_page.dart +++ b/example/lib/pages/about_dialog_page.dart @@ -34,6 +34,16 @@ class AboutDialogPage extends StatelessWidget { url: 'mailto:ben@dover.com', ), ], + acknowledgements: [ + AboutWindowAcknowledgementSection( + name: 'Special Thanks to', + people: [ + AboutWindowPerson( + name: 'My Cat', + ), + ], + ), + ], details: AboutWindowDetails( comments: "Typeset is an app that doesn't exist and is used as an example content for this about window.", diff --git a/lib/src/models/about_window/about_window_acknowledgement_section.dart b/lib/src/models/about_window/about_window_acknowledgement_section.dart new file mode 100644 index 0000000..728155c --- /dev/null +++ b/lib/src/models/about_window/about_window_acknowledgement_section.dart @@ -0,0 +1,8 @@ +import 'package:libadwaita/libadwaita.dart'; + +class AboutWindowAcknowledgementSection { + AboutWindowAcknowledgementSection({required this.name, required this.people}); + + final String name; + final List people; +} diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart index 207e5a1..88a9e1d 100644 --- a/lib/src/models/models.dart +++ b/lib/src/models/models.dart @@ -1,4 +1,6 @@ +export 'about_window/about_window_acknowledgement_section.dart'; export 'about_window/about_window_details.dart'; export 'about_window/about_window_person.dart'; +export 'about_window/about_window_person.dart'; export 'view_switcher_data.dart'; export 'view_switcher_policy.dart'; diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 76f36dd..3f3371f 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:libadwaita/libadwaita.dart'; -import 'package:libadwaita/src/models/about_window/about_window_person.dart'; +import 'package:libadwaita/src/models/about_window/about_window_acknowledgement_section.dart'; import 'package:url_launcher/url_launcher_string.dart'; /// The About window for your app in libadwaita style @@ -28,6 +28,7 @@ class AdwAboutWindow extends StatefulWidget { this.artists, this.documentors, this.translators, + this.acknowledgements, }) : super(key: key); final AboutWindowDetails? details; @@ -38,6 +39,7 @@ class AdwAboutWindow extends StatefulWidget { final List? artists; final List? documentors; final List? translators; + final List? acknowledgements; @override State createState() => _AdwAboutWindowState(); @@ -101,6 +103,7 @@ class _AdwAboutWindowState extends State { details: widget.details, supportUrl: widget.supportUrl, issueUrl: widget.issueUrl, + acknowledgements: widget.acknowledgements, ), ); @@ -122,6 +125,11 @@ class _AdwAboutWindowState extends State { translators: widget.translators, ); break; + case '/acknowledgements': + page = _AdwAboutDialogAcknowledgements( + sections: widget.acknowledgements!, + ); + break; } return PageRouteBuilder( @@ -155,17 +163,23 @@ class _AdwAboutDialogHome extends StatelessWidget { this.details, this.supportUrl, this.issueUrl, + this.acknowledgements, }) : super(key: key); final Function(String) goTo; final AboutWindowDetails? details; final String? supportUrl; final String? issueUrl; + final List? acknowledgements; bool hasTroubleshooting() { return supportUrl != null || issueUrl != null; } + bool hasAcknowledgements() { + return acknowledgements != null && acknowledgements!.isNotEmpty; + } + @override Widget build(BuildContext context) { return ListView( @@ -327,18 +341,21 @@ class _AdwAboutDialogHome extends StatelessWidget { size: 16, ), ), - AdwActionRow( - title: 'Acknowledgements', - titleStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 13, - ), - onActivated: () {}, - end: const Icon( - Icons.arrow_forward_ios, - size: 16, + if (hasAcknowledgements()) + AdwActionRow( + title: 'Acknowledgements', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () { + goTo('/acknowledgements'); + }, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), ), - ), ], ), const SizedBox( @@ -470,6 +487,34 @@ class _AdwAboutDialogCredits extends StatelessWidget { } } +class _AdwAboutDialogAcknowledgements extends StatelessWidget { + const _AdwAboutDialogAcknowledgements({ + Key? key, + required this.sections, + }) : super(key: key); + + final List sections; + + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).dialogBackgroundColor, + height: double.infinity, + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + children: sections + .map( + (e) => _CreditSection( + type: e.name, + people: e.people, + ), + ) + .toList(), + ), + ); + } +} + class _CreditSection extends StatelessWidget { const _CreditSection({Key? key, required this.type, required this.people}) : super(key: key); From cb2b069e4b565e6ec5f6667da8cf9e8ebbf135bb Mon Sep 17 00:00:00 2001 From: Simrat Grewal Date: Thu, 8 Sep 2022 17:59:15 -0700 Subject: [PATCH 13/13] feat: Add initial legal page --- example/lib/pages/about_dialog_page.dart | 16 ++- example/pubspec.lock | 24 ++-- .../about_window/about_window_legal.dart | 8 ++ lib/src/models/models.dart | 1 + lib/src/widgets/adw/about_window.dart | 109 ++++++++++++++---- 5 files changed, 122 insertions(+), 36 deletions(-) create mode 100644 lib/src/models/about_window/about_window_legal.dart diff --git a/example/lib/pages/about_dialog_page.dart b/example/lib/pages/about_dialog_page.dart index de13225..a78a32d 100644 --- a/example/lib/pages/about_dialog_page.dart +++ b/example/lib/pages/about_dialog_page.dart @@ -45,13 +45,25 @@ class AboutDialogPage extends StatelessWidget { ), ], details: AboutWindowDetails( - comments: - "Typeset is an app that doesn't exist and is used as an example content for this about window.", + comments: """ +Typeset is an app that doesn't exist and is used as an example content for this about window.""", links: { 'Website': 'https://example.org', 'Documentation': 'https://example.org', }, ), + legalSections: [ + AboutWindowLegalSection( + title: 'This Application', + copyright: '© 2022', + license: ''' +This application comes with absolutely no warranty. See the GNU Lesser General Public License, version 2.1 or later for details''', + ), + AboutWindowLegalSection( + title: 'Fonts', + copyright: '© 2022', + license: 'This application uses font data from somewhere.'), + ], ), ); }, diff --git a/example/pubspec.lock b/example/pubspec.lock index 40331bd..2398f05 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,7 +21,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" bitsdojo_window_linux: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -77,7 +77,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: @@ -105,7 +105,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" ffi: dependency: transitive description: @@ -197,21 +197,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" package_info_plus: dependency: transitive description: @@ -260,7 +260,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" path_drawing: dependency: transitive description: @@ -321,7 +321,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -342,21 +342,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" typed_data: dependency: transitive description: diff --git a/lib/src/models/about_window/about_window_legal.dart b/lib/src/models/about_window/about_window_legal.dart new file mode 100644 index 0000000..f0148da --- /dev/null +++ b/lib/src/models/about_window/about_window_legal.dart @@ -0,0 +1,8 @@ +class AboutWindowLegalSection { + AboutWindowLegalSection( + {required this.title, required this.copyright, required this.license,}); + + final String title; + final String copyright; + final String license; +} diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart index 88a9e1d..63bcda7 100644 --- a/lib/src/models/models.dart +++ b/lib/src/models/models.dart @@ -1,5 +1,6 @@ export 'about_window/about_window_acknowledgement_section.dart'; export 'about_window/about_window_details.dart'; +export 'about_window/about_window_legal.dart'; export 'about_window/about_window_person.dart'; export 'about_window/about_window_person.dart'; export 'view_switcher_data.dart'; diff --git a/lib/src/widgets/adw/about_window.dart b/lib/src/widgets/adw/about_window.dart index 3f3371f..4cf65d5 100644 --- a/lib/src/widgets/adw/about_window.dart +++ b/lib/src/widgets/adw/about_window.dart @@ -1,22 +1,12 @@ import 'package:flutter/material.dart'; import 'package:libadwaita/libadwaita.dart'; -import 'package:libadwaita/src/models/about_window/about_window_acknowledgement_section.dart'; import 'package:url_launcher/url_launcher_string.dart'; /// The About window for your app in libadwaita style /// Use this with [showDialog] and onPressed / onTap / onActivated /// parameter of a button /// Example: -/// ``` -/// showDialog( -/// context: context, -/// builder: (ctx) => AdwAboutWindow( -/// issueTrackerLink: 'link', -/// appIcon: Image.asset('assets/logo.png'), -/// credits: [], -/// ), -/// ), -/// ``` +/// ``` showDialog( context: context, builder: (ctx) => AdwAboutWindow( issueTrackerLink: 'link', appIcon: Image.asset('assets/logo.png'), credits: [],),), ``` class AdwAboutWindow extends StatefulWidget { const AdwAboutWindow({ Key? key, @@ -29,6 +19,7 @@ class AdwAboutWindow extends StatefulWidget { this.documentors, this.translators, this.acknowledgements, + this.legalSections, }) : super(key: key); final AboutWindowDetails? details; @@ -40,6 +31,7 @@ class AdwAboutWindow extends StatefulWidget { final List? documentors; final List? translators; final List? acknowledgements; + final List? legalSections; @override State createState() => _AdwAboutWindowState(); @@ -104,6 +96,7 @@ class _AdwAboutWindowState extends State { supportUrl: widget.supportUrl, issueUrl: widget.issueUrl, acknowledgements: widget.acknowledgements, + legalSections: widget.legalSections, ), ); @@ -130,6 +123,11 @@ class _AdwAboutWindowState extends State { sections: widget.acknowledgements!, ); break; + case '/legal': + page = _AdwAboutDialogLegal( + legalSections: widget.legalSections!, + ); + break; } return PageRouteBuilder( @@ -164,6 +162,7 @@ class _AdwAboutDialogHome extends StatelessWidget { this.supportUrl, this.issueUrl, this.acknowledgements, + this.legalSections, }) : super(key: key); final Function(String) goTo; @@ -171,6 +170,7 @@ class _AdwAboutDialogHome extends StatelessWidget { final String? supportUrl; final String? issueUrl; final List? acknowledgements; + final List? legalSections; bool hasTroubleshooting() { return supportUrl != null || issueUrl != null; @@ -180,6 +180,10 @@ class _AdwAboutDialogHome extends StatelessWidget { return acknowledgements != null && acknowledgements!.isNotEmpty; } + bool hasLegal() { + return legalSections != null && legalSections!.isNotEmpty; + } + @override Widget build(BuildContext context) { return ListView( @@ -329,18 +333,21 @@ class _AdwAboutDialogHome extends StatelessWidget { size: 16, ), ), - AdwActionRow( - title: 'Legal', - titleStyle: const TextStyle( - fontWeight: FontWeight.normal, - fontSize: 13, - ), - onActivated: () {}, - end: const Icon( - Icons.arrow_forward_ios, - size: 16, + if (hasLegal()) + AdwActionRow( + title: 'Legal', + titleStyle: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 13, + ), + onActivated: () { + goTo('/legal'); + }, + end: const Icon( + Icons.arrow_forward_ios, + size: 16, + ), ), - ), if (hasAcknowledgements()) AdwActionRow( title: 'Acknowledgements', @@ -555,3 +562,61 @@ class _CreditSection extends StatelessWidget { ); } } + +class _AdwAboutDialogLegal extends StatelessWidget { + const _AdwAboutDialogLegal({Key? key, required this.legalSections}) + : super(key: key); + + final List legalSections; + + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).dialogBackgroundColor, + height: double.infinity, + child: ListView( + padding: const EdgeInsets.symmetric(horizontal: 12), + children: legalSections + .map((e) => _AdwAboutDialogLegalSection(info: e)) + .toList(), + ), + ); + } +} + +class _AdwAboutDialogLegalSection extends StatelessWidget { + const _AdwAboutDialogLegalSection({Key? key, required this.info}) + : super(key: key); + + final AboutWindowLegalSection info; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + info.title, + style: const TextStyle( + fontWeight: FontWeight.w500, + ), + ), + const SizedBox( + height: 16, + ), + Text( + info.copyright, + ), + const SizedBox( + height: 12, + ), + Text( + info.license, + ), + const SizedBox( + height: 20, + ), + ], + ); + } +}