From af3b540a380181c76f96092c1743880878e3abe0 Mon Sep 17 00:00:00 2001 From: Wilielmus <88447902+WilliamKarolDiCioccio@users.noreply.github.com> Date: Mon, 26 Aug 2024 18:12:01 +0200 Subject: [PATCH] Create ChangelogDialog --- app/assets/l10n/intl_en.arb | 1 + app/assets/metadata/app_changelog.json | 24 +++ app/lib/frontend/dialogs/changelog.dart | 237 ++++++++++++++++++++++++ app/lib/frontend/screens/dashboard.dart | 17 +- app/pubspec.yaml | 2 + 5 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 app/assets/metadata/app_changelog.json create mode 100644 app/lib/frontend/dialogs/changelog.dart diff --git a/app/assets/l10n/intl_en.arb b/app/assets/l10n/intl_en.arb index 25e2109..dffb510 100644 --- a/app/assets/l10n/intl_en.arb +++ b/app/assets/l10n/intl_en.arb @@ -24,6 +24,7 @@ "attachFilesDialogBrowseFilesButton": "Browse files", "attachFilesDialogDropFilesText": "Drop files here", "cancelButtonShared": "Cancel", + "changelogButton": "Changelog", "chatAttachFilesTooltip": "Attach files", "chatCancelEditButton": "Cancel editing", "chatCancelGenerationTooltip": "Cancel generation", diff --git a/app/assets/metadata/app_changelog.json b/app/assets/metadata/app_changelog.json new file mode 100644 index 0000000..342e10e --- /dev/null +++ b/app/assets/metadata/app_changelog.json @@ -0,0 +1,24 @@ +{ + "releases": [ + { + "version": "1.0.0", + "date": "26/08/2024", + "type": "patch", + "image": "https://github.com/WilliamKarolDiCioccio/open_local_ui/raw/main/.github/images/github_readme_banner.webp", + "changes": [ + { + "category": "bugfix", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + }, + { + "category": "feature", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + }, + { + "category": "improvement", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + } + ] + } + ] +} diff --git a/app/lib/frontend/dialogs/changelog.dart b/app/lib/frontend/dialogs/changelog.dart new file mode 100644 index 0000000..89748e4 --- /dev/null +++ b/app/lib/frontend/dialogs/changelog.dart @@ -0,0 +1,237 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; + +import 'package:adaptive_theme/adaptive_theme.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:gap/gap.dart'; +import 'package:timelines_plus/timelines_plus.dart'; +import 'package:unicons/unicons.dart'; + +class ChangelogDialog extends StatelessWidget { + Widget _buildChangeCategoryChip(String type) { + switch (type) { + case 'bugfix': + return Chip( + avatar: Icon( + UniconsLine.bug, + size: 18, + color: Colors.red, + ), + label: Text( + type.toUpperCase(), + style: TextStyle( + fontSize: 12, + ), + ), + backgroundColor: Colors.red.withOpacity(0.25), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + side: BorderSide( + color: Colors.red, + width: 1, + ), + ), + ); + case 'feature': + return Chip( + avatar: Icon( + UniconsLine.rocket, + size: 18, + color: Colors.green, + ), + label: Text( + type.toUpperCase(), + style: TextStyle( + fontSize: 12, + ), + ), + backgroundColor: Colors.green.withOpacity(0.25), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + side: BorderSide( + color: Colors.green, + width: 1, + ), + ), + ); + case 'improvement': + return Chip( + avatar: Icon( + UniconsLine.chart_bar, + size: 18, + color: Colors.tealAccent, + ), + label: Text( + type.toUpperCase(), + style: TextStyle( + fontSize: 12, + ), + ), + backgroundColor: Colors.tealAccent.withOpacity(0.25), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20.0), + side: BorderSide( + color: Colors.tealAccent, + width: 1, + ), + ), + ); + default: + return SizedBox.shrink(); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('Changelog'), + content: SizedBox( + width: 900, + child: FutureBuilder( + future: DefaultAssetBundle.of(context).loadString( + 'assets/metadata/app_changelog.json', + ), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return CircularProgressIndicator(); + } else if (snapshot.hasData) { + final changelogData = jsonDecode(snapshot.data.toString()); + final releases = changelogData['releases'] as List; + + if (releases.isEmpty) return Text('No changelog data available'); + + return SingleChildScrollView( + child: FixedTimeline( + theme: TimelineThemeData( + nodePosition: 0.5, + connectorTheme: ConnectorThemeData( + color: Colors.grey, + thickness: 2.0, + ), + indicatorTheme: IndicatorThemeData( + size: 20.0, + color: Colors.blue, + ), + ), + children: releases.map((release) { + final version = release['version']; + final date = release['date']; + final changes = release['changes'] as List; + + return TimelineTile( + nodePosition: 0.3, + oppositeContents: Container( + margin: EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + ' $version ', + style: TextStyle( + fontSize: 48.0, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.start, + ), + Text( + date, + style: TextStyle( + color: Colors.grey, + ), + textAlign: TextAlign.center, + ), + const Gap(16.0), + if (release['image'] != null) + CachedNetworkImage( + imageUrl: release['image'], + ), + ], + ), + ), + contents: Container( + decoration: BoxDecoration( + border: Border.all( + color: AdaptiveTheme.of(context).theme.dividerColor, + ), + borderRadius: BorderRadius.circular(16.0), + ), + margin: EdgeInsets.symmetric( + horizontal: 22.0, + vertical: 16.0, + ), + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: changes.map((change) { + final changeData = + change as Map; + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + _buildChangeCategoryChip( + changeData['category'], + ), + const Gap(8.0), + Text( + changeData['description'], + ), + ], + ), + ); + }).toList(), + ), + ], + ), + ), + node: TimelineNode( + indicator: OutlinedDotIndicator( + color: AdaptiveTheme.of(context).theme.dividerColor, + ), + startConnector: SolidLineConnector(), + endConnector: SolidLineConnector(), + ), + ); + }).toList(), + ), + ); + } else if (snapshot.hasError) { + return Text('Failed to load changelog data'); + } else { + return CircularProgressIndicator(); + } + }, + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text(AppLocalizations.of(context).closeButtonShared), + ), + ], + ); + } +} + +Future showChangelogDialog(BuildContext context) async { + return showDialog( + context: context, + builder: (context) { + return ChangelogDialog(); + }, + ); +} diff --git a/app/lib/frontend/screens/dashboard.dart b/app/lib/frontend/screens/dashboard.dart index d4c3f58..ab0eeee 100644 --- a/app/lib/frontend/screens/dashboard.dart +++ b/app/lib/frontend/screens/dashboard.dart @@ -1,10 +1,10 @@ import 'dart:io'; -import 'package:battery_plus/battery_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:adaptive_theme/adaptive_theme.dart'; +import 'package:battery_plus/battery_plus.dart'; import 'package:feedback/feedback.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:gap/gap.dart'; @@ -12,16 +12,17 @@ import 'package:gpu_info/gpu_info.dart'; import 'package:image/image.dart' as img; import 'package:open_local_ui/core/github.dart'; import 'package:open_local_ui/core/logger.dart'; +import 'package:open_local_ui/core/snackbar.dart'; import 'package:open_local_ui/core/update.dart'; import 'package:open_local_ui/frontend/components/floating_menu.dart'; +import 'package:open_local_ui/frontend/components/window_management_bar.dart'; +import 'package:open_local_ui/frontend/dialogs/changelog.dart'; import 'package:open_local_ui/frontend/dialogs/update.dart'; -import 'package:open_local_ui/core/snackbar.dart'; import 'package:open_local_ui/frontend/pages/dashboard/about.dart'; import 'package:open_local_ui/frontend/pages/dashboard/chat.dart'; import 'package:open_local_ui/frontend/pages/dashboard/models.dart'; import 'package:open_local_ui/frontend/pages/dashboard/sessions.dart'; import 'package:open_local_ui/frontend/pages/dashboard/settings.dart'; -import 'package:open_local_ui/frontend/components/window_management_bar.dart'; import 'package:path_provider/path_provider.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:system_info2/system_info2.dart'; @@ -285,9 +286,13 @@ class _DashboardScreenState extends State { ), const Gap(8), TextButton.icon( - onPressed: () { - showLicensePage(context: context); - }, + onPressed: () => showChangelogDialog(context), + icon: const Icon(UniconsLine.code_branch), + label: Text(AppLocalizations.of(context).changelogButton), + ), + const Gap(8), + TextButton.icon( + onPressed: () => showLicensePage(context: context), icon: const Icon(UniconsLine.keyhole_circle), label: Text(AppLocalizations.of(context).licenseButton), ), diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 4704b15..dbba464 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -128,6 +128,8 @@ flutter: - assets/prompts/sessions_title_generator.txt # Model Metadata - assets/metadata/ollama_models.json + # App metadata + - assets/metadata/app_changelog.json # Logos - assets/graphics/logos/open_local_ui.svg - assets/graphics/logos/flutter.svg