mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 09:08:40 +00:00
fix #257
This commit is contained in:
parent
afb1806cb1
commit
c18a8ed311
16 changed files with 194 additions and 10 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Changelog
|
||||
|
||||
## 0.0.58 (WIP)
|
||||
## 0.0.58
|
||||
|
||||
- twonly now has a free plan and is now financed by donations and an optional subscription with more features (coming soon)
|
||||
- Implementing iOS gestures to close images
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
|
|
@ -12,6 +16,7 @@ import 'package:twonly/src/views/components/app_outdated.dart';
|
|||
import 'package:twonly/src/views/home.view.dart';
|
||||
import 'package:twonly/src/views/onboarding/onboarding.view.dart';
|
||||
import 'package:twonly/src/views/onboarding/register.view.dart';
|
||||
import 'package:twonly/src/views/settings/help/changelog.view.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({super.key});
|
||||
|
|
|
|||
|
|
@ -330,5 +330,6 @@
|
|||
"appOutdatedBtn": "Jetzt aktualisieren.",
|
||||
"doubleClickToReopen": "Doppelklicken zum\nerneuten Öffnen.",
|
||||
"retransmissionRequested": "Wird erneut versucht.",
|
||||
"testPaymentMethod": "Vielen Dank für dein Interesse an einem kostenpflichtigen Tarif. Die kostenpflichtigen Pläne sind derzeit noch deaktiviert. Sie werden aber bald aktiviert!"
|
||||
"testPaymentMethod": "Vielen Dank für dein Interesse an einem kostenpflichtigen Tarif. Die kostenpflichtigen Pläne sind derzeit noch deaktiviert. Sie werden aber bald aktiviert!",
|
||||
"openChangeLog": "Changelog automatisch öffnen"
|
||||
}
|
||||
|
|
@ -486,5 +486,6 @@
|
|||
"appOutdatedBtn": "Update Now",
|
||||
"doubleClickToReopen": "Double-click\nto open again",
|
||||
"retransmissionRequested": "Retransmission requested",
|
||||
"testPaymentMethod": "Thanks for the interest in a paid plan. Currently the paid plans are still deactivated. But they will be activated soon!"
|
||||
"testPaymentMethod": "Thanks for the interest in a paid plan. Currently the paid plans are still deactivated. But they will be activated soon!",
|
||||
"openChangeLog": "Open changelog automatically"
|
||||
}
|
||||
|
|
@ -2023,6 +2023,12 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Thanks for the interest in a paid plan. Currently the paid plans are still deactivated. But they will be activated soon!'**
|
||||
String get testPaymentMethod;
|
||||
|
||||
/// No description provided for @openChangeLog.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Open changelog automatically'**
|
||||
String get openChangeLog;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -1073,4 +1073,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
@override
|
||||
String get testPaymentMethod =>
|
||||
'Vielen Dank für dein Interesse an einem kostenpflichtigen Tarif. Die kostenpflichtigen Pläne sind derzeit noch deaktiviert. Sie werden aber bald aktiviert!';
|
||||
|
||||
@override
|
||||
String get openChangeLog => 'Changelog automatisch öffnen';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1067,4 +1067,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get testPaymentMethod =>
|
||||
'Thanks for the interest in a paid plan. Currently the paid plans are still deactivated. But they will be activated soon!';
|
||||
|
||||
@override
|
||||
String get openChangeLog => 'Open changelog automatically';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ class UserData {
|
|||
|
||||
List<int>? lastChangeLogHash;
|
||||
|
||||
@JsonKey(defaultValue: false)
|
||||
bool hideChangeLog = false;
|
||||
|
||||
// --- BACKUP ---
|
||||
|
||||
DateTime? nextTimeToShowBackupNotice;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) => UserData(
|
|||
..lastChangeLogHash = (json['lastChangeLogHash'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList()
|
||||
..hideChangeLog = json['hideChangeLog'] as bool? ?? false
|
||||
..nextTimeToShowBackupNotice = json['nextTimeToShowBackupNotice'] == null
|
||||
? null
|
||||
: DateTime.parse(json['nextTimeToShowBackupNotice'] as String)
|
||||
|
|
@ -95,6 +96,7 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
|
|||
'currentPreKeyIndexStart': instance.currentPreKeyIndexStart,
|
||||
'currentSignedPreKeyIndexStart': instance.currentSignedPreKeyIndexStart,
|
||||
'lastChangeLogHash': instance.lastChangeLogHash,
|
||||
'hideChangeLog': instance.hideChangeLog,
|
||||
'nextTimeToShowBackupNotice':
|
||||
instance.nextTimeToShowBackupNotice?.toIso8601String(),
|
||||
'backupServer': instance.backupServer,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
|
|
@ -24,6 +27,7 @@ import 'package:twonly/src/views/components/initialsavatar.dart';
|
|||
import 'package:twonly/src/views/components/message_send_state_icon.dart';
|
||||
import 'package:twonly/src/views/components/notification_badge.dart';
|
||||
import 'package:twonly/src/views/components/user_context_menu.dart';
|
||||
import 'package:twonly/src/views/settings/help/changelog.view.dart';
|
||||
import 'package:twonly/src/views/settings/help/contact_us.view.dart';
|
||||
import 'package:twonly/src/views/settings/settings_main.view.dart';
|
||||
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
|
||||
|
|
@ -71,10 +75,26 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
});
|
||||
|
||||
final user = await getUser();
|
||||
if (user != null) {
|
||||
setState(() {
|
||||
showFeedbackShortcut = user.showFeedbackShortcut;
|
||||
if (user == null) return;
|
||||
setState(() {
|
||||
showFeedbackShortcut = user.showFeedbackShortcut;
|
||||
});
|
||||
|
||||
final changeLog = await rootBundle.loadString('CHANGELOG.md');
|
||||
final changeLogHash =
|
||||
(await compute(Sha256().hash, changeLog.codeUnits)).bytes;
|
||||
if (!user.hideChangeLog &&
|
||||
user.lastChangeLogHash.toString() != changeLogHash.toString()) {
|
||||
await updateUserdata((u) {
|
||||
u.lastChangeLogHash = changeLogHash;
|
||||
return u;
|
||||
});
|
||||
if (!mounted) return;
|
||||
await Navigator.push(context, MaterialPageRoute(builder: (context) {
|
||||
return ChangeLogView(
|
||||
changeLog: changeLog,
|
||||
);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class _AppearanceViewState extends State<AppearanceView> {
|
|||
ListTile(
|
||||
title: Text(context.lang.contactUsShortcut),
|
||||
onTap: toggleShowFeedbackIcon,
|
||||
trailing: Checkbox(
|
||||
trailing: Switch(
|
||||
value: !showFeedbackShortcut,
|
||||
onChanged: (a) => toggleShowFeedbackIcon(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class _DataAndStorageViewState extends State<DataAndStorageView> {
|
|||
title: Text(context.lang.settingsStorageDataStoreInGTitle),
|
||||
subtitle: Text(context.lang.settingsStorageDataStoreInGSubtitle),
|
||||
onTap: toggleStoreInGallery,
|
||||
trailing: Checkbox(
|
||||
trailing: Switch(
|
||||
value: storeMediaFilesInGallery,
|
||||
onChanged: (a) => toggleStoreInGallery(),
|
||||
),
|
||||
|
|
|
|||
129
lib/src/views/settings/help/changelog.view.dart
Normal file
129
lib/src/views/settings/help/changelog.view.dart
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
|
||||
List<Widget> parseMarkdown(BuildContext context, String markdown) {
|
||||
List<Widget> widgets = [];
|
||||
// Split the string into lines
|
||||
final lines = markdown.split('\n');
|
||||
|
||||
for (var line in lines) {
|
||||
line = line.trim();
|
||||
|
||||
// Check for headers
|
||||
if (line.startsWith('# ')) {
|
||||
// widgets.add(Padding(
|
||||
// padding: const EdgeInsets.all(8),
|
||||
// child: Text(
|
||||
// line.substring(2), // Remove the '# ' part
|
||||
// textAlign: TextAlign.center,
|
||||
// style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// ));
|
||||
} else if (line.startsWith('## ')) {
|
||||
widgets.add(Padding(
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 10),
|
||||
child: Text(
|
||||
line.substring(3), // Remove the '## ' part
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
));
|
||||
}
|
||||
// Check for bullet points
|
||||
else if (line.startsWith('- ')) {
|
||||
widgets.add(Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 7),
|
||||
child: Icon(
|
||||
Icons.brightness_1,
|
||||
size: 7,
|
||||
color: context.color.onSurface,
|
||||
),
|
||||
), // Bullet point icon
|
||||
const SizedBox(width: 8), // Space between bullet and text
|
||||
Expanded(child: Text(line.substring(2))), // Remove the '- ' part
|
||||
],
|
||||
));
|
||||
} else {
|
||||
widgets.add(Text(line));
|
||||
}
|
||||
}
|
||||
|
||||
return widgets;
|
||||
}
|
||||
|
||||
class ChangeLogView extends StatefulWidget {
|
||||
const ChangeLogView({super.key, this.changeLog});
|
||||
|
||||
final String? changeLog;
|
||||
|
||||
@override
|
||||
State<ChangeLogView> createState() => _ChangeLogViewState();
|
||||
}
|
||||
|
||||
class _ChangeLogViewState extends State<ChangeLogView> {
|
||||
String changeLog = '';
|
||||
bool hideChangeLog = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.changeLog != null) {
|
||||
changeLog = widget.changeLog!;
|
||||
} else {
|
||||
initAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> initAsync() async {
|
||||
changeLog = await rootBundle.loadString('CHANGELOG.md');
|
||||
final user = await getUser();
|
||||
if (user != null) {
|
||||
hideChangeLog = user.hideChangeLog;
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future<void> _toggleAutoOpen(bool value) async {
|
||||
await updateUserdata((u) {
|
||||
u.hideChangeLog = !hideChangeLog;
|
||||
return u;
|
||||
});
|
||||
setState(() {
|
||||
hideChangeLog = !value;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Changelog'),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: ListView(
|
||||
children: parseMarkdown(context, changeLog),
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(context.lang.openChangeLog),
|
||||
Switch(
|
||||
value: !hideChangeLog,
|
||||
onChanged: _toggleAutoOpen,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import 'package:twonly/globals.dart';
|
|||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||
import 'package:twonly/src/views/settings/help/changelog.view.dart';
|
||||
import 'package:twonly/src/views/settings/help/contact_us.view.dart';
|
||||
import 'package:twonly/src/views/settings/help/credits.view.dart';
|
||||
import 'package:twonly/src/views/settings/help/diagnostics.view.dart';
|
||||
|
|
@ -91,6 +92,15 @@ class HelpView extends StatelessWidget {
|
|||
}));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Changelog'),
|
||||
onTap: () async {
|
||||
await Navigator.push(context,
|
||||
MaterialPageRoute(builder: (context) {
|
||||
return const ChangeLogView();
|
||||
}));
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text("Open Source"),
|
||||
onTap: () {
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ class _ManageSubscriptionViewState extends State<ManageSubscriptionView> {
|
|||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
onTap: toggleRenewalOption,
|
||||
trailing: Checkbox(
|
||||
value: autoRenewal,
|
||||
trailing: Switch(
|
||||
value: autoRenewal!,
|
||||
onChanged: (a) {
|
||||
toggleRenewalOption();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -104,4 +104,5 @@ flutter:
|
|||
- assets/animated_icons/
|
||||
- assets/animations/
|
||||
- assets/passwords/
|
||||
- CHANGELOG.md
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue