switch to go_router

This commit is contained in:
otsmr 2026-02-09 23:45:34 +01:00
parent dbc3ee62d0
commit 61a5352bb8
42 changed files with 632 additions and 793 deletions

View file

@ -5,7 +5,6 @@
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:enableOnBackInvokedCallback="true"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""

View file

@ -7,8 +7,11 @@ import 'package:twonly/globals.dart';
import 'package:twonly/src/localization/generated/app_localizations.dart';
import 'package:twonly/src/providers/connection.provider.dart';
import 'package:twonly/src/providers/purchases.provider.dart';
import 'package:twonly/src/providers/routing.provider.dart';
import 'package:twonly/src/providers/settings.provider.dart';
import 'package:twonly/src/services/subscription.service.dart';
import 'package:twonly/src/themes/dark.dart';
import 'package:twonly/src/themes/light.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/pow.dart';
import 'package:twonly/src/utils/storage.dart';
@ -16,7 +19,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/backup/twonly_safe_backup.view.dart';
import 'package:twonly/src/views/settings/backup/setup_backup.view.dart';
import 'package:twonly/src/views/updates/62_database_migration.view.dart';
class App extends StatefulWidget {
@ -93,50 +96,24 @@ class _AppState extends State<App> with WidgetsBindingObserver {
return ListenableBuilder(
listenable: context.watch<SettingsChangeProvider>(),
builder: (BuildContext context, Widget? child) {
return MaterialApp(
return MaterialApp.router(
routerConfig: routerProvider,
scaffoldMessengerKey: globalRootScaffoldMessengerKey,
restorationScopeId: 'app',
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
debugShowCheckedModeBanner: false,
supportedLocales: const [
Locale('en', ''),
Locale('de', ''),
],
onGenerateTitle: (BuildContext context) => 'twonly',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF57CC99),
),
pageTransitionsTheme: const PageTransitionsTheme(
builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
},
),
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
),
darkTheme: ThemeData.dark().copyWith(
colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark,
seedColor: const Color(0xFF57CC99),
surface: const Color.fromARGB(255, 20, 18, 23),
surfaceContainer: const Color.fromARGB(255, 33, 30, 39),
),
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
),
title: 'twonly',
theme: lightTheme,
darkTheme: darkTheme,
themeMode: context.watch<SettingsChangeProvider>().themeMode,
initialRoute: '/',
routes: {
'/': (context) => const AppMainWidget(initialPage: 1),
'/chats': (context) => const AppMainWidget(initialPage: 0),
},
);
},
);
@ -213,7 +190,7 @@ class _AppMainWidgetState extends State<AppMainWidget> {
child = const DatabaseMigrationView();
} else if (_isUserCreated) {
if (gUser.twonlySafeBackup == null && !_skipBackup && kReleaseMode) {
child = TwonlyIdentityBackupView(
child = SetupBackupView(
callBack: () {
_skipBackup = true;
setState(() {});

View file

@ -0,0 +1,55 @@
class Routes {
static const String home = '/';
static const String chats = '/chats';
static const String chatsAddNewUser = '/chats/add_new_user';
static const String chatsArchived = '/chats/archived';
static const String chatsStartNewChat = '/chats/start_new_chat';
static const String chatsCameraSendTo = '/chats/camera_send_to';
static const String chatsMediaViewer = '/chats/media_viewer';
static const String chatsMessages = '/chats/messages';
static String groupCreateSelectMember(String? groupId) =>
'/group/create/select_member${groupId == null ? '' : '/$groupId'}';
static String profileGroup(String groupId) => '/profile/group/$groupId';
static String profileContact(int contactId) => '/profile/contact/$contactId';
static const String cameraQRScanner = '/camera/qr_scanner';
static const String settings = '/settings';
static const String settingsProfile = '/settings/profile';
static const String settingsPublicProfile = '/settings/public_profile';
static const String settingsProfileModifyAvatar =
'/settings/profile/modify_avatar';
static const String settingsAccount = '/settings/account';
static const String settingsSubscription = '/settings/subscription';
static const String settingsBackup = '/settings/backup';
static const String settingsBackupServer = '/settings/backup/server';
static const String settingsBackupRecovery = '/settings/backup/recovery';
static const String settingsBackupSetup = '/settings/backup/setup';
static const String settingsAppearance = '/settings/appearance';
static const String settingsChats = '/settings/chats';
static const String settingsChatsReactions = '/settings/chats/reactions';
static const String settingsPrivacy = '/settings/privacy';
static const String settingsPrivacyBlockUsers =
'/settings/privacy/block_users';
static const String settingsNotification = '/settings/notification';
static const String settingsStorage = '/settings/storage_data';
static const String settingsStorageImport = '/settings/storage_data/import';
static const String settingsStorageExport = '/settings/storage_data/export';
static const String settingsHelp = '/settings/help';
static const String settingsHelpFaq = '/settings/help/faq';
static const String settingsHelpContactUs = '/settings/help/contact_us';
static const String settingsHelpDiagnostics = '/settings/help/diagnostics';
static const String settingsHelpUserStudy = '/settings/help/user_study';
static const String settingsHelpUserStudyQuestionnaire =
'/settings/help/user_study/questionnaire';
static const String settingsHelpCredits = '/settings/help/credits';
static const String settingsHelpChangelog = '/settings/help/changelog';
static const String settingsDeveloper = '/settings/developer';
static const String settingsDeveloperRetransmissionDatabase =
'/settings/developer/retransmission_database';
static const String settingsDeveloperAutomatedTesting =
'/settings/developer/automated_testing';
static const String settingsInvite = '/settings/invite';
}

View file

@ -0,0 +1,285 @@
import 'package:go_router/go_router.dart';
import 'package:twonly/app.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/views/camera/camera_qr_scanner.view.dart';
import 'package:twonly/src/views/camera/camera_send_to.view.dart';
import 'package:twonly/src/views/chats/add_new_user.view.dart';
import 'package:twonly/src/views/chats/archived_chats.view.dart';
import 'package:twonly/src/views/chats/chat_messages.view.dart';
import 'package:twonly/src/views/chats/media_viewer.view.dart';
import 'package:twonly/src/views/chats/start_new_chat.view.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
import 'package:twonly/src/views/groups/group.view.dart';
import 'package:twonly/src/views/groups/group_create_select_members.view.dart';
import 'package:twonly/src/views/onboarding/recover.view.dart';
import 'package:twonly/src/views/public_profile.view.dart';
import 'package:twonly/src/views/settings/account.view.dart';
import 'package:twonly/src/views/settings/appearance.view.dart';
import 'package:twonly/src/views/settings/backup/backup.view.dart';
import 'package:twonly/src/views/settings/backup/backup_server.view.dart';
import 'package:twonly/src/views/settings/backup/setup_backup.view.dart';
import 'package:twonly/src/views/settings/chat/chat_reactions.view.dart';
import 'package:twonly/src/views/settings/chat/chat_settings.view.dart';
import 'package:twonly/src/views/settings/data_and_storage.view.dart';
import 'package:twonly/src/views/settings/data_and_storage/export_media.view.dart';
import 'package:twonly/src/views/settings/data_and_storage/import_media.view.dart';
import 'package:twonly/src/views/settings/developer/automated_testing.view.dart';
import 'package:twonly/src/views/settings/developer/developer.view.dart';
import 'package:twonly/src/views/settings/developer/retransmission_data.view.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';
import 'package:twonly/src/views/settings/help/faq.view.dart';
import 'package:twonly/src/views/settings/help/help.view.dart';
import 'package:twonly/src/views/settings/notification.view.dart';
import 'package:twonly/src/views/settings/privacy.view.dart';
import 'package:twonly/src/views/settings/privacy_view_block.view.dart';
import 'package:twonly/src/views/settings/profile/modify_avatar.view.dart';
import 'package:twonly/src/views/settings/profile/profile.view.dart';
import 'package:twonly/src/views/settings/settings_main.view.dart';
import 'package:twonly/src/views/settings/share_with_friends.view.dart';
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
import 'package:twonly/src/views/user_study/user_study_questionnaire.view.dart';
import 'package:twonly/src/views/user_study/user_study_welcome.view.dart';
final routerProvider = GoRouter(
routes: [
GoRoute(
path: Routes.home,
builder: (context, state) => const AppMainWidget(initialPage: 1),
),
// Chats
GoRoute(
path: Routes.chats,
builder: (context, state) => const AppMainWidget(initialPage: 0),
routes: [
GoRoute(
path: 'add_new_user',
builder: (context, state) => const AddNewUserView(),
),
GoRoute(
path: 'archived',
builder: (context, state) => const ArchivedChatsView(),
),
GoRoute(
path: 'start_new_chat',
builder: (context, state) => const StartNewChatView(),
),
GoRoute(
path: 'camera_send_to',
builder: (context, state) {
final group = state.extra! as Group;
return CameraSendToView(group);
},
),
GoRoute(
path: 'media_viewer',
builder: (context, state) {
final group = state.extra! as Group;
return MediaViewerView(group);
},
),
GoRoute(
path: 'messages',
builder: (context, state) {
final group = state.extra! as Group;
return ChatMessagesView(group);
},
),
],
),
GoRoute(
path: '/profile/contact/:contactId',
builder: (context, state) {
final contactId = state.pathParameters['contactId']!;
return ContactView(int.parse(contactId));
},
),
GoRoute(
path: '/profile/group/:groupId',
builder: (context, state) {
final groupId = state.pathParameters['groupId']!;
return GroupView(groupId);
},
),
GoRoute(
path: '/group/create/select_member',
builder: (context, state) {
return const GroupCreateSelectMembersView();
},
routes: [
GoRoute(
path: ':groupId',
builder: (context, state) {
final groupId = state.pathParameters['groupId'];
return GroupCreateSelectMembersView(groupId: groupId);
},
),
],
),
GoRoute(
path: Routes.cameraQRScanner,
builder: (context, state) {
return const QrCodeScannerView();
},
),
// settings
GoRoute(
path: Routes.settings,
builder: (context, state) => const SettingsMainView(),
routes: [
GoRoute(
path: 'profile',
builder: (context, state) => const ProfileView(),
routes: [
GoRoute(
path: 'modify_avatar',
builder: (context, state) => const ModifyAvatarView(),
)
],
),
GoRoute(
path: 'public_profile',
builder: (context, state) => const PublicProfileView(),
),
GoRoute(
path: 'account',
builder: (context, state) => const AccountView(),
),
GoRoute(
path: 'subscription',
builder: (context, state) => const SubscriptionView(),
),
GoRoute(
path: 'backup',
builder: (context, state) => const BackupView(),
routes: [
GoRoute(
path: 'server',
builder: (context, state) => const BackupServerView(),
),
GoRoute(
path: 'recovery',
builder: (context, state) => const BackupRecoveryView(),
),
GoRoute(
path: 'setup',
builder: (context, state) => SetupBackupView(
isPasswordChangeOnly: state.extra as bool? ?? false,
),
),
],
),
GoRoute(
path: 'appearance',
builder: (context, state) => const AppearanceView(),
),
GoRoute(
path: 'chats',
builder: (context, state) => const ChatSettingsView(),
routes: [
GoRoute(
path: 'reactions',
builder: (context, state) => const ChatReactionSelectionView(),
),
],
),
GoRoute(
path: 'privacy',
builder: (context, state) => const PrivacyView(),
routes: [
GoRoute(
path: 'block_users',
builder: (context, state) => const PrivacyViewBlockUsersView(),
)
],
),
GoRoute(
path: 'notification',
builder: (context, state) => const NotificationView(),
),
GoRoute(
path: 'storage_data',
builder: (context, state) => const DataAndStorageView(),
routes: [
GoRoute(
path: 'import',
builder: (context, state) => const ImportMediaView(),
),
GoRoute(
path: 'export',
builder: (context, state) => const ExportMediaView(),
),
],
),
GoRoute(
path: 'help',
builder: (context, state) => const HelpView(),
routes: [
GoRoute(
path: 'faq',
builder: (context, state) => const FaqView(),
),
GoRoute(
path: 'contact_us',
builder: (context, state) => const ContactUsView(),
),
GoRoute(
path: 'diagnostics',
builder: (context, state) => const DiagnosticsView(),
),
GoRoute(
path: 'user_study',
builder: (context, state) => UserStudyWelcomeView(
wasOpenedAutomatic: state.extra as bool? ?? false,
),
routes: [
GoRoute(
path: 'questionnaire',
builder: (context, state) =>
const UserStudyQuestionnaireView(),
),
],
),
GoRoute(
path: 'credits',
builder: (context, state) => const CreditsView(),
),
GoRoute(
path: 'changelog',
builder: (context, state) => ChangeLogView(
changeLog: state.extra as String?,
),
),
],
),
GoRoute(
path: 'developer',
builder: (context, state) => const DeveloperSettingsView(),
routes: [
GoRoute(
path: 'retransmission_database',
builder: (context, state) => const RetransmissionDataView(),
),
GoRoute(
path: 'automated_testing',
builder: (context, state) => const AutomatedTestingView(),
),
],
),
GoRoute(
path: 'invite',
builder: (context, state) => const ShareWithFriendsView(),
),
],
),
],
);

View file

@ -5,8 +5,11 @@ import 'dart:typed_data';
import 'package:collection/collection.dart';
import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/services/api/mediafiles/upload.service.dart';
@ -16,8 +19,6 @@ import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/camera/share_image_editor.view.dart';
import 'package:twonly/src/views/chats/add_new_user.view.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
import 'package:twonly/src/views/public_profile.view.dart';
Future<bool> handleIntentUrl(BuildContext context, Uri uri) async {
if (!uri.scheme.startsWith('http')) return false;
@ -32,14 +33,7 @@ Future<bool> handleIntentUrl(BuildContext context, Uri uri) async {
if (!context.mounted) return false;
if (username == gUser.username) {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
await context.push(Routes.settingsPublicProfile);
return true;
}
@ -91,14 +85,7 @@ Future<bool> handleIntentUrl(BuildContext context, Uri uri) async {
);
}
} else {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ContactView(contact.userId);
},
),
);
await context.push(Routes.profileContact(contact.userId));
}
} else {
await showAlertDialog(
@ -149,6 +136,27 @@ Future<void> handleIntentMediaFile(
);
}
StreamSubscription<List<SharedFile>> initIntentStreams(
BuildContext context,
void Function(Uri) onUrlCallBack,
) {
FlutterSharingIntent.instance.getInitialSharing().then((f) {
if (!context.mounted) return;
handleIntentSharedFile(context, f, onUrlCallBack);
});
return FlutterSharingIntent.instance.getMediaStream().listen(
(f) {
if (!context.mounted) return;
handleIntentSharedFile(context, f, onUrlCallBack);
},
// ignore: inference_failure_on_untyped_parameter
onError: (err) {
Log.error('getIntentDataStream error: $err');
},
);
}
Future<void> handleIntentSharedFile(
BuildContext context,
List<SharedFile> files,

13
lib/src/themes/dark.dart Normal file
View file

@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
final ThemeData darkTheme = ThemeData.dark().copyWith(
colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark,
seedColor: const Color(0xFF57CC99),
surface: const Color.fromARGB(255, 20, 18, 23),
surfaceContainer: const Color.fromARGB(255, 33, 30, 39),
),
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
);

10
lib/src/themes/light.dart Normal file
View file

@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
final ThemeData lightTheme = ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF57CC99),
),
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
);

View file

@ -4,13 +4,13 @@ import 'package:twonly/src/views/camera/camera_preview_components/camera_preview
import 'package:twonly/src/views/camera/camera_preview_components/camera_preview_controller_view.dart';
import 'package:twonly/src/views/camera/camera_preview_components/main_camera_controller.dart';
class QrCodeScanner extends StatefulWidget {
const QrCodeScanner({super.key});
class QrCodeScannerView extends StatefulWidget {
const QrCodeScannerView({super.key});
@override
State<QrCodeScanner> createState() => QrCodeScannerState();
State<QrCodeScannerView> createState() => QrCodeScannerViewState();
}
class QrCodeScannerState extends State<QrCodeScanner> {
class QrCodeScannerViewState extends State<QrCodeScannerView> {
final MainCameraController _mainCameraController = MainCameraController();
@override

View file

@ -4,28 +4,21 @@ 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:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/providers/connection.provider.dart';
import 'package:twonly/src/providers/purchases.provider.dart';
import 'package:twonly/src/services/subscription.service.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/chats/add_new_user.view.dart';
import 'package:twonly/src/views/chats/archived_chats.view.dart';
import 'package:twonly/src/views/chats/chat_list_components/connection_info.comp.dart';
import 'package:twonly/src/views/chats/chat_list_components/feedback_btn.dart';
import 'package:twonly/src/views/chats/chat_list_components/group_list_item.dart';
import 'package:twonly/src/views/chats/start_new_chat.view.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/notification_badge.dart';
import 'package:twonly/src/views/public_profile.view.dart';
import 'package:twonly/src/views/settings/help/changelog.view.dart';
import 'package:twonly/src/views/settings/profile/profile.view.dart';
import 'package:twonly/src/views/settings/settings_main.view.dart';
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
import 'package:twonly/src/views/user_study/user_study_welcome.view.dart';
class ChatListView extends StatefulWidget {
const ChatListView({super.key});
@ -64,15 +57,9 @@ class _ChatListViewState extends State<ChatListView> {
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (gUser.subscriptionPlan == SubscriptionPlan.Tester.name &&
!gUser.askedForUserStudyPermission) {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const UserStudyWelcomeView(
wasOpenedAutomatic: true,
);
},
),
await context.push(
Routes.settingsHelpUserStudy,
extra: true,
);
}
@ -89,15 +76,9 @@ class _ChatListViewState extends State<ChatListView> {
// only show changelog to people who already have contacts
// this prevents that this is shown directly after the user registered
if (_groupsNotPinned.isNotEmpty) {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ChangeLogView(
changeLog: changeLog,
);
},
),
await context.push(
Routes.settingsHelpChangelog,
extra: changeLog,
);
}
}
@ -120,14 +101,7 @@ class _ChatListViewState extends State<ChatListView> {
children: [
GestureDetector(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ProfileView();
},
),
);
await context.push(Routes.settingsProfile);
if (!mounted) return;
setState(() {}); // gUser has updated
},
@ -141,16 +115,7 @@ class _ChatListViewState extends State<ChatListView> {
const Text('twonly '),
if (plan != SubscriptionPlan.Free)
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const SubscriptionView();
},
),
);
},
onTap: () => context.push(Routes.settingsSubscription),
child: Container(
decoration: BoxDecoration(
color: context.color.primary,
@ -184,28 +149,15 @@ class _ChatListViewState extends State<ChatListView> {
child: IconButton(
key: searchForOtherUsers,
icon: const FaIcon(FontAwesomeIcons.userPlus, size: 18),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AddNewUserView(),
),
);
},
onPressed: () => context.push(Routes.chatsAddNewUser),
),
);
},
),
IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SettingsMainView(),
),
);
if (!mounted) return;
setState(() {}); // gUser may has changed...
await context.push(Routes.settings);
if (mounted) setState(() {}); // gUser may has changed...
},
icon: const FaIcon(FontAwesomeIcons.gear, size: 19),
),
@ -234,14 +186,7 @@ class _ChatListViewState extends State<ChatListView> {
padding: const EdgeInsets.all(10),
child: OutlinedButton.icon(
icon: const Icon(Icons.person_add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AddNewUserView(),
),
);
},
onPressed: () => context.push(Routes.chatsAddNewUser),
label: Text(
context.lang.chatListViewSearchUserNameBtn,
),
@ -265,16 +210,7 @@ class _ChatListViewState extends State<ChatListView> {
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 13),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ArchivedChatsView();
},
),
);
},
onTap: () => context.push(Routes.chatsArchived),
);
}
// Check if the index is for the pinned users
@ -320,16 +256,7 @@ class _ChatListViewState extends State<ChatListView> {
color: context.color.primary,
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
},
onTap: () => context.push(Routes.settingsPublicProfile),
child: SizedBox(
width: 45,
height: 45,
@ -345,16 +272,7 @@ class _ChatListViewState extends State<ChatListView> {
const SizedBox(height: 12),
FloatingActionButton(
backgroundColor: context.color.primary,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const StartNewChatView();
},
),
);
},
onPressed: () => context.push(Routes.chatsStartNewChat),
child: FaIcon(
FontAwesomeIcons.penToSquare,
color: isDarkMode(context) ? Colors.black : Colors.white,

View file

@ -1,10 +1,10 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/settings/help/contact_us.view.dart';
class FeedbackIconButton extends StatefulWidget {
const FeedbackIconButton({super.key});
@ -37,14 +37,7 @@ class _FeedbackIconButtonState extends State<FeedbackIconButton> {
}
return IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ContactUsView(),
),
);
},
onPressed: () => context.push(Routes.settingsHelpContactUs),
color: Colors.grey,
tooltip: context.lang.feedbackTooltip,
icon: const FaIcon(FontAwesomeIcons.commentDots, size: 19),

