feat: add changelogs, update old changelogs, update build scripts

This commit is contained in:
Anton Stubenbord
2023-10-10 19:22:41 +02:00
parent 162d50bf70
commit 2484bd2c7c
34 changed files with 413 additions and 54 deletions

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:paperless_mobile/generated/assets.gen.dart';
class PaperlessLogo extends StatelessWidget {
static const _paperlessGreen = Color(0xFF18541F);
@@ -25,15 +26,16 @@ class PaperlessLogo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
maxHeight: height ?? Theme.of(context).iconTheme.size ?? 32,
maxWidth: width ?? Theme.of(context).iconTheme.size ?? 32,
),
padding: const EdgeInsets.only(right: 8),
child: SvgPicture.asset(
"assets/logos/paperless_logo_white.svg",
color: _color,
),
);
constraints: BoxConstraints(
maxHeight: height ?? Theme.of(context).iconTheme.size ?? 32,
maxWidth: width ?? Theme.of(context).iconTheme.size ?? 32,
),
padding: const EdgeInsets.only(right: 8),
child: Assets.logos.paperlessLogoWhiteSvg.svg(
colorFilter: ColorFilter.mode(
_color,
BlendMode.srcIn,
),
));
}
}

View File

@@ -5,17 +5,20 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:paperless_mobile/constants.dart';
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
import 'package:paperless_mobile/core/global/asset_images.dart';
import 'package:paperless_mobile/core/widgets/hint_card.dart';
import 'package:paperless_mobile/core/widgets/paperless_logo.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
import 'package:paperless_mobile/features/sharing/cubit/receive_share_cubit.dart';
import 'package:paperless_mobile/generated/assets.gen.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/routes/typed/branches/documents_route.dart';
import 'package:paperless_mobile/routes/typed/branches/saved_views_route.dart';
import 'package:paperless_mobile/routes/typed/branches/upload_queue_route.dart';
import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/changelog_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/settings_route.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher_string.dart';
@@ -95,7 +98,7 @@ class AppDrawer extends StatelessWidget {
),
actionsAlignment: MainAxisAlignment.spaceBetween,
actions: [
Text("~ Anton"),
const Text("~ Anton"),
TextButton(
onPressed: Navigator.of(context).pop,
child: Text(S.of(context)!.gotIt),
@@ -105,6 +108,14 @@ class AppDrawer extends StatelessWidget {
);
},
),
ListTile(
dense: true,
leading: const Icon(Icons.history),
title: Text(S.of(context)!.changelog),
onTap: () {
ChangelogRoute().push(context);
},
),
ListTile(
dense: true,
leading: const Icon(Icons.bug_report_outlined),
@@ -127,9 +138,11 @@ class AppDrawer extends StatelessWidget {
),
ListTile(
dense: true,
leading: SvgPicture.asset(
"assets/images/github-mark.svg",
color: Theme.of(context).colorScheme.onBackground,
leading: Assets.images.githubMark.svg(
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onBackground,
BlendMode.srcIn,
),
height: 24,
width: 24,
),
@@ -215,7 +228,7 @@ class AppDrawer extends StatelessWidget {
const CreateSavedViewRoute(showInSidebar: true)
.push(context);
},
icon: Icon(Icons.add),
icon: const Icon(Icons.add),
label: Text(S.of(context)!.newView),
),
],
@@ -227,7 +240,7 @@ class AppDrawer extends StatelessWidget {
final view = sidebarViews[index];
return ListTile(
title: Text(view.name),
trailing: Icon(Icons.arrow_forward),
trailing: const Icon(Icons.arrow_forward),
onTap: () {
Scaffold.of(context).closeDrawer();
context

View File

@@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:go_router/go_router.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/theme.dart';
class ChangelogDialog extends StatelessWidget {
const ChangelogDialog({super.key});
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
actionsPadding: const EdgeInsets.all(4),
title: Text(S.of(context)!.changelog),
content: FutureBuilder<String>(
future: _loadChangelog(context),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
).padded(24);
}
return SizedBox(
width: 1000,
child: Markdown(
data: snapshot.data!,
),
);
},
),
actions: [
TextButton(
child: Text(S.of(context)!.close),
onPressed: () {
context.pop();
},
),
],
);
}
Future<String> _loadChangelog(BuildContext context) async {
final languageCode = Localizations.localeOf(context).languageCode;
final locale = switch (languageCode) {
'de' => 'de-DE',
_ => 'en-US',
};
'en-US';
String changelog = await rootBundle.loadString(
'assets/changelogs/changelogs_$locale.md',
);
for (var versionNumber in _versionNumbers.keys) {
changelog = changelog.replaceFirst(
RegExp('# $versionNumber'),
'# v${_versionNumbers[versionNumber]!}',
);
}
return changelog;
}
}
const _versionNumbers = {
"53": "3.0.6",
"52": "3.0.5",
"51": "3.0.4",
"50": "3.0.3",
"49": "3.0.2",
"48": "3.0.1",
"47": "3.0.0",
"46": "2.3.11",
"45": "2.3.10",
"44": "2.3.9",
"43": "2.3.8",
"42": "2.3.7",
"41": "2.3.6",
"40": "2.3.5",
"39": "2.3.4",
"38": "2.3.3",
"37": "2.3.2",
"36": "2.3.1",
"35": "2.3.0",
"34": "2.2.6",
"33": "2.2.5",
"32": "2.2.4",
"31": "2.2.3",
"30": "2.2.2",
"29": "2.2.1",
"28": "2.2.0",
"27": "2.1.0",
"26": "2.0.9",
"25": "2.0.8",
"24": "2.0.7",
"23": "2.0.6",
"22": "2.0.5",
"21": "2.0.4",
"20": "2.0.3",
"19": "2.0.2",
"18": "2.0.1",
"17": "2.0.0",
"16": "1.5.3",
"15": "1.5.2",
"14": "1.5.1",
"13": "1.5.0",
"12": "1.4.1",
"11": "1.4.0",
"10": "1.3.1",
"9": "1.3.0",
"8": "1.2.2",
"7": "1.2.1",
"6": "1.2.0",
"5": "1.1.0",
"3": "1.0.5",
"4": "1.0.6",
"2": "1.0.4",
};

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/constants.dart';
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
@@ -14,6 +15,14 @@ import 'package:paperless_mobile/routes/typed/branches/documents_route.dart';
import 'package:paperless_mobile/routes/typed/branches/inbox_route.dart';
import 'package:paperless_mobile/routes/typed/branches/saved_views_route.dart';
import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/changelog_route.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Changelog {
final int buildNumber;
final String? changelog;
Changelog(this.buildNumber, this.changelog);
}
class LandingPage extends StatefulWidget {
const LandingPage({super.key});
@@ -25,6 +34,34 @@ class LandingPage extends StatefulWidget {
class _LandingPageState extends State<LandingPage> {
final _searchBarHandle = SliverOverlapAbsorberHandle();
Future<bool> get _shouldShowChangelog async {
try {
final sp = await SharedPreferences.getInstance();
final currentBuild = packageInfo.buildNumber;
final _existingVersions =
sp.getStringList('changelogSeenForBuilds') ?? [];
if (_existingVersions.contains(currentBuild)) {
return false;
} else {
_existingVersions.add(currentBuild);
await sp.setStringList('changelogSeenForBuilds', _existingVersions);
return true;
}
} catch (e) {
return false;
}
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
if (await _shouldShowChangelog) {
ChangelogRoute().push(context);
}
});
}
@override
Widget build(BuildContext context) {
final currentUser = context.watch<LocalUserAccount>().paperlessUser;
@@ -187,18 +224,19 @@ class _LandingPageState extends State<LandingPage> {
titleTextStyle: Theme.of(context).textTheme.labelLarge,
title: Text(S.of(context)!.totalCharacters),
trailing: Text(
stats.totalChars.toString(),
(stats.totalChars ?? 0).toString(),
style: Theme.of(context).textTheme.labelLarge,
),
),
),
AspectRatio(
aspectRatio: 1.3,
child: SizedBox(
width: 300,
child: MimeTypesPieChart(statistics: stats),
if (stats.fileTypeCounts.isNotEmpty)
AspectRatio(
aspectRatio: 1.3,
child: SizedBox(
width: 300,
child: MimeTypesPieChart(statistics: stats),
),
),
),
],
).padded(16);
},

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "Tens canvis sense desar. Si continues es perdran. Vols descartar els canvis?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "Du hast ungespeicherte Änderungen. Diese gehen verloren, falls du fortfährst. Möchtest du die Änderungen verwerfen?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -1000,5 +1000,6 @@
"discardChangesWarning": "You have unsaved changes. By continuing, all changes will be lost. Do you want to discard these changes?",
"@discardChangesWarning": {
"description": "Warning message shown when the user tries to close a route without saving the changes."
}
},
"changelog": "Changelog"
}

View File

@@ -6,6 +6,7 @@ import 'package:device_info_plus/device_info_plus.dart';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
@@ -39,6 +40,7 @@ import 'package:paperless_mobile/routes/navigation_keys.dart';
import 'package:paperless_mobile/routes/typed/branches/landing_route.dart';
import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/add_account_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/changelog_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/logging_out_route.dart';
import 'package:paperless_mobile/routes/typed/top_level/login_route.dart';
import 'package:paperless_mobile/theme.dart';
@@ -89,6 +91,7 @@ Future<void> performMigrations() async {
}
}
Future<void> _initHive() async {
await Hive.initFlutter();
@@ -316,6 +319,7 @@ class _GoRouterShellState extends State<GoRouterShell> {
$loginRoute,
$loggingOutRoute,
$addAccountRoute,
$changelogRoute,
$authenticatedRoute,
],
),

View File

@@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:paperless_mobile/features/changelogs/view/changelog_dialog.dart';
import 'package:paperless_mobile/routes/navigation_keys.dart';
import 'package:paperless_mobile/routes/utils/dialog_page.dart';
part 'changelog_route.g.dart';
@TypedGoRoute<ChangelogRoute>(path: '/changelogs)')
class ChangelogRoute extends GoRouteData {
static final $parentNavigatorKey = rootNavigatorKey;
@override
Page<void> buildPage(BuildContext context, GoRouterState state) {
return DialogPage(
builder: (context) => const ChangelogDialog(),
);
}
}