View file

@ -1,24 +1,22 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:mutex/mutex.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/database/tables/messages.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/camera/camera_send_to.view.dart';
import 'package:twonly/src/views/chats/chat_list_components/last_message_time.dart';
import 'package:twonly/src/views/chats/chat_messages.view.dart';
import 'package:twonly/src/views/chats/chat_messages_components/message_send_state_icon.dart';
import 'package:twonly/src/views/chats/media_viewer.view.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/views/components/group_context_menu.component.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
import 'package:twonly/src/views/groups/group.view.dart';
class GroupListItem extends StatefulWidget {
const GroupListItem({
@ -161,13 +159,9 @@ class _UserListItem extends State<GroupListItem> {
Future<void> onTap() async {
if (_currentMessage == null && widget.group.totalMediaCounter == 0) {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return CameraSendToView(widget.group);
},
),
await context.push(
Routes.chatsCameraSendTo,
extra: widget.group,
);
return;
}
@ -185,26 +179,18 @@ class _UserListItem extends State<GroupListItem> {
}
if (mediaFile.downloadState! == DownloadState.ready) {
if (!mounted) return;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MediaViewerView(widget.group);
},
),
await context.push(
Routes.chatsMediaViewer,
extra: widget.group,
);
return;
}
}
}
if (!mounted) return;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ChatMessagesView(widget.group);
},
),
await context.push(
Routes.chatsMessages,
extra: widget.group,
);
}
@ -250,42 +236,27 @@ class _UserListItem extends State<GroupListItem> {
),
leading: GestureDetector(
onTap: () async {
Widget pushWidget = GroupView(widget.group);
if (widget.group.isDirectChat) {
final contacts = await twonlyDB.groupsDao
.getGroupContact(widget.group.groupId);
pushWidget = ContactView(contacts.first.userId);
}
if (!context.mounted) return;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return pushWidget;
},
),
);
await context.push(Routes.profileContact(contacts.first.userId));
return;
} else {
await context.push(Routes.profileGroup(widget.group.groupId));
}
},
child: AvatarIcon(group: widget.group),
),
trailing: (widget.group.leftGroup)
? null
: IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
if (_hasNonOpenedMediaFile) {
return ChatMessagesView(widget.group);
} else {
return CameraSendToView(widget.group);
}
},
onPressed: () => context.push(
_hasNonOpenedMediaFile
? Routes.chatsMessages
: Routes.chatsCameraSendTo,
extra: widget.group,
),
);
},
icon: FaIcon(
_hasNonOpenedMediaFile
? FontAwesomeIcons.solidComments

View file

@ -1,11 +1,12 @@
import 'dart:async';
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:mutex/mutex.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/database/tables/messages.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
@ -21,8 +22,6 @@ import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/blink.component.dart';
import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/views/components/verified_shield.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
import 'package:twonly/src/views/groups/group.view.dart';
Color getMessageColor(Message message) {
return (message.senderId == null)
@ -291,23 +290,10 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
await twonlyDB.groupsDao.getAllGroupMembers(group.groupId);
if (!context.mounted) return;
if (member.isEmpty) return;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ContactView(member.first.contactId);
},
),
);
await context
.push(Routes.profileContact(member.first.contactId));
} else {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return GroupView(group);
},
),
);
await context.push(Routes.profileGroup(group.groupId));
}
},
child: Row(

View file

@ -1,7 +1,9 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/database/tables/messages.table.dart'
hide MessageActions;
@ -17,7 +19,6 @@ import 'package:twonly/src/views/chats/chat_messages_components/message_actions.
import 'package:twonly/src/views/chats/chat_messages_components/message_context_menu.dart';
import 'package:twonly/src/views/chats/chat_messages_components/response_container.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
class ChatListEntry extends StatefulWidget {
const ChatListEntry({
@ -204,15 +205,9 @@ class _ChatListEntryState extends State<ChatListEntry> {
hideContactAvatar
? const SizedBox(width: 24)
: GestureDetector(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ContactView(widget.message.senderId!),
onTap: () => context.push(
Routes.profileContact(widget.message.senderId!),
),
);
},
child: AvatarIcon(
contactId: widget.message.senderId,
fontSize: 12,

View file

@ -2,13 +2,14 @@ import 'dart:collection';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/database/tables/messages.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
enum MessageSendState {
received,
@ -163,16 +164,7 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
style: const TextStyle(fontSize: 9),
);
onTap = () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const SubscriptionView();
},
),
);
};
onTap = () => context.push(Routes.settingsSubscription);
}
if (mediaFile.uploadState == UploadState.preprocessing ||
mediaFile.uploadState == UploadState.initialized) {

View file

@ -2,17 +2,17 @@ import 'dart:async';
import 'package:drift/drift.dart' hide Column;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/chats/add_new_user.view.dart';
import 'package:twonly/src/views/chats/chat_messages.view.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/views/components/group_context_menu.component.dart';
import 'package:twonly/src/views/components/user_context_menu.component.dart';
import 'package:twonly/src/views/groups/group_create_select_members.view.dart';
class StartNewChatView extends StatefulWidget {
const StartNewChatView({super.key});
@ -165,15 +165,8 @@ class _StartNewChatView extends State<StartNewChatView> {
size: 13,
),
),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const GroupCreateSelectMembersView(),
),
);
},
onTap: () => context
.push(Routes.groupCreateSelectMember(null)),
);
}
if (i == 1) {
@ -185,14 +178,7 @@ class _StartNewChatView extends State<StartNewChatView> {
size: 13,
),
),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AddNewUserView(),
),
);
},
onTap: () => context.push(Routes.chatsAddNewUser),
);
}
if (i == 2) {

View file

@ -1,10 +1,11 @@
import 'package:drift/drift.dart' hide Column;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/chats/chat_messages.view.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/components/context_menu.component.dart';
@ -45,16 +46,10 @@ class GroupContextMenu extends StatelessWidget {
),
ContextMenuItem(
title: context.lang.contextMenuOpenChat,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ChatMessagesView(group);
},
onTap: () => context.push(
Routes.chatsMessages,
extra: group,
),
);
},
icon: FontAwesomeIcons.comments,
),
if (!group.archived)

View file

@ -2,7 +2,9 @@ import 'dart:async';
import 'package:clock/clock.dart';
import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/services/flame.service.dart';
import 'package:twonly/src/services/subscription.service.dart';
@ -10,7 +12,6 @@ import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
class MaxFlameListTitle extends StatefulWidget {
const MaxFlameListTitle({
@ -46,14 +47,7 @@ class _MaxFlameListTitleState extends State<MaxFlameListTitle> {
Future<void> _restoreFlames() async {
if (!isPayingUser(getCurrentPlan())) {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const SubscriptionView();
},
),
);
await context.push(Routes.settingsSubscription);
return;
}
Log.info(

View file

@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/context_menu.component.dart';
import 'package:twonly/src/views/contact/contact.view.dart';
class UserContextMenu extends StatelessWidget {
const UserContextMenu({
@ -20,16 +21,7 @@ class UserContextMenu extends StatelessWidget {
items: [
ContextMenuItem(
title: context.lang.contextMenuUserProfile,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ContactView(contact.userId);
},
),
);
},
onTap: () => context.push(Routes.profileContact(contact.userId)),
icon: FontAwesomeIcons.user,
),
],

View file

@ -1,9 +1,10 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/views/public_profile.view.dart';
class VerifiedShield extends StatefulWidget {
const VerifiedShield({
@ -58,16 +59,7 @@ class _VerifiedShieldState extends State<VerifiedShield> {
return GestureDetector(
onTap: (contact == null)
? null
: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
},
: () => context.push(Routes.settingsPublicProfile),
child: Tooltip(
message: isVerified
? 'You verified this contact'

View file

@ -19,16 +19,16 @@ import 'package:twonly/src/views/groups/group_member.context.dart';
import 'package:twonly/src/views/settings/profile/profile.view.dart';
class GroupView extends StatefulWidget {
const GroupView(this.group, {super.key});
const GroupView(this.groupId, {super.key});
final Group group;
final String groupId;
@override
State<GroupView> createState() => _GroupViewState();
}
class _GroupViewState extends State<GroupView> {
late Group group;
Group? _group;
List<(Contact, GroupMember)> members = [];
@ -37,7 +37,6 @@ class _GroupViewState extends State<GroupView> {
@override
void initState() {
group = widget.group;
initAsync();
super.initState();
}
@ -50,16 +49,15 @@ class _GroupViewState extends State<GroupView> {
}
Future<void> initAsync() async {
final groupStream = twonlyDB.groupsDao.watchGroup(widget.group.groupId);
final groupStream = twonlyDB.groupsDao.watchGroup(widget.groupId);
groupSub = groupStream.listen((update) {
if (update != null) {
setState(() {
group = update;
_group = update;
});
}
});
final membersStream =
twonlyDB.groupsDao.watchGroupMembers(widget.group.groupId);
final membersStream = twonlyDB.groupsDao.watchGroupMembers(widget.groupId);
membersSub = membersStream.listen((update) {
setState(() {
members = update;
@ -71,13 +69,13 @@ class _GroupViewState extends State<GroupView> {
}
Future<void> _updateGroupName() async {
final newGroupName = await showGroupNameChangeDialog(context, group);
final newGroupName = await showGroupNameChangeDialog(context, _group!);
if (context.mounted &&
newGroupName != null &&
newGroupName != '' &&
newGroupName != group.groupName) {
if (!await updateGroupName(group, newGroupName)) {
newGroupName != _group!.groupName) {
if (!await updateGroupName(_group!, newGroupName)) {
if (mounted) {
showNetworkIssue(context);
}
@ -89,11 +87,13 @@ class _GroupViewState extends State<GroupView> {
final selectedUserIds = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GroupCreateSelectMembersView(group: group),
builder: (context) => GroupCreateSelectMembersView(
groupId: _group?.groupId,
),
),
) as List<int>?;
if (selectedUserIds == null) return;
if (!await addNewGroupMembers(group, selectedUserIds)) {
if (!await addNewGroupMembers(_group!, selectedUserIds)) {
if (mounted) {
showNetworkIssue(context);
}
@ -115,7 +115,7 @@ class _GroupViewState extends State<GroupView> {
if (members.isNotEmpty) {
// In case there are other members, check that there is at least one other admin before I leave the group.
if (group.isGroupAdmin) {
if (_group!.isGroupAdmin) {
if (!members.any((m) => m.$2.memberState == MemberState.admin)) {
if (!mounted) return;
await showAlertDialog(
@ -131,16 +131,17 @@ class _GroupViewState extends State<GroupView> {
late bool success;
if (group.isGroupAdmin) {
if (_group!.isGroupAdmin) {
// Current user is a admin, to the state can be updated by the user him self.
final keyPair = IdentityKeyPair.fromSerialized(group.myGroupPrivateKey!);
final keyPair =
IdentityKeyPair.fromSerialized(_group!.myGroupPrivateKey!);
success = await removeMemberFromGroup(
group,
_group!,
keyPair.getPublicKey().serialize(),
gUser.userId,
);
} else {
success = await leaveAsNonAdminFromGroup(group);
success = await leaveAsNonAdminFromGroup(_group!);
}
if (!success) {
@ -153,6 +154,9 @@ class _GroupViewState extends State<GroupView> {
@override
Widget build(BuildContext context) {
if (_group == null) {
return Container();
}
return Scaffold(
appBar: AppBar(
title: const Text(''),
@ -162,7 +166,7 @@ class _GroupViewState extends State<GroupView> {
Padding(
padding: const EdgeInsets.all(10),
child: AvatarIcon(
group: group,
group: _group,
fontSize: 30,
),
),
@ -171,24 +175,24 @@ class _GroupViewState extends State<GroupView> {
children: [
Padding(
padding: const EdgeInsets.only(right: 10),
child: VerifiedShield(key: Key(group.groupId), group: group),
child: VerifiedShield(key: Key(_group!.groupId), group: _group),
),
Text(
substringBy(group.groupName, 25),
substringBy(_group!.groupName, 25),
style: const TextStyle(fontSize: 20),
),
],
),
const SizedBox(height: 50),
if (group.isGroupAdmin && !group.leftGroup)
if (_group!.isGroupAdmin && !_group!.leftGroup)
BetterListTile(
icon: FontAwesomeIcons.pencil,
text: context.lang.groupNameInput,
onTap: _updateGroupName,
),
SelectChatDeletionTimeListTitle(
groupId: widget.group.groupId,
disabled: !group.isGroupAdmin,
groupId: widget.groupId,
disabled: !_group!.isGroupAdmin,
),
const Divider(),
ListTile(
@ -203,7 +207,7 @@ class _GroupViewState extends State<GroupView> {
),
),
),
if (group.isGroupAdmin && !group.leftGroup)
if (_group!.isGroupAdmin && !_group!.leftGroup)
BetterListTile(
icon: FontAwesomeIcons.plus,
text: context.lang.addMember,
@ -216,7 +220,7 @@ class _GroupViewState extends State<GroupView> {
fontSize: 16,
),
text: context.lang.you,
trailing: (group.isGroupAdmin) ? Text(context.lang.admin) : null,
trailing: (_group!.isGroupAdmin) ? Text(context.lang.admin) : null,
onTap: () async {
await Navigator.push(
context,
@ -229,7 +233,7 @@ class _GroupViewState extends State<GroupView> {
...members.map((member) {
return GroupMemberContextMenu(
key: ValueKey(member.$1.userId),
group: group,
group: _group!,
contact: member.$1,
member: member.$2,
child: BetterListTile(
@ -256,7 +260,7 @@ class _GroupViewState extends State<GroupView> {
const SizedBox(height: 10),
const Divider(),
const SizedBox(height: 10),
if (!group.leftGroup)
if (!_group!.leftGroup)
BetterListTile(
icon: FontAwesomeIcons.rightFromBracket,
color: Colors.red,

View file

@ -12,8 +12,8 @@ import 'package:twonly/src/views/components/user_context_menu.component.dart';
import 'package:twonly/src/views/groups/group_create_select_group_name.view.dart';
class GroupCreateSelectMembersView extends StatefulWidget {
const GroupCreateSelectMembersView({this.group, super.key});
final Group? group;
const GroupCreateSelectMembersView({this.groupId, super.key});
final String? groupId;
@override
State<GroupCreateSelectMembersView> createState() => _StartNewChatView();
}
@ -46,9 +46,8 @@ class _StartNewChatView extends State<GroupCreateSelectMembersView> {
}
Future<void> initAsync() async {
if (widget.group != null) {
final members =
await twonlyDB.groupsDao.getGroupContact(widget.group!.groupId);
if (widget.groupId != null) {
final members = await twonlyDB.groupsDao.getGroupContact(widget.groupId!);
for (final member in members) {
alreadyInGroup.add(member.userId);
}
@ -101,7 +100,7 @@ class _StartNewChatView extends State<GroupCreateSelectMembersView> {
}
Future<void> submitChanges() async {
if (widget.group != null) {
if (widget.groupId != null) {
Navigator.pop(context, selectedUsers.toList());
return;
}
@ -125,7 +124,7 @@ class _StartNewChatView extends State<GroupCreateSelectMembersView> {
child: Scaffold(
appBar: AppBar(
title: Text(
widget.group == null
widget.groupId == null
? context.lang.selectMembers
: context.lang.addMember,
),
@ -133,7 +132,9 @@ class _StartNewChatView extends State<GroupCreateSelectMembersView> {
floatingActionButton: FilledButton.icon(
onPressed: selectedUsers.isEmpty ? null : submitChanges,
label: Text(
widget.group == null ? context.lang.next : context.lang.updateGroup,
widget.groupId == null
? context.lang.next
: context.lang.updateGroup,
),
icon: const FaIcon(FontAwesomeIcons.penToSquare),
),

View file

@ -1,7 +1,9 @@
import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/database/tables/groups.table.dart';
import 'package:twonly/src/database/twonly.db.dart';
@ -9,7 +11,6 @@ import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart';
import 'package:twonly/src/services/api/messages.dart';
import 'package:twonly/src/services/group.services.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/chats/chat_messages.view.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/components/context_menu.component.dart';
import 'package:twonly/src/views/groups/group.view.dart';
@ -128,12 +129,7 @@ class GroupMemberContextMenu extends StatelessWidget {
return;
}
if (!context.mounted) return;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatMessagesView(directChat),
),
);
await context.push(Routes.chatsMessages, extra: directChat);
},
icon: FontAwesomeIcons.message,
),

View file

@ -2,7 +2,6 @@ import 'dart:async';
import 'package:app_links/app_links.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_sharing_intent/flutter_sharing_intent.dart';
import 'package:flutter_sharing_intent/model/sharing_file.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart';
@ -126,32 +125,11 @@ class HomeViewState extends State<HomeView> {
}
});
_intentStreamSub = FlutterSharingIntent.instance.getMediaStream().listen(
(f) {
if (mounted) {
handleIntentSharedFile(
_intentStreamSub = initIntentStreams(
context,
f,
_mainCameraController.setSharedLinkForPreview,
);
}
},
// ignore: inference_failure_on_untyped_parameter
onError: (err) {
Log.error('getIntentDataStream error: $err');
},
);
FlutterSharingIntent.instance.getInitialSharing().then((f) {
if (mounted) {
handleIntentSharedFile(
context,
f,
_mainCameraController.setSharedLinkForPreview,
);
}
});
}
@override
void dispose() {

View file

@ -1,12 +1,13 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:restart_app/restart_app.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/twonly_safe/restore.twonly_safe.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/settings/backup/twonly_safe_server.view.dart';
class BackupRecoveryView extends StatefulWidget {
const BackupRecoveryView({super.key});
@ -135,14 +136,8 @@ class _BackupRecoveryViewState extends State<BackupRecoveryView> {
Center(
child: OutlinedButton(
onPressed: () async {
backupServer = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const TwonlySafeServerView();
},
),
);
backupServer =
await context.push(Routes.settingsBackupServer);
setState(() {});
},
child: Text(context.lang.backupExpertSettings),

View file

@ -2,11 +2,12 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/constants/secure_storage_keys.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
@ -17,7 +18,6 @@ import 'package:twonly/src/utils/pow.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/groups/group.view.dart';
import 'package:twonly/src/views/onboarding/recover.view.dart';
class RegisterView extends StatefulWidget {
const RegisterView({
@ -302,16 +302,8 @@ class _RegisterViewState extends State<RegisterView> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
OutlinedButton.icon(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const BackupRecoveryView();
},
),
);
},
onPressed: () =>
context.push(Routes.settingsBackupRecovery),
label: Text(context.lang.twonlySafeRecoverBtn),
),
],

View file

@ -1,15 +1,15 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:share_plus/share_plus.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/utils/avatars.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/qr.dart';
import 'package:twonly/src/views/camera/camera_qr_scanner.view.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
class PublicProfileView extends StatefulWidget {
@ -96,14 +96,7 @@ class _PublicProfileViewState extends State<PublicProfileView> {
BetterListTile(
leading: const FaIcon(FontAwesomeIcons.qrcode),
text: context.lang.scanOtherProfile,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const QrCodeScanner(),
),
);
},
onTap: () => context.push(Routes.cameraQRScanner),
),
BetterListTile(
leading: const FaIcon(

View file

@ -1,11 +1,12 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/settings/backup/twonly_safe_backup.view.dart';
void Function() gUpdateBackupView = () {};
@ -60,16 +61,7 @@ class _BackupViewState extends State<BackupView> {
}
Future<void> changeTwonlySafePassword() async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const TwonlyIdentityBackupView(
isPasswordChangeOnly: true,
);
},
),
);
await context.push(Routes.settingsBackupSetup, extra: true);
setState(() {
// gUser was updated
});

View file

@ -11,14 +11,14 @@ import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
class TwonlySafeServerView extends StatefulWidget {
const TwonlySafeServerView({super.key});
class BackupServerView extends StatefulWidget {
const BackupServerView({super.key});
@override
State<TwonlySafeServerView> createState() => _TwonlySafeServerViewState();
State<BackupServerView> createState() => _BackupServerViewState();
}
class _TwonlySafeServerViewState extends State<TwonlySafeServerView> {
class _BackupServerViewState extends State<BackupServerView> {
final TextEditingController _urlController = TextEditingController();
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();

View file

@ -2,13 +2,14 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/settings/backup/twonly_safe_server.view.dart';
class TwonlyIdentityBackupView extends StatefulWidget {
const TwonlyIdentityBackupView({
class SetupBackupView extends StatefulWidget {
const SetupBackupView({
this.isPasswordChangeOnly = false,
this.callBack,
super.key,
@ -20,11 +21,10 @@ class TwonlyIdentityBackupView extends StatefulWidget {
final bool isPasswordChangeOnly;
@override
State<TwonlyIdentityBackupView> createState() =>
_TwonlyIdentityBackupViewState();
State<SetupBackupView> createState() => _SetupBackupViewState();
}
class _TwonlyIdentityBackupViewState extends State<TwonlyIdentityBackupView> {
class _SetupBackupViewState extends State<SetupBackupView> {
bool obscureText = true;
bool isLoading = false;
final TextEditingController passwordCtrl = TextEditingController();
@ -179,16 +179,7 @@ class _TwonlyIdentityBackupViewState extends State<TwonlyIdentityBackupView> {
const SizedBox(height: 10),
Center(
child: OutlinedButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const TwonlySafeServerView();
},
),
);
},
onPressed: () => context.push(Routes.settingsBackupServer),
child: Text(context.lang.backupExpertSettings),
),
),

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/settings/chat/chat_reactions.view.dart';
class ChatSettingsView extends StatefulWidget {
const ChatSettingsView({super.key});
@ -25,16 +26,7 @@ class _ChatSettingsViewState extends State<ChatSettingsView> {
children: [
ListTile(
title: Text(context.lang.settingsPreSelectedReactions),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ChatReactionSelectionView();
},
),
);
},
onTap: () => context.push(Routes.settingsChatsReactions),
),
],
),

View file

@ -1,14 +1,13 @@
import 'dart:async';
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/services/api/mediafiles/download.service.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/settings/data_and_storage/export_media.view.dart';
import 'package:twonly/src/views/settings/data_and_storage/import_media.view.dart';
class DataAndStorageView extends StatefulWidget {
const DataAndStorageView({super.key});
@ -91,32 +90,14 @@ class _DataAndStorageViewState extends State<DataAndStorageView> {
title: Text(
context.lang.exportMemories,
),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) {
return const ExportMediaView();
},
),
);
},
onTap: () => context.push(Routes.settingsStorageExport),
),
if (Platform.isAndroid)
ListTile(
title: Text(
context.lang.importMemories,
),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) {
return const ImportMediaView();
},
),
);
},
onTap: () => context.push(Routes.settingsStorageImport),
),
const Divider(),
ListTile(

View file

@ -1,12 +1,12 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:restart_app/restart_app.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/views/settings/developer/automated_testing.view.dart';
import 'package:twonly/src/views/settings/developer/retransmission_data.view.dart';
class DeveloperSettingsView extends StatefulWidget {
const DeveloperSettingsView({super.key});
@ -55,16 +55,8 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
),
ListTile(
title: const Text('Show Retransmission Database'),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const RetransmissionDataView();
},
),
);
},
onTap: () =>
context.push(Routes.settingsDeveloperRetransmissionDatabase),
),
ListTile(
title: const Text('Delete all (!) app data'),
@ -97,16 +89,8 @@ class _DeveloperSettingsViewState extends State<DeveloperSettingsView> {
if (!kReleaseMode)
ListTile(
title: const Text('Automated Testing'),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const AutomatedTestingView();
},
),
);
},
onTap: () =>
context.push(Routes.settingsDeveloperAutomatedTesting),
),
],
),

View file

@ -1,17 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.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';
import 'package:twonly/src/views/settings/help/faq.view.dart';
import 'package:twonly/src/views/user_study/user_study_welcome.view.dart';
import 'package:url_launcher/url_launcher.dart';
class HelpView extends StatefulWidget {
@ -40,50 +36,12 @@ class _HelpViewState extends State<HelpView> {
children: [
ListTile(
title: Text(context.lang.settingsHelpFAQ),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const FaqView();
},
),
);
},
onTap: () => context.push(Routes.settingsHelpFaq),
),
ListTile(
title: Text(context.lang.settingsHelpContactUs),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ContactUsView();
},
onTap: () => context.push(Routes.settingsHelpContactUs),
),
);
},
),
// ListTile(
// title: Text(context.lang.settingsResetTutorials),
// subtitle: Text(
// context.lang.settingsResetTutorialsDesc,
// style: const TextStyle(fontSize: 12),
// ),
// onTap: () async {
// await updateUserdata((user) {
// user.tutorialDisplayed = [];
// return user;
// });
// if (!context.mounted) return;
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(context.lang.settingsResetTutorialsSuccess),
// duration: const Duration(seconds: 3),
// ),
// );
// },
// ),
const Divider(),
ListTile(
title: Text(context.lang.allowErrorTracking),
@ -99,32 +57,13 @@ class _HelpViewState extends State<HelpView> {
),
ListTile(
title: Text(context.lang.settingsHelpDiagnostics),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const DiagnosticsView();
},
),
);
},
onTap: () => context.push(Routes.settingsHelpDiagnostics),
),
const Divider(),
if (gUser.userStudyParticipantsToken == null || kDebugMode)
ListTile(
title: const Text('Teilnahme an Nutzerstudie'),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const UserStudyWelcomeView();
},
),
);
setState(() {}); // gUser has changed
},
onTap: () => context.push(Routes.settingsHelpUserStudy),
),
FutureBuilder(
future: PackageInfo.fromPlatform(),
@ -141,59 +80,34 @@ class _HelpViewState extends State<HelpView> {
),
ListTile(
title: Text(context.lang.settingsHelpLicenses),
onTap: () {
showLicensePage(context: context);
},
onTap: () => showLicensePage(context: context),
),
ListTile(
title: Text(context.lang.settingsHelpCredits),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const CreditsView();
},
),
);
},
onTap: () => context.push(Routes.settingsHelpCredits),
),
ListTile(
title: const Text('Changelog'),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ChangeLogView();
},
),
);
},
onTap: () => context.push(Routes.settingsHelpChangelog),
),
ListTile(
title: const Text('Open Source'),
onTap: () async {
await launchUrl(
onTap: () => launchUrl(
Uri.parse('https://github.com/twonlyapp/twonly-app'),
);
},
),
trailing:
const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15),
),
ListTile(
title: Text(context.lang.settingsHelpImprint),
onTap: () async {
await launchUrl(Uri.parse('https://twonly.eu/de/legal/'));
},
onTap: () => launchUrl(Uri.parse('https://twonly.eu/de/legal/')),
trailing:
const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15),
),
ListTile(
title: Text(context.lang.settingsHelpTerms),
onTap: () async {
await launchUrl(Uri.parse('https://twonly.eu/de/legal/agb.html'));
},
onTap: () =>
launchUrl(Uri.parse('https://twonly.eu/de/legal/agb.html')),
trailing:
const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15),
),

View file

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/settings/privacy_view_block.users.dart';
class PrivacyView extends StatefulWidget {
const PrivacyView({super.key});
@ -40,16 +41,7 @@ class _PrivacyViewState extends State<PrivacyView> {
}
},
),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PrivacyViewBlockUsers();
},
),
);
},
onTap: () => context.push(Routes.settingsPrivacyBlockUsers),
),
],
),

View file

@ -7,14 +7,14 @@ import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/user_context_menu.component.dart';
class PrivacyViewBlockUsers extends StatefulWidget {
const PrivacyViewBlockUsers({super.key});
class PrivacyViewBlockUsersView extends StatefulWidget {
const PrivacyViewBlockUsersView({super.key});
@override
State<PrivacyViewBlockUsers> createState() => _PrivacyViewBlockUsers();
State<PrivacyViewBlockUsersView> createState() => _PrivacyViewBlockUsers();
}
class _PrivacyViewBlockUsers extends State<PrivacyViewBlockUsers> {
class _PrivacyViewBlockUsers extends State<PrivacyViewBlockUsersView> {
late Stream<List<Contact>> allUsers;
List<Contact> filteredUsers = [];
String filter = '';

View file

@ -6,14 +6,14 @@ import 'package:twonly/globals.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
class ModifyAvatar extends StatefulWidget {
const ModifyAvatar({super.key});
class ModifyAvatarView extends StatefulWidget {
const ModifyAvatarView({super.key});
@override
State<ModifyAvatar> createState() => _ModifyAvatarState();
State<ModifyAvatarView> createState() => _ModifyAvatarViewState();
}
class _ModifyAvatarState extends State<ModifyAvatar> {
class _ModifyAvatarViewState extends State<ModifyAvatarView> {
final AvatarMakerController _avatarMakerController =
PersistentAvatarMakerController(customizedPropertyCategories: []);

View file

@ -3,7 +3,9 @@ import 'package:avatar_maker/avatar_maker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart';
import 'package:twonly/src/services/twonly_safe/common.twonly_safe.dart';
import 'package:twonly/src/services/twonly_safe/create_backup.twonly_safe.dart';
@ -11,7 +13,6 @@ import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/groups/group.view.dart';
import 'package:twonly/src/views/settings/profile/modify_avatar.view.dart';
class ProfileView extends StatefulWidget {
const ProfileView({super.key});
@ -110,12 +111,7 @@ class _ProfileViewState extends State<ProfileView> {
icon: const Icon(Icons.edit),
label: Text(context.lang.settingsProfileCustomizeAvatar),
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ModifyAvatar(),
),
);
await context.push(Routes.settingsProfileModifyAvatar);
await _avatarMakerController.performRestore();
setState(() {});
},

View file

@ -1,23 +1,12 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/components/avatar_icon.component.dart';
import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/views/public_profile.view.dart';
import 'package:twonly/src/views/settings/account.view.dart';
import 'package:twonly/src/views/settings/appearance.view.dart';
import 'package:twonly/src/views/settings/backup/backup.view.dart';
import 'package:twonly/src/views/settings/chat/chat_settings.view.dart';
import 'package:twonly/src/views/settings/data_and_storage.view.dart';
import 'package:twonly/src/views/settings/developer/developer.view.dart';
import 'package:twonly/src/views/settings/help/help.view.dart';
import 'package:twonly/src/views/settings/notification.view.dart';
import 'package:twonly/src/views/settings/privacy.view.dart';
import 'package:twonly/src/views/settings/profile/profile.view.dart';
import 'package:twonly/src/views/settings/share_with_friends.view.dart';
import 'package:twonly/src/views/settings/subscription/subscription.view.dart';
class SettingsMainView extends StatefulWidget {
const SettingsMainView({super.key});
@ -42,14 +31,7 @@ class _SettingsMainViewState extends State<SettingsMainView> {
Expanded(
child: GestureDetector(
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ProfileView();
},
),
);
await context.push(Routes.settingsProfile);
setState(() {});
},
child: ColoredBox(
@ -86,16 +68,7 @@ class _SettingsMainViewState extends State<SettingsMainView> {
Align(
alignment: Alignment.centerRight,
child: IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PublicProfileView();
},
),
);
},
onPressed: () => context.push(Routes.settingsPublicProfile),
icon: const FaIcon(FontAwesomeIcons.qrcode),
),
),
@ -105,160 +78,61 @@ class _SettingsMainViewState extends State<SettingsMainView> {
BetterListTile(
icon: FontAwesomeIcons.user,
text: context.lang.settingsAccount,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const AccountView();
},
),
);
},
onTap: () => context.push(Routes.settingsAccount),
),
BetterListTile(
icon: FontAwesomeIcons.shieldHeart,
text: context.lang.settingsSubscription,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const SubscriptionView();
},
),
);
},
onTap: () => context.push(Routes.settingsSubscription),
),
BetterListTile(
icon: Icons.lock_clock_rounded,
text: context.lang.settingsBackup,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const BackupView();
},
),
);
},
onTap: () => context.push(Routes.settingsBackup),
),
const Divider(),
BetterListTile(
icon: FontAwesomeIcons.sun,
text: context.lang.settingsAppearance,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const AppearanceView();
},
),
);
},
onTap: () => context.push(Routes.settingsAppearance),
),
BetterListTile(
icon: FontAwesomeIcons.comment,
text: context.lang.settingsChats,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ChatSettingsView();
},
),
);
},
onTap: () => context.push(Routes.settingsChats),
),
BetterListTile(
icon: FontAwesomeIcons.lock,
text: context.lang.settingsPrivacy,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const PrivacyView();
},
),
);
},
onTap: () => context.push(Routes.settingsPrivacy),
),
BetterListTile(
icon: FontAwesomeIcons.bell,
text: context.lang.settingsNotification,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const NotificationView();
},
),
);
},
onTap: () => context.push(Routes.settingsNotification),
),
BetterListTile(
icon: FontAwesomeIcons.chartPie,
iconSize: 15,
text: context.lang.settingsStorageData,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const DataAndStorageView();
},
),
);
},
onTap: () => context.push(Routes.settingsStorage),
),
const Divider(),
BetterListTile(
icon: FontAwesomeIcons.circleQuestion,
text: context.lang.settingsHelp,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const HelpView();
},
),
);
},
onTap: () => context.push(Routes.settingsHelp),
),
if (gUser.isDeveloper)
BetterListTile(
icon: FontAwesomeIcons.code,
text: 'Developer Settings',
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const DeveloperSettingsView();
},
),
);
},
onTap: () => context.push(Routes.settingsDeveloper),
),
BetterListTile(
icon: FontAwesomeIcons.shareFromSquare,
text: context.lang.inviteFriends,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return const ShareWithFriendsView();
},
),
);
},
onTap: () => context.push(Routes.settingsInvite),
),
],
),