View File

@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
class DialogPage<T> extends Page<T> {
final Offset? anchorPoint;
final Color? barrierColor;
final bool barrierDismissible;
final String? barrierLabel;
final bool useSafeArea;
final CapturedThemes? themes;
final WidgetBuilder builder;
const DialogPage({
required this.builder,
this.anchorPoint,
this.barrierColor = Colors.black38,
this.barrierDismissible = true,
this.barrierLabel,
this.useSafeArea = true,
this.themes,
super.key,
super.name,
super.arguments,
super.restorationId,
});
@override
Route<T> createRoute(BuildContext context) => DialogRoute<T>(
context: context,
settings: this,
builder: (context) => Dialog(
child: builder(context),
),
anchorPoint: anchorPoint,
barrierColor: barrierColor,
barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel,
useSafeArea: useSafeArea,
themes: themes,
);
}

View File

@@ -82,12 +82,14 @@ SystemUiOverlayStyle buildOverlayStyle(
Brightness.light => SystemUiOverlayStyle.dark.copyWith(
systemNavigationBarColor: color,
systemNavigationBarDividerColor: color,
statusBarColor: theme.colorScheme.background,
// statusBarColor: theme.colorScheme.background,
// systemNavigationBarDividerColor: theme.colorScheme.surface,
),
Brightness.dark => SystemUiOverlayStyle.light.copyWith(
systemNavigationBarColor: color,
systemNavigationBarDividerColor: color,
statusBarColor: theme.colorScheme.background,
// statusBarColor: theme.colorScheme.background,
// systemNavigationBarDividerColor: theme.colorScheme.surface,
),