View file

@ -2,19 +2,22 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/utils/keyvalue.dart';
import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/user_study/user_study_data_collection.dart';
class UserStudyQuestionnaire extends StatefulWidget {
const UserStudyQuestionnaire({super.key});
class UserStudyQuestionnaireView extends StatefulWidget {
const UserStudyQuestionnaireView({super.key});
@override
State<UserStudyQuestionnaire> createState() => _UserStudyQuestionnaireState();
State<UserStudyQuestionnaireView> createState() =>
_UserStudyQuestionnaireViewState();
}
class _UserStudyQuestionnaireState extends State<UserStudyQuestionnaire> {
class _UserStudyQuestionnaireViewState
extends State<UserStudyQuestionnaireView> {
final Map<String, dynamic> _responses = {
'age': null,
'education': null,
@ -62,7 +65,7 @@ class _UserStudyQuestionnaireState extends State<UserStudyQuestionnaire> {
const SnackBar(content: Text('Vielen Dank für deine Teilnahme!')),
);
Navigator.pop(context);
context.pop();
}
@override

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/user_study/user_study_questionnaire.view.dart';
class UserStudyWelcomeView extends StatefulWidget {
const UserStudyWelcomeView({super.key, this.wasOpenedAutomatic = false});
@ -54,16 +55,8 @@ class _UserStudyWelcomeViewState extends State<UserStudyWelcomeView> {
const SizedBox(height: 40),
Center(
child: FilledButton(
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) {
return const UserStudyQuestionnaire();
},
),
);
},
onPressed: () => context
.pushReplacement(Routes.settingsHelpUserStudyQuestionnaire),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
child: Text(
@ -77,9 +70,7 @@ class _UserStudyWelcomeViewState extends State<UserStudyWelcomeView> {
if (widget.wasOpenedAutomatic)
Center(
child: OutlinedButton(
onPressed: () {
Navigator.pop(context);
},
onPressed: () => context.pop(),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Text(
@ -98,7 +89,7 @@ class _UserStudyWelcomeViewState extends State<UserStudyWelcomeView> {
u.askedForUserStudyPermission = true;
return u;
});
if (context.mounted) Navigator.pop(context);
if (context.mounted) context.pop();
},
child: const Text(
'Nicht mehr anzeigen',

View file

@ -852,6 +852,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.3"
go_router:
dependency: "direct main"
description:
name: go_router
sha256: "7974313e217a7771557add6ff2238acb63f635317c35fa590d348fb238f00896"
url: "https://pub.dev"
source: hosted
version: "17.1.0"
google_mlkit_barcode_scanning:
dependency: "direct main"
description:

View file

@ -39,6 +39,7 @@ dependencies:
vector_graphics: ^1.1.19
video_player: ^2.10.1
in_app_purchase: ^3.2.3
go_router: ^17.1.0
# Trusted publisher fluttercommunity.dev