refactor, update and rotation fix

This commit is contained in:
otsmr 2025-04-21 21:32:18 +02:00
parent 8f29461f72
commit f5b4e35e18
106 changed files with 2262 additions and 551 deletions

View file

@ -63,5 +63,5 @@ flutter {
} }
dependencies { dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
} }

View file

@ -11,6 +11,7 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user

View file

@ -4,7 +4,7 @@
SRC_DIR="../twonly-server/twonly/src/" SRC_DIR="../twonly-server/twonly/src/"
DST_DIR="$(pwd)/lib/src/proto/" DST_DIR="$(pwd)/lib/src/model/protobuf/"
mkdir $DST_DIR mkdir $DST_DIR

View file

@ -5,54 +5,54 @@ PODS:
- Flutter - Flutter
- cryptography_flutter_plus (0.2.0): - cryptography_flutter_plus (0.2.0):
- Flutter - Flutter
- Firebase (11.8.0): - Firebase (11.10.0):
- Firebase/Core (= 11.8.0) - Firebase/Core (= 11.10.0)
- Firebase/Core (11.8.0): - Firebase/Core (11.10.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAnalytics (~> 11.8.0) - FirebaseAnalytics (~> 11.10.0)
- Firebase/CoreOnly (11.8.0): - Firebase/CoreOnly (11.10.0):
- FirebaseCore (~> 11.8.0) - FirebaseCore (~> 11.10.0)
- Firebase/Messaging (11.8.0): - Firebase/Messaging (11.10.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseMessaging (~> 11.8.0) - FirebaseMessaging (~> 11.10.0)
- firebase_core (3.12.1): - firebase_core (3.13.0):
- Firebase/CoreOnly (= 11.8.0) - Firebase/CoreOnly (= 11.10.0)
- Flutter - Flutter
- firebase_messaging (15.2.4): - firebase_messaging (15.2.5):
- Firebase/Messaging (= 11.8.0) - Firebase/Messaging (= 11.10.0)
- firebase_core - firebase_core
- Flutter - Flutter
- FirebaseAnalytics (11.8.0): - FirebaseAnalytics (11.10.0):
- FirebaseAnalytics/AdIdSupport (= 11.8.0) - FirebaseAnalytics/AdIdSupport (= 11.10.0)
- FirebaseCore (~> 11.8.0) - FirebaseCore (~> 11.10.0)
- FirebaseInstallations (~> 11.0) - FirebaseInstallations (~> 11.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 8.0) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 8.0) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 8.0)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- FirebaseAnalytics/AdIdSupport (11.8.0): - FirebaseAnalytics/AdIdSupport (11.10.0):
- FirebaseCore (~> 11.8.0) - FirebaseCore (~> 11.10.0)
- FirebaseInstallations (~> 11.0) - FirebaseInstallations (~> 11.0)
- GoogleAppMeasurement (= 11.8.0) - GoogleAppMeasurement (= 11.10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 8.0) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 8.0) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 8.0)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- FirebaseCore (11.8.1): - FirebaseCore (11.10.0):
- FirebaseCoreInternal (~> 11.8.0) - FirebaseCoreInternal (~> 11.10.0)
- GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/Logger (~> 8.0) - GoogleUtilities/Logger (~> 8.0)
- FirebaseCoreInternal (11.8.0): - FirebaseCoreInternal (11.10.0):
- "GoogleUtilities/NSData+zlib (~> 8.0)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- FirebaseInstallations (11.8.0): - FirebaseInstallations (11.10.0):
- FirebaseCore (~> 11.8.0) - FirebaseCore (~> 11.10.0)
- GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4) - PromisesObjC (~> 2.4)
- FirebaseMessaging (11.8.0): - FirebaseMessaging (11.10.0):
- FirebaseCore (~> 11.8.0) - FirebaseCore (~> 11.10.0)
- FirebaseInstallations (~> 11.0) - FirebaseInstallations (~> 11.0)
- GoogleDataTransport (~> 10.0) - GoogleDataTransport (~> 10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
@ -78,21 +78,21 @@ PODS:
- gal (1.0.0): - gal (1.0.0):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- GoogleAppMeasurement (11.8.0): - GoogleAppMeasurement (11.10.0):
- GoogleAppMeasurement/AdIdSupport (= 11.8.0) - GoogleAppMeasurement/AdIdSupport (= 11.10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 8.0) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 8.0) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 8.0)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/AdIdSupport (11.8.0): - GoogleAppMeasurement/AdIdSupport (11.10.0):
- GoogleAppMeasurement/WithoutAdIdSupport (= 11.8.0) - GoogleAppMeasurement/WithoutAdIdSupport (= 11.10.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 8.0) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 8.0) - GoogleUtilities/Network (~> 8.0)
- "GoogleUtilities/NSData+zlib (~> 8.0)" - "GoogleUtilities/NSData+zlib (~> 8.0)"
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- GoogleAppMeasurement/WithoutAdIdSupport (11.8.0): - GoogleAppMeasurement/WithoutAdIdSupport (11.10.0):
- GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- GoogleUtilities/MethodSwizzler (~> 8.0) - GoogleUtilities/MethodSwizzler (~> 8.0)
- GoogleUtilities/Network (~> 8.0) - GoogleUtilities/Network (~> 8.0)
@ -317,25 +317,25 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
camera_avfoundation: 04b44aeb14070126c6529e5ab82cc7c9fca107cf camera_avfoundation: be3be85408cd4126f250386828e9b1dfa40ab436
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f cryptography_flutter_plus: 44f4e9e4079395fcbb3e7809c0ac2c6ae2d9576f
Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
firebase_core: 8d552814f6c01ccde5d88939fced4ec26f2f5510 firebase_core: 2d4534e7b489907dcede540c835b48981d890943
firebase_messaging: 8b96a4f09841c15a16b96973ef5c3dcfc1a064e4 firebase_messaging: 75bc93a4df25faccad67f6662ae872ac9ae69b64
FirebaseAnalytics: 4fd42def128146e24e480e89f310e3d8534ea42b FirebaseAnalytics: 4e42333f02cf78ed93703a5c36f36dd518aebdef
FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d FirebaseCore: 8344daef5e2661eb004b177488d6f9f0f24251b7
FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629 FirebaseCoreInternal: ef4505d2afb1d0ebbc33162cb3795382904b5679
FirebaseInstallations: 6c963bd2a86aca0481eef4f48f5a4df783ae5917 FirebaseInstallations: 9980995bdd06ec8081dfb6ab364162bdd64245c3
FirebaseMessaging: 487b634ccdf6f7b7ff180fdcb2a9935490f764e8 FirebaseMessaging: 2b9f56aa4ed286e1f0ce2ee1d413aabb8f9f5cb9
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1 flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619 flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4 flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468 flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb flutter_volume_controller: c2be490cb0487e8b88d0d9fc2b7e1c139a4ebccb
gal: baecd024ebfd13c441269ca7404792a7152fde89 gal: baecd024ebfd13c441269ca7404792a7152fde89
GoogleAppMeasurement: fc0817122bd4d4189164f85374e06773b9561896 GoogleAppMeasurement: 36684bfb3ee034e2b42b4321eb19da3a1b81e65d
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a

View file

@ -24,6 +24,10 @@
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FIREBASE_ANALYTICS_COLLECTION_ENABLED</key>
<false/>
<key>FirebaseAutomaticScreenReportingEnabled</key>
<false/>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
@ -45,20 +49,9 @@
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
<string>Main</string> <string>Main</string>
<key>FIREBASE_ANALYTICS_COLLECTION_ENABLED</key><false/>
<key>FirebaseAutomaticScreenReportingEnabled</key> <false/>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
<array> <array>
<string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
</dict> </dict>
</plist> </plist>

View file

@ -1,4 +1,6 @@
synthetic-package: false
arb-dir: lib/src/localization arb-dir: lib/src/localization
template-arb-file: app_en.arb template-arb-file: app_en.arb
output-localization-file: app_localizations.dart output-localization-file: app_localizations.dart
untranslated-messages-file: build/l10n.log untranslated-messages-file: build/l10n.log
output-dir: lib/src/localization/generated

View file

@ -1,5 +1,6 @@
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/globals.dart'; 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/connection_provider.dart';
import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/providers/settings_change_provider.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
@ -8,13 +9,12 @@ import 'package:twonly/src/views/onboarding/onboarding_view.dart';
import 'package:twonly/src/views/home_view.dart'; import 'package:twonly/src/views/home_view.dart';
import 'package:twonly/src/views/onboarding/register_view.dart'; import 'package:twonly/src/views/onboarding/register_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'dart:async'; import 'dart:async';
// these global function can be called from anywhere to update // these global function can be called from anywhere to update
// the ui when something changed. The callbacks will be set by // the ui when something changed. The callbacks will be set by
// MyApp widget. // App widget.
// this callback is called by the apiProvider // this callback is called by the apiProvider
Function(bool) globalCallbackConnectionState = (a) {}; Function(bool) globalCallbackConnectionState = (a) {};
@ -23,14 +23,13 @@ bool globalIsAppInBackground = true;
// these two callbacks are called on updated to the corresponding database // these two callbacks are called on updated to the corresponding database
/// The Widget that configures your application. /// The Widget that configures your application.
class MyApp extends StatefulWidget { class App extends StatefulWidget {
const MyApp({super.key}); const App({super.key});
@override @override
State<MyApp> createState() => _MyAppState(); State<App> createState() => _AppState();
} }
class _MyAppState extends State<MyApp> with WidgetsBindingObserver { class _AppState extends State<App> with WidgetsBindingObserver {
bool wasPaused = false; bool wasPaused = false;
@override @override
@ -60,7 +59,6 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
globalIsAppInBackground = false; globalIsAppInBackground = false;
twonlyDatabase.markUpdated(); twonlyDatabase.markUpdated();
apiProvider.connect(); apiProvider.connect();
// _stopService();
} }
} else if (state == AppLifecycleState.paused) { } else if (state == AppLifecycleState.paused) {
wasPaused = true; wasPaused = true;
@ -70,20 +68,13 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override @override
void dispose() { void dispose() {
// apiProvider.close(() {});
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
// disable globalCallbacks to the flutter tree
globalCallbackConnectionState = (a) {}; globalCallbackConnectionState = (a) {};
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// var isConnected = context.watch<ApiProvider>().isConnected;
// Glue the SettingsController to the MaterialApp.
//
// The ListenableBuilder Widget listens to the SettingsController for changes.
// Whenever the user updates their settings, the MaterialApp is rebuilt.
return ListenableBuilder( return ListenableBuilder(
listenable: context.watch<SettingsChangeProvider>(), listenable: context.watch<SettingsChangeProvider>(),
builder: (BuildContext context, Widget? child) { builder: (BuildContext context, Widget? child) {
@ -107,7 +98,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
const InputDecorationTheme(border: OutlineInputBorder())), const InputDecorationTheme(border: OutlineInputBorder())),
darkTheme: ThemeData.dark().copyWith( darkTheme: ThemeData.dark().copyWith(
colorScheme: ColorScheme.fromSeed( colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark, // <-- the only line added brightness: Brightness.dark,
seedColor: const Color(0xFF57CC99), seedColor: const Color(0xFF57CC99),
), ),
inputDecorationTheme: const InputDecorationTheme( inputDecorationTheme: const InputDecorationTheme(
@ -117,9 +108,8 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
themeMode: context.watch<SettingsChangeProvider>().themeMode, themeMode: context.watch<SettingsChangeProvider>().themeMode,
initialRoute: '/', initialRoute: '/',
routes: { routes: {
"/": (context) => MyAppMainWidget(initialPage: 0), "/": (context) => AppMainWidget(initialPage: 0),
"/chats": (context) => MyAppMainWidget(initialPage: 1) "/chats": (context) => AppMainWidget(initialPage: 1)
// home: MyAppMainWidget(isConnected: isConnected, initialPage: 0),
}, },
); );
}, },
@ -127,53 +117,49 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
} }
} }
class MyAppMainWidget extends StatefulWidget { class AppMainWidget extends StatefulWidget {
const MyAppMainWidget({super.key, required this.initialPage}); const AppMainWidget({super.key, required this.initialPage});
final int initialPage; final int initialPage;
@override @override
State<MyAppMainWidget> createState() => _MyAppMainWidgetState(); State<AppMainWidget> createState() => _AppMainWidgetState();
} }
class _MyAppMainWidgetState extends State<MyAppMainWidget> { class _AppMainWidgetState extends State<AppMainWidget> {
Future<bool> _isUserCreated = isUserCreated(); Future<bool> userCreated = isUserCreated();
bool _showOnboarding = true; bool showOnboarding = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Stack(
children: [ children: [
FutureBuilder<bool>( FutureBuilder<bool>(
future: _isUserCreated, future: userCreated,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (!snapshot.hasData) {
return Center(child: Container());
}
if (snapshot.data!) { if (snapshot.data!) {
return HomeView( return HomeView(
initialPage: widget.initialPage, initialPage: widget.initialPage,
); );
} }
if (_showOnboarding) { return showOnboarding
return OnboardingView( ? OnboardingView(
callbackOnSuccess: () { callbackOnSuccess: () {
setState(() { setState(() {
_showOnboarding = false; showOnboarding = false;
});
},
)
: RegisterView(
callbackOnSuccess: () {
setState(() {
userCreated = isUserCreated();
}); });
}, },
); );
}
return RegisterView(
callbackOnSuccess: () {
setState(() {
_isUserCreated = isUserCreated();
});
},
);
} else {
return Center(child: Container());
}
}, },
), ),
], ],

View file

@ -1,4 +1,5 @@
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
@ -10,7 +11,7 @@ import 'package:twonly/src/providers/settings_change_provider.dart';
import 'package:twonly/src/services/fcm_service.dart'; import 'package:twonly/src/services/fcm_service.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'src/app.dart'; import 'app.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -32,13 +33,15 @@ void main() async {
twonlyDatabase = TwonlyDatabase(); twonlyDatabase = TwonlyDatabase();
await twonlyDatabase.messagesDao.appRestarted(); await twonlyDatabase.messagesDao.appRestarted();
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp( runApp(
MultiProvider( MultiProvider(
providers: [ providers: [
ChangeNotifierProvider(create: (_) => settingsController), ChangeNotifierProvider(create: (_) => settingsController),
ChangeNotifierProvider(create: (_) => ConnectionChangeProvider()), ChangeNotifierProvider(create: (_) => ConnectionChangeProvider()),
], ],
child: MyApp(), child: App(),
), ),
); );
} }

View file

@ -11,7 +11,7 @@ class MessagesDao extends DatabaseAccessor<TwonlyDatabase>
with _$MessagesDaoMixin { with _$MessagesDaoMixin {
// this constructor is required so that the main database can create an instance // this constructor is required so that the main database can create an instance
// of this object. // of this object.
MessagesDao(TwonlyDatabase db) : super(db); MessagesDao(super.db);
Stream<List<Message>> watchMessageNotOpened(int contactId) { Stream<List<Message>> watchMessageNotOpened(int contactId) {
return (select(messages) return (select(messages)

View file

@ -0,0 +1,933 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_de.dart';
import 'app_localizations_en.dart';
// ignore_for_file: type=lint
/// Callers can lookup localized strings with an instance of AppLocalizations
/// returned by `AppLocalizations.of(context)`.
///
/// Applications need to include `AppLocalizations.delegate()` in their app's
/// `localizationDelegates` list, and the locales they support in the app's
/// `supportedLocales` list. For example:
///
/// ```dart
/// import 'generated/app_localizations.dart';
///
/// return MaterialApp(
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
/// supportedLocales: AppLocalizations.supportedLocales,
/// home: MyApplicationHome(),
/// );
/// ```
///
/// ## Update pubspec.yaml
///
/// Please make sure to update your pubspec.yaml to include the following
/// packages:
///
/// ```yaml
/// dependencies:
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: any # Use the pinned version from flutter_localizations
///
/// # Rest of dependencies
/// ```
///
/// ## iOS Applications
///
/// iOS applications define key application metadata, including supported
/// locales, in an Info.plist file that is built into the application bundle.
/// To configure the locales supported by your app, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects Runner folder.
///
/// Next, select the Information Property List item, select Add Item from the
/// Editor menu, then select Localizations from the pop-up menu.
///
/// Select and expand the newly-created Localizations item then, for each
/// locale your application supports, add a new item and select the locale
/// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property.
abstract class AppLocalizations {
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('de'),
Locale('en')
];
/// No description provided for @registerTitle.
///
/// In en, this message translates to:
/// **'Welcome to twonly!'**
String get registerTitle;
/// No description provided for @registerSlogan.
///
/// In en, this message translates to:
/// **'twonly, a privacy friendly way to connect with friends through secure, spontaneous image sharing'**
String get registerSlogan;
/// No description provided for @onboardingWelcomeTitle.
///
/// In en, this message translates to:
/// **'Welcome to twonly!'**
String get onboardingWelcomeTitle;
/// No description provided for @onboardingWelcomeBody.
///
/// In en, this message translates to:
/// **'Experience a private and secure way to stay in touch with friends by sharing instant pictures.'**
String get onboardingWelcomeBody;
/// No description provided for @onboardingE2eTitle.
///
/// In en, this message translates to:
/// **'Carefree sharing'**
String get onboardingE2eTitle;
/// No description provided for @onboardingE2eBody.
///
/// In en, this message translates to:
/// **'With end-to-end encryption, enjoy the peace of mind that only you and your friends can see the moments you share.'**
String get onboardingE2eBody;
/// No description provided for @onboardingFocusTitle.
///
/// In en, this message translates to:
/// **'Focus on sharing moments'**
String get onboardingFocusTitle;
/// No description provided for @onboardingFocusBody.
///
/// In en, this message translates to:
/// **'Say goodbye to addictive features! twonly was created for sharing moments, free from useless distractions or ads.'**
String get onboardingFocusBody;
/// No description provided for @onboardingSendTwonliesTitle.
///
/// In en, this message translates to:
/// **'Send twonlies'**
String get onboardingSendTwonliesTitle;
/// No description provided for @onboardingSendTwonliesBody.
///
/// In en, this message translates to:
/// **'Share moments securely with your partner. twonly ensures that only your partner can open it, keeping your moments with your partner a two(o)nly thing!'**
String get onboardingSendTwonliesBody;
/// No description provided for @onboardingNotProductTitle.
///
/// In en, this message translates to:
/// **'You are not the product!'**
String get onboardingNotProductTitle;
/// No description provided for @onboardingNotProductBody.
///
/// In en, this message translates to:
/// **'twonly is financed by a small monthly fee and not by selling your data.'**
String get onboardingNotProductBody;
/// No description provided for @onboardingBuyOneGetTwoTitle.
///
/// In en, this message translates to:
/// **'Buy one get two'**
String get onboardingBuyOneGetTwoTitle;
/// No description provided for @onboardingBuyOneGetTwoBody.
///
/// In en, this message translates to:
/// **'twonly always requires at least two people, which is why you receive a second free license for your twonly partner with your purchase.'**
String get onboardingBuyOneGetTwoBody;
/// No description provided for @onboardingGetStartedTitle.
///
/// In en, this message translates to:
/// **'Let\'s go!'**
String get onboardingGetStartedTitle;
/// No description provided for @onboardingGetStartedBody.
///
/// In en, this message translates to:
/// **'You can test twonly free of charge for 14 days, after that it costs either 1€/month or 9€/year.'**
String get onboardingGetStartedBody;
/// No description provided for @onboardingTryForFree.
///
/// In en, this message translates to:
/// **'Try for free'**
String get onboardingTryForFree;
/// No description provided for @registerUsernameSlogan.
///
/// In en, this message translates to:
/// **'Please select a username so others can find you!'**
String get registerUsernameSlogan;
/// No description provided for @registerUsernameDecoration.
///
/// In en, this message translates to:
/// **'Username'**
String get registerUsernameDecoration;
/// No description provided for @registerUsernameLimits.
///
/// In en, this message translates to:
/// **'Username must be 3 to 12 characters long, consisting only of letters (a-z) and numbers (0-9).'**
String get registerUsernameLimits;
/// No description provided for @registerSubmitButton.
///
/// In en, this message translates to:
/// **'Register now!'**
String get registerSubmitButton;
/// No description provided for @newMessageTitle.
///
/// In en, this message translates to:
/// **'New message'**
String get newMessageTitle;
/// No description provided for @chatsTapToSend.
///
/// In en, this message translates to:
/// **'Click to send your first image'**
String get chatsTapToSend;
/// No description provided for @cameraPreviewSendTo.
///
/// In en, this message translates to:
/// **'Send to'**
String get cameraPreviewSendTo;
/// No description provided for @shareImageTitle.
///
/// In en, this message translates to:
/// **'Share with'**
String get shareImageTitle;
/// No description provided for @shareImageBestFriends.
///
/// In en, this message translates to:
/// **'Best friends'**
String get shareImageBestFriends;
/// No description provided for @shareImagedEditorSendImage.
///
/// In en, this message translates to:
/// **'Send'**
String get shareImagedEditorSendImage;
/// No description provided for @shareImagedEditorShareWith.
///
/// In en, this message translates to:
/// **'Share with'**
String get shareImagedEditorShareWith;
/// No description provided for @shareImagedEditorSaveImage.
///
/// In en, this message translates to:
/// **'Save'**
String get shareImagedEditorSaveImage;
/// No description provided for @shareImagedEditorSavedImage.
///
/// In en, this message translates to:
/// **'Saved'**
String get shareImagedEditorSavedImage;
/// No description provided for @shareImageSearchAllContacts.
///
/// In en, this message translates to:
/// **'Search all contacts'**
String get shareImageSearchAllContacts;
/// No description provided for @startNewChatTitle.
///
/// In en, this message translates to:
/// **'Select Contact'**
String get startNewChatTitle;
/// No description provided for @startNewChatNewContact.
///
/// In en, this message translates to:
/// **'New Contact'**
String get startNewChatNewContact;
/// No description provided for @startNewChatYourContacts.
///
/// In en, this message translates to:
/// **'Your Contacts'**
String get startNewChatYourContacts;
/// No description provided for @shareImageAllUsers.
///
/// In en, this message translates to:
/// **'All contacts'**
String get shareImageAllUsers;
/// No description provided for @shareImageAllTwonlyWarning.
///
/// In en, this message translates to:
/// **'twonlies can only be send to verified contacts!'**
String get shareImageAllTwonlyWarning;
/// No description provided for @searchUsernameInput.
///
/// In en, this message translates to:
/// **'Username'**
String get searchUsernameInput;
/// No description provided for @searchUsernameTitle.
///
/// In en, this message translates to:
/// **'Search username'**
String get searchUsernameTitle;
/// No description provided for @searchUserNamePending.
///
/// In en, this message translates to:
/// **'Pending'**
String get searchUserNamePending;
/// No description provided for @searchUserNameBlockUserTooltip.
///
/// In en, this message translates to:
/// **'Block the user without informing.'**
String get searchUserNameBlockUserTooltip;
/// No description provided for @searchUserNameRejectUserTooltip.
///
/// In en, this message translates to:
/// **'Reject the request and let the requester know.'**
String get searchUserNameRejectUserTooltip;
/// No description provided for @searchUserNameArchiveUserTooltip.
///
/// In en, this message translates to:
/// **'Archive the user. He will appear again as soon as he accepts your request.'**
String get searchUserNameArchiveUserTooltip;
/// No description provided for @searchUsernameNotFound.
///
/// In en, this message translates to:
/// **'Username not found'**
String get searchUsernameNotFound;
/// No description provided for @searchUsernameNotFoundBody.
///
/// In en, this message translates to:
/// **'There is no user with the username \"{username}\" registered'**
String searchUsernameNotFoundBody(Object username);
/// No description provided for @searchUsernameNewFollowerTitle.
///
/// In en, this message translates to:
/// **'Follow requests'**
String get searchUsernameNewFollowerTitle;
/// No description provided for @searchUsernameQrCodeBtn.
///
/// In en, this message translates to:
/// **'Scan QR code'**
String get searchUsernameQrCodeBtn;
/// No description provided for @chatListViewSearchUserNameBtn.
///
/// In en, this message translates to:
/// **'Add your first twonly contact!'**
String get chatListViewSearchUserNameBtn;
/// No description provided for @chatListViewSendFirstTwonly.
///
/// In en, this message translates to:
/// **'Send your first twonly!'**
String get chatListViewSendFirstTwonly;
/// No description provided for @chatListDetailInput.
///
/// In en, this message translates to:
/// **'Type a message'**
String get chatListDetailInput;
/// No description provided for @contextMenuVerifyUser.
///
/// In en, this message translates to:
/// **'Verify'**
String get contextMenuVerifyUser;
/// No description provided for @contextMenuArchiveUser.
///
/// In en, this message translates to:
/// **'Archive'**
String get contextMenuArchiveUser;
/// No description provided for @contextMenuUndoArchiveUser.
///
/// In en, this message translates to:
/// **'Undo archiving'**
String get contextMenuUndoArchiveUser;
/// No description provided for @contextMenuOpenChat.
///
/// In en, this message translates to:
/// **'Open chat'**
String get contextMenuOpenChat;
/// No description provided for @contextMenuSendImage.
///
/// In en, this message translates to:
/// **'Send image'**
String get contextMenuSendImage;
/// No description provided for @mediaViewerAuthReason.
///
/// In en, this message translates to:
/// **'Please authenticate to see this twonly!'**
String get mediaViewerAuthReason;
/// No description provided for @messageSendState_Received.
///
/// In en, this message translates to:
/// **'Received'**
String get messageSendState_Received;
/// No description provided for @messageSendState_Opened.
///
/// In en, this message translates to:
/// **'Opened'**
String get messageSendState_Opened;
/// No description provided for @messageSendState_Send.
///
/// In en, this message translates to:
/// **'Sent'**
String get messageSendState_Send;
/// No description provided for @messageSendState_Sending.
///
/// In en, this message translates to:
/// **'Sending'**
String get messageSendState_Sending;
/// No description provided for @messageSendState_TapToLoad.
///
/// In en, this message translates to:
/// **'Tap to load'**
String get messageSendState_TapToLoad;
/// No description provided for @messageSendState_Loading.
///
/// In en, this message translates to:
/// **'Downloading'**
String get messageSendState_Loading;
/// No description provided for @messageStoredInGalery.
///
/// In en, this message translates to:
/// **'Stored in gallery'**
String get messageStoredInGalery;
/// No description provided for @imageEditorDrawOk.
///
/// In en, this message translates to:
/// **'Take drawing'**
String get imageEditorDrawOk;
/// No description provided for @settingsTitle.
///
/// In en, this message translates to:
/// **'Settings'**
String get settingsTitle;
/// No description provided for @settingsChats.
///
/// In en, this message translates to:
/// **'Chats'**
String get settingsChats;
/// No description provided for @settingsPreSelectedReactions.
///
/// In en, this message translates to:
/// **'Preselected reaction emojis'**
String get settingsPreSelectedReactions;
/// No description provided for @settingsPreSelectedReactionsError.
///
/// In en, this message translates to:
/// **'A maximum of 12 reactions can be selected.'**
String get settingsPreSelectedReactionsError;
/// No description provided for @settingsProfile.
///
/// In en, this message translates to:
/// **'Profile'**
String get settingsProfile;
/// No description provided for @settingsProfileCustomizeAvatar.
///
/// In en, this message translates to:
/// **'Customize your avatar'**
String get settingsProfileCustomizeAvatar;
/// No description provided for @settingsProfileEditDisplayName.
///
/// In en, this message translates to:
/// **'Displayname'**
String get settingsProfileEditDisplayName;
/// No description provided for @settingsProfileEditDisplayNameNew.
///
/// In en, this message translates to:
/// **'New Displayname'**
String get settingsProfileEditDisplayNameNew;
/// No description provided for @settingsAccount.
///
/// In en, this message translates to:
/// **'Konto'**
String get settingsAccount;
/// No description provided for @settingsSubscription.
///
/// In en, this message translates to:
/// **'Subscription'**
String get settingsSubscription;
/// No description provided for @settingsAppearance.
///
/// In en, this message translates to:
/// **'Appearance'**
String get settingsAppearance;
/// No description provided for @settingsPrivacy.
///
/// In en, this message translates to:
/// **'Privacy'**
String get settingsPrivacy;
/// No description provided for @settingsPrivacyBlockUsers.
///
/// In en, this message translates to:
/// **'Block users'**
String get settingsPrivacyBlockUsers;
/// No description provided for @settingsPrivacyBlockUsersDesc.
///
/// In en, this message translates to:
/// **'Blocked users will not be able to communicate with you. You can unblock a blocked user at any time.'**
String get settingsPrivacyBlockUsersDesc;
/// No description provided for @settingsPrivacyBlockUsersCount.
///
/// In en, this message translates to:
/// **'{len} contact(s)'**
String settingsPrivacyBlockUsersCount(Object len);
/// No description provided for @settingsNotification.
///
/// In en, this message translates to:
/// **'Notification'**
String get settingsNotification;
/// No description provided for @settingsNotifyTroubleshooting.
///
/// In en, this message translates to:
/// **'Troubleshooting'**
String get settingsNotifyTroubleshooting;
/// No description provided for @settingsNotifyTroubleshootingDesc.
///
/// In en, this message translates to:
/// **'Click here if you have problems receiving push notifications.'**
String get settingsNotifyTroubleshootingDesc;
/// No description provided for @settingsNotifyTroubleshootingNoProblem.
///
/// In en, this message translates to:
/// **'No problem detected'**
String get settingsNotifyTroubleshootingNoProblem;
/// No description provided for @settingsNotifyTroubleshootingNoProblemDesc.
///
/// In en, this message translates to:
/// **'Press OK to receive a test notification. When you receive no message even after waiting for 10 minutes, please send us your debug log in Settings > Help > Debug log, so we can look at that issue.'**
String get settingsNotifyTroubleshootingNoProblemDesc;
/// No description provided for @settingsHelp.
///
/// In en, this message translates to:
/// **'Help'**
String get settingsHelp;
/// No description provided for @settingsHelpDiagnostics.
///
/// In en, this message translates to:
/// **'Diagnostic protocol'**
String get settingsHelpDiagnostics;
/// No description provided for @settingsHelpSupport.
///
/// In en, this message translates to:
/// **'Support Center'**
String get settingsHelpSupport;
/// No description provided for @settingsHelpVersion.
///
/// In en, this message translates to:
/// **'Version'**
String get settingsHelpVersion;
/// No description provided for @settingsHelpLicenses.
///
/// In en, this message translates to:
/// **'Licenses (Source-Code)'**
String get settingsHelpLicenses;
/// No description provided for @settingsHelpCredits.
///
/// In en, this message translates to:
/// **'Licenses (Images)'**
String get settingsHelpCredits;
/// No description provided for @settingsHelpLegal.
///
/// In en, this message translates to:
/// **'Imprint, Terms & Privacy Policy'**
String get settingsHelpLegal;
/// No description provided for @settingsAppearanceTheme.
///
/// In en, this message translates to:
/// **'Theme'**
String get settingsAppearanceTheme;
/// No description provided for @settingsAccountDeleteAccount.
///
/// In en, this message translates to:
/// **'Delete account'**
String get settingsAccountDeleteAccount;
/// No description provided for @settingsAccountDeleteModalTitle.
///
/// In en, this message translates to:
/// **'Are you sure?'**
String get settingsAccountDeleteModalTitle;
/// No description provided for @settingsAccountDeleteModalBody.
///
/// In en, this message translates to:
/// **'Your account will be deleted. There is no change to restore it.'**
String get settingsAccountDeleteModalBody;
/// No description provided for @contactVerifyNumberTitle.
///
/// In en, this message translates to:
/// **'Verify safety number'**
String get contactVerifyNumberTitle;
/// No description provided for @contactVerifyNumberMarkAsVerified.
///
/// In en, this message translates to:
/// **'Mark as verified'**
String get contactVerifyNumberMarkAsVerified;
/// No description provided for @contactVerifyNumberClearVerification.
///
/// In en, this message translates to:
/// **'Clear verification'**
String get contactVerifyNumberClearVerification;
/// No description provided for @contactVerifyNumberLongDesc.
///
/// In en, this message translates to:
/// **'To verify the end-to-end encryption with {username}, compare the numbers with their device. The person can also scan your code with their device.'**
String contactVerifyNumberLongDesc(Object username);
/// No description provided for @contactNickname.
///
/// In en, this message translates to:
/// **'Nickname'**
String get contactNickname;
/// No description provided for @contactNicknameNew.
///
/// In en, this message translates to:
/// **'New nickname'**
String get contactNicknameNew;
/// No description provided for @deleteAllContactMessages.
///
/// In en, this message translates to:
/// **'Delete all messages'**
String get deleteAllContactMessages;
/// No description provided for @deleteAllContactMessagesBody.
///
/// In en, this message translates to:
/// **'This will remove all messages in your chat with {username}. This will NOT delete the messages stored at {username}s device!'**
String deleteAllContactMessagesBody(Object username);
/// No description provided for @contactBlock.
///
/// In en, this message translates to:
/// **'Block'**
String get contactBlock;
/// No description provided for @contactBlockTitle.
///
/// In en, this message translates to:
/// **'Block {username}'**
String contactBlockTitle(Object username);
/// No description provided for @contactBlockBody.
///
/// In en, this message translates to:
/// **'A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.'**
String get contactBlockBody;
/// No description provided for @undo.
///
/// In en, this message translates to:
/// **'Undo'**
String get undo;
/// No description provided for @redo.
///
/// In en, this message translates to:
/// **'Redo'**
String get redo;
/// No description provided for @next.
///
/// In en, this message translates to:
/// **'Next'**
String get next;
/// No description provided for @close.
///
/// In en, this message translates to:
/// **'Close'**
String get close;
/// No description provided for @cancel.
///
/// In en, this message translates to:
/// **'Cancel'**
String get cancel;
/// No description provided for @ok.
///
/// In en, this message translates to:
/// **'Ok'**
String get ok;
/// No description provided for @switchFrontAndBackCamera.
///
/// In en, this message translates to:
/// **'Switch between front and back camera.'**
String get switchFrontAndBackCamera;
/// No description provided for @addTextItem.
///
/// In en, this message translates to:
/// **'Text'**
String get addTextItem;
/// No description provided for @protectAsARealTwonly.
///
/// In en, this message translates to:
/// **'Send as real twonly!'**
String get protectAsARealTwonly;
/// No description provided for @addDrawing.
///
/// In en, this message translates to:
/// **'Drawing'**
String get addDrawing;
/// No description provided for @addEmoji.
///
/// In en, this message translates to:
/// **'Emoji'**
String get addEmoji;
/// No description provided for @toggleFlashLight.
///
/// In en, this message translates to:
/// **'Toggle the flash light'**
String get toggleFlashLight;
/// No description provided for @toggleHighQuality.
///
/// In en, this message translates to:
/// **'Toggle better resolution'**
String get toggleHighQuality;
/// No description provided for @userFound.
///
/// In en, this message translates to:
/// **'User found'**
String get userFound;
/// No description provided for @userFoundBody.
///
/// In en, this message translates to:
/// **'Do you want to create a follow request?'**
String get userFoundBody;
/// No description provided for @searchUsernameNotFoundLong.
///
/// In en, this message translates to:
/// **'\"{username}\" is not a twonly user. Please check the username and try again.'**
String searchUsernameNotFoundLong(Object username);
/// No description provided for @errorUnknown.
///
/// In en, this message translates to:
/// **'An unexpected error has occurred. Please try again later.'**
String get errorUnknown;
/// No description provided for @errorBadRequest.
///
/// In en, this message translates to:
/// **'The request could not be understood by the server due to malformed syntax. Please check your input and try again.'**
String get errorBadRequest;
/// No description provided for @errorTooManyRequests.
///
/// In en, this message translates to:
/// **'You have made too many requests in a short period. Please wait a moment before trying again.'**
String get errorTooManyRequests;
/// No description provided for @errorInternalError.
///
/// In en, this message translates to:
/// **'The server is currently not available. Please try again later.'**
String get errorInternalError;
/// No description provided for @errorInvalidInvitationCode.
///
/// In en, this message translates to:
/// **'The invitation code you provided is invalid. Please check the code and try again.'**
String get errorInvalidInvitationCode;
/// No description provided for @errorUsernameAlreadyTaken.
///
/// In en, this message translates to:
/// **'The username you want to use is already taken. Please choose a different username.'**
String get errorUsernameAlreadyTaken;
/// No description provided for @errorSignatureNotValid.
///
/// In en, this message translates to:
/// **'The provided signature is not valid. Please check your credentials and try again.'**
String get errorSignatureNotValid;
/// No description provided for @errorUsernameNotFound.
///
/// In en, this message translates to:
/// **'The username you entered does not exist. Please check the spelling or create a new account.'**
String get errorUsernameNotFound;
/// No description provided for @errorUsernameNotValid.
///
/// In en, this message translates to:
/// **'The username you provided does not meet the required criteria. Please choose a valid username.'**
String get errorUsernameNotValid;
/// No description provided for @errorInvalidPublicKey.
///
/// In en, this message translates to:
/// **'The public key you provided is invalid. Please check the key and try again.'**
String get errorInvalidPublicKey;
/// No description provided for @errorSessionAlreadyAuthenticated.
///
/// In en, this message translates to:
/// **'You are already logged in. Please log out if you want to log in with a different account.'**
String get errorSessionAlreadyAuthenticated;
/// No description provided for @errorSessionNotAuthenticated.
///
/// In en, this message translates to:
/// **'Your session is not authenticated. Please log in to continue.'**
String get errorSessionNotAuthenticated;
/// No description provided for @errorOnlyOneSessionAllowed.
///
/// In en, this message translates to:
/// **'Only one active session is allowed per user. Please log out from other devices to continue.'**
String get errorOnlyOneSessionAllowed;
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) => <String>['de', 'en'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'de': return AppLocalizationsDe();
case 'en': return AppLocalizationsEn();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.'
);
}

View file

@ -0,0 +1,424 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for German (`de`).
class AppLocalizationsDe extends AppLocalizations {
AppLocalizationsDe([String locale = 'de']) : super(locale);
@override
String get registerTitle => 'Willkommen bei twonly!';
@override
String get registerSlogan => 'twonly, eine private und sichere Möglichkeit um mit Freunden in Kontakt zu bleiben.';
@override
String get onboardingWelcomeTitle => 'Willkommen bei twonly!';
@override
String get onboardingWelcomeBody => 'Erlebe eine private und sichere Möglichkeit mit Freunden in Kontakt zu bleiben, indem du spontane Bilder teilst.';
@override
String get onboardingE2eTitle => 'Unbekümmert teilen';
@override
String get onboardingE2eBody => 'Genieße durch die Ende-zu-Ende-Verschlüsselung die Gewissheit, dass nur du und deine Freunde die geteilten Momente sehen können.';
@override
String get onboardingFocusTitle => 'Fokussiere dich auf das Teilen von Momenten';
@override
String get onboardingFocusBody => 'Verabschiede dich von süchtig machenden Funktionen! twonly wurde für das Teilen von Momenten ohne nutzlose Ablenkungen oder Werbung entwickelt.';
@override
String get onboardingSendTwonliesTitle => 'Twonlies senden';
@override
String get onboardingSendTwonliesBody => 'Teile Momente sicher mit deinem Partner. twonly stellt sicher, dass nur dein Partner sie öffnen kann, sodass deine Momente mit deinem Partner eine two(o)nly Sache bleiben!';
@override
String get onboardingNotProductTitle => 'Du bist nicht das Produkt!';
@override
String get onboardingNotProductBody => 'twonly finanziert sich durch eine geringe monatliche Gebühr und nicht durch den Verkauf deiner Daten.';
@override
String get onboardingBuyOneGetTwoTitle => 'Kaufe eins, bekomme zwei';
@override
String get onboardingBuyOneGetTwoBody => 'twonly benötigt immer mindestens zwei Personen, daher erhältst du beim Kauf eine zweite kostenlose Lizenz für deinen twonly-Partner.';
@override
String get onboardingGetStartedTitle => 'Auf geht\'s';
@override
String get onboardingGetStartedBody => 'Du kannst twonly 14 Tage lang kostenlos testen, danach kostet es entweder 1€/Monat oder 9€/Jahr.';
@override
String get onboardingTryForFree => 'Kostenlos testen';
@override
String get registerUsernameSlogan => 'Bitte wähle einen Benutzernamen, damit dich andere finden können!';
@override
String get registerUsernameDecoration => 'Benutzername';
@override
String get registerUsernameLimits => 'Der Benutzername muss 3 bis 12 Zeichen lang sein und darf nur aus Buchstaben (a-z) und Zahlen (0-9) bestehen.';
@override
String get registerSubmitButton => 'Jetzt registrieren!';
@override
String get newMessageTitle => 'Neue Nachricht';
@override
String get chatsTapToSend => 'Klicke, um dein erstes Bild zu teilen.';
@override
String get cameraPreviewSendTo => 'Senden an';
@override
String get shareImageTitle => 'Teilen mit';
@override
String get shareImageBestFriends => 'Beste Freunde';
@override
String get shareImagedEditorSendImage => 'Senden';
@override
String get shareImagedEditorShareWith => 'Teilen mit';
@override
String get shareImagedEditorSaveImage => 'Speichern';
@override
String get shareImagedEditorSavedImage => 'Gespeichert';
@override
String get shareImageSearchAllContacts => 'Alle Kontakte durchsuchen';
@override
String get startNewChatTitle => 'Kontakt wählen';
@override
String get startNewChatNewContact => 'Neuer Kontakt';
@override
String get startNewChatYourContacts => 'Deine Kontakte';
@override
String get shareImageAllUsers => 'Alle Kontakte';
@override
String get shareImageAllTwonlyWarning => 'Twonlies können nur an verifizierte Kontakte gesendet werden!';
@override
String get searchUsernameInput => 'Benutzername';
@override
String get searchUsernameTitle => 'Benutzernamen suchen';
@override
String get searchUserNamePending => 'Ausstehend';
@override
String get searchUserNameBlockUserTooltip => 'Benutzer ohne Benachrichtigung blockieren.';
@override
String get searchUserNameRejectUserTooltip => 'Die Anfrage ablehnen und den Anfragenden informieren.';
@override
String get searchUserNameArchiveUserTooltip => 'Benutzer archivieren. Du wirst informiert sobald er deine Anfrage akzeptiert.';
@override
String get searchUsernameNotFound => 'Benutzername nicht gefunden';
@override
String searchUsernameNotFoundBody(Object username) {
return 'Es wurde kein Benutzer mit dem Benutzernamen \"$username\" gefunden.';
}
@override
String get searchUsernameNewFollowerTitle => 'Folgeanfragen';
@override
String get searchUsernameQrCodeBtn => 'QR-Code scannen';
@override
String get chatListViewSearchUserNameBtn => 'Füge deinen ersten twonly-Kontakt hinzu!';
@override
String get chatListViewSendFirstTwonly => 'Sende dein erstes twonly!';
@override
String get chatListDetailInput => 'Nachricht eingeben';
@override
String get contextMenuVerifyUser => 'Verifizieren';
@override
String get contextMenuArchiveUser => 'Archivieren';
@override
String get contextMenuUndoArchiveUser => 'Archivierung aufheben';
@override
String get contextMenuOpenChat => 'Chat';
@override
String get contextMenuSendImage => 'Bild senden';
@override
String get mediaViewerAuthReason => 'Bitte authentifiziere dich, um diesen twonly zu sehen!';
@override
String get messageSendState_Received => 'Empfangen';
@override
String get messageSendState_Opened => 'Geöffnet';
@override
String get messageSendState_Send => 'Gesendet';
@override
String get messageSendState_Sending => 'Wird gesendet';
@override
String get messageSendState_TapToLoad => 'Tippe zum Laden';
@override
String get messageSendState_Loading => 'Herunterladen';
@override
String get messageStoredInGalery => 'In Gallerie gespeichert';
@override
String get imageEditorDrawOk => 'Zeichnung machen';
@override
String get settingsTitle => 'Einstellungen';
@override
String get settingsChats => 'Chats';
@override
String get settingsPreSelectedReactions => 'Vorgewählte Reaktions-Emojis';
@override
String get settingsPreSelectedReactionsError => 'Es können maximal 12 Reaktionen ausgewählt werden.';
@override
String get settingsProfile => 'Profil';
@override
String get settingsProfileCustomizeAvatar => 'Avatar anpassen';
@override
String get settingsProfileEditDisplayName => 'Anzeigename';
@override
String get settingsProfileEditDisplayNameNew => 'Neuer Anzeigename';
@override
String get settingsAccount => 'Konto';
@override
String get settingsSubscription => 'Abonnement';
@override
String get settingsAppearance => 'Erscheinungsbild';
@override
String get settingsPrivacy => 'Datenschutz';
@override
String get settingsPrivacyBlockUsers => 'Benutzer blockieren';
@override
String get settingsPrivacyBlockUsersDesc => 'Blockierte Benutzer können nicht mit dir kommunizieren. Du kannst einen blockierten Benutzer jederzeit wieder entsperren.';
@override
String settingsPrivacyBlockUsersCount(Object len) {
return '$len Kontakt(e)';
}
@override
String get settingsNotification => 'Benachrichtigung';
@override
String get settingsNotifyTroubleshooting => 'Fehlersuche';
@override
String get settingsNotifyTroubleshootingDesc => 'Hier klicken, wenn Probleme beim Empfang von Push-Benachrichtigungen auftreten.';
@override
String get settingsNotifyTroubleshootingNoProblem => 'Kein Problem festgestellt';
@override
String get settingsNotifyTroubleshootingNoProblemDesc => 'Klicke auf OK, um eine Testbenachrichtigung zu erhalten. Wenn du auch nach 10 Minuten warten keine Nachricht erhältst, sende uns bitte dein Diagnoseprotokoll unter Einstellungen > Hilfe > Diagnoseprotokoll, damit wir uns das Problem ansehen können.';
@override
String get settingsHelp => 'Hilfe';
@override
String get settingsHelpDiagnostics => 'Diagnoseprotokoll';
@override
String get settingsHelpSupport => 'Support-Center';
@override
String get settingsHelpVersion => 'Version';
@override
String get settingsHelpLicenses => 'Lizenzen (Source-Code)';
@override
String get settingsHelpCredits => 'Lizenzen (Bilder)';
@override
String get settingsHelpLegal => 'Impressum, Nutzungsbedingungen & Datenschutzrichtlinie';
@override
String get settingsAppearanceTheme => 'Theme';
@override
String get settingsAccountDeleteAccount => 'Konto löschen';
@override
String get settingsAccountDeleteModalTitle => 'Bist du sicher?';
@override
String get settingsAccountDeleteModalBody => 'Dein Konto wird gelöscht. Es gibt keine Möglichkeit, es wiederherzustellen.';
@override
String get contactVerifyNumberTitle => 'Sicherheitsnummer verifizieren';
@override
String get contactVerifyNumberMarkAsVerified => 'Als verifiziert markieren';
@override
String get contactVerifyNumberClearVerification => 'Verifizierung aufheben';
@override
String contactVerifyNumberLongDesc(Object username) {
return 'Um die Ende-zu-Ende-Verschlüsselung mit $username zu verifizieren, vergleiche die Zahlen mit ihrem Gerät. Die Person kann auch deinen Code mit ihrem Gerät scannen.';
}
@override
String get contactNickname => 'Spitzname';
@override
String get contactNicknameNew => 'Neuer Spitzname';
@override
String get deleteAllContactMessages => 'Alle Nachrichten löschen';
@override
String deleteAllContactMessagesBody(Object username) {
return 'Dadurch werden alle Nachrichten in deinem Chat mit $username gelöscht. Dies löscht NICHT die auf dem Gerät von $username gespeicherten Nachrichten!';
}
@override
String get contactBlock => 'Blockieren';
@override
String contactBlockTitle(Object username) {
return 'Blockiere $username';
}
@override
String get contactBlockBody => 'Ein blockierter Benutzer kann dir keine Nachrichten mehr senden, und sein Profil ist nicht mehr sichtbar. Um die Blockierung eines Benutzers aufzuheben, navigiere einfach zu Einstellungen > Datenschutz > Blockierte Benutzer.';
@override
String get undo => 'Rückgängig';
@override
String get redo => 'Wiederholen';
@override
String get next => 'Weiter';
@override
String get close => 'Schließen';
@override
String get cancel => 'Abbrechen';
@override
String get ok => 'Ok';
@override
String get switchFrontAndBackCamera => 'Zwischen Front- und Rückkamera wechseln.';
@override
String get addTextItem => 'Text';
@override
String get protectAsARealTwonly => 'Als echtes twonly senden!';
@override
String get addDrawing => 'Zeichnung';
@override
String get addEmoji => 'Emoji';
@override
String get toggleFlashLight => 'Taschenlampe umschalten';
@override
String get toggleHighQuality => 'Bessere Auflösung umschalten';
@override
String get userFound => 'Benutzer gefunden';
@override
String get userFoundBody => 'Möchtest du eine Folgeanfrage stellen?';
@override
String searchUsernameNotFoundLong(Object username) {
return '\"$username\" ist kein twonly-Benutzer. Bitte überprüfe den Benutzernamen und versuche es erneut.';
}
@override
String get errorUnknown => 'Ein unerwarteter Fehler ist aufgetreten. Bitte versuche es später erneut.';
@override
String get errorBadRequest => 'Die Anfrage konnte vom Server aufgrund einer fehlerhaften Syntax nicht verstanden werden. Bitte überprüfe deine Eingabe und versuche es erneut.';
@override
String get errorTooManyRequests => 'Du hast in kurzer Zeit zu viele Anfragen gestellt. Bitte warte einen Moment, bevor du es erneut versuchst.';
@override
String get errorInternalError => 'Der Server ist derzeit nicht verfügbar. Bitte versuche es später erneut.';
@override
String get errorInvalidInvitationCode => 'Der von dir angegebene Einladungscode ist ungültig. Bitte überprüfe den Code und versuche es erneut.';
@override
String get errorUsernameAlreadyTaken => 'Der Benutzername, den du verwenden möchtest, ist bereits vergeben. Bitte wähle einen anderen Benutzernamen.';
@override
String get errorSignatureNotValid => 'Die bereitgestellte Signatur ist nicht gültig. Bitte überprüfe deine Anmeldeinformationen und versuche es erneut.';
@override
String get errorUsernameNotFound => 'Der eingegebene Benutzername existiert nicht. Bitte überprüfe die Schreibweise oder erstelle ein neues Konto.';
@override
String get errorUsernameNotValid => 'Der von dir angegebene Benutzername entspricht nicht den erforderlichen Kriterien. Bitte wähle einen gültigen Benutzernamen.';
@override
String get errorInvalidPublicKey => 'Der von dir angegebene öffentliche Schlüssel ist ungültig. Bitte überprüfe den Schlüssel und versuche es erneut.';
@override
String get errorSessionAlreadyAuthenticated => 'Du bist bereits angemeldet. Bitte melde dich ab, wenn du dich mit einem anderen Konto anmelden möchtest.';
@override
String get errorSessionNotAuthenticated => 'Deine Sitzung ist nicht authentifiziert. Bitte melde dich an, um fortzufahren.';
@override
String get errorOnlyOneSessionAllowed => 'Es ist nur eine aktive Sitzung pro Benutzer erlaubt. Bitte melde dich von anderen Geräten ab, um fortzufahren.';
}

View file

@ -0,0 +1,424 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for English (`en`).
class AppLocalizationsEn extends AppLocalizations {
AppLocalizationsEn([String locale = 'en']) : super(locale);
@override
String get registerTitle => 'Welcome to twonly!';
@override
String get registerSlogan => 'twonly, a privacy friendly way to connect with friends through secure, spontaneous image sharing';
@override
String get onboardingWelcomeTitle => 'Welcome to twonly!';
@override
String get onboardingWelcomeBody => 'Experience a private and secure way to stay in touch with friends by sharing instant pictures.';
@override
String get onboardingE2eTitle => 'Carefree sharing';
@override
String get onboardingE2eBody => 'With end-to-end encryption, enjoy the peace of mind that only you and your friends can see the moments you share.';
@override
String get onboardingFocusTitle => 'Focus on sharing moments';
@override
String get onboardingFocusBody => 'Say goodbye to addictive features! twonly was created for sharing moments, free from useless distractions or ads.';
@override
String get onboardingSendTwonliesTitle => 'Send twonlies';
@override
String get onboardingSendTwonliesBody => 'Share moments securely with your partner. twonly ensures that only your partner can open it, keeping your moments with your partner a two(o)nly thing!';
@override
String get onboardingNotProductTitle => 'You are not the product!';
@override
String get onboardingNotProductBody => 'twonly is financed by a small monthly fee and not by selling your data.';
@override
String get onboardingBuyOneGetTwoTitle => 'Buy one get two';
@override
String get onboardingBuyOneGetTwoBody => 'twonly always requires at least two people, which is why you receive a second free license for your twonly partner with your purchase.';
@override
String get onboardingGetStartedTitle => 'Let\'s go!';
@override
String get onboardingGetStartedBody => 'You can test twonly free of charge for 14 days, after that it costs either 1€/month or 9€/year.';
@override
String get onboardingTryForFree => 'Try for free';
@override
String get registerUsernameSlogan => 'Please select a username so others can find you!';
@override
String get registerUsernameDecoration => 'Username';
@override
String get registerUsernameLimits => 'Username must be 3 to 12 characters long, consisting only of letters (a-z) and numbers (0-9).';
@override
String get registerSubmitButton => 'Register now!';
@override
String get newMessageTitle => 'New message';
@override
String get chatsTapToSend => 'Click to send your first image';
@override
String get cameraPreviewSendTo => 'Send to';
@override
String get shareImageTitle => 'Share with';
@override
String get shareImageBestFriends => 'Best friends';
@override
String get shareImagedEditorSendImage => 'Send';
@override
String get shareImagedEditorShareWith => 'Share with';
@override
String get shareImagedEditorSaveImage => 'Save';
@override
String get shareImagedEditorSavedImage => 'Saved';
@override
String get shareImageSearchAllContacts => 'Search all contacts';
@override
String get startNewChatTitle => 'Select Contact';
@override
String get startNewChatNewContact => 'New Contact';
@override
String get startNewChatYourContacts => 'Your Contacts';
@override
String get shareImageAllUsers => 'All contacts';
@override
String get shareImageAllTwonlyWarning => 'twonlies can only be send to verified contacts!';
@override
String get searchUsernameInput => 'Username';
@override
String get searchUsernameTitle => 'Search username';
@override
String get searchUserNamePending => 'Pending';
@override
String get searchUserNameBlockUserTooltip => 'Block the user without informing.';
@override
String get searchUserNameRejectUserTooltip => 'Reject the request and let the requester know.';
@override
String get searchUserNameArchiveUserTooltip => 'Archive the user. He will appear again as soon as he accepts your request.';
@override
String get searchUsernameNotFound => 'Username not found';
@override
String searchUsernameNotFoundBody(Object username) {
return 'There is no user with the username \"$username\" registered';
}
@override
String get searchUsernameNewFollowerTitle => 'Follow requests';
@override
String get searchUsernameQrCodeBtn => 'Scan QR code';
@override
String get chatListViewSearchUserNameBtn => 'Add your first twonly contact!';
@override
String get chatListViewSendFirstTwonly => 'Send your first twonly!';
@override
String get chatListDetailInput => 'Type a message';
@override
String get contextMenuVerifyUser => 'Verify';
@override
String get contextMenuArchiveUser => 'Archive';
@override
String get contextMenuUndoArchiveUser => 'Undo archiving';
@override
String get contextMenuOpenChat => 'Open chat';
@override
String get contextMenuSendImage => 'Send image';
@override
String get mediaViewerAuthReason => 'Please authenticate to see this twonly!';
@override
String get messageSendState_Received => 'Received';
@override
String get messageSendState_Opened => 'Opened';
@override
String get messageSendState_Send => 'Sent';
@override
String get messageSendState_Sending => 'Sending';
@override
String get messageSendState_TapToLoad => 'Tap to load';
@override
String get messageSendState_Loading => 'Downloading';
@override
String get messageStoredInGalery => 'Stored in gallery';
@override
String get imageEditorDrawOk => 'Take drawing';
@override
String get settingsTitle => 'Settings';
@override
String get settingsChats => 'Chats';
@override
String get settingsPreSelectedReactions => 'Preselected reaction emojis';
@override
String get settingsPreSelectedReactionsError => 'A maximum of 12 reactions can be selected.';
@override
String get settingsProfile => 'Profile';
@override
String get settingsProfileCustomizeAvatar => 'Customize your avatar';
@override
String get settingsProfileEditDisplayName => 'Displayname';
@override
String get settingsProfileEditDisplayNameNew => 'New Displayname';
@override
String get settingsAccount => 'Konto';
@override
String get settingsSubscription => 'Subscription';
@override
String get settingsAppearance => 'Appearance';
@override
String get settingsPrivacy => 'Privacy';
@override
String get settingsPrivacyBlockUsers => 'Block users';
@override
String get settingsPrivacyBlockUsersDesc => 'Blocked users will not be able to communicate with you. You can unblock a blocked user at any time.';
@override
String settingsPrivacyBlockUsersCount(Object len) {
return '$len contact(s)';
}
@override
String get settingsNotification => 'Notification';
@override
String get settingsNotifyTroubleshooting => 'Troubleshooting';
@override
String get settingsNotifyTroubleshootingDesc => 'Click here if you have problems receiving push notifications.';
@override
String get settingsNotifyTroubleshootingNoProblem => 'No problem detected';
@override
String get settingsNotifyTroubleshootingNoProblemDesc => 'Press OK to receive a test notification. When you receive no message even after waiting for 10 minutes, please send us your debug log in Settings > Help > Debug log, so we can look at that issue.';
@override
String get settingsHelp => 'Help';
@override
String get settingsHelpDiagnostics => 'Diagnostic protocol';
@override
String get settingsHelpSupport => 'Support Center';
@override
String get settingsHelpVersion => 'Version';
@override
String get settingsHelpLicenses => 'Licenses (Source-Code)';
@override
String get settingsHelpCredits => 'Licenses (Images)';
@override
String get settingsHelpLegal => 'Imprint, Terms & Privacy Policy';
@override
String get settingsAppearanceTheme => 'Theme';
@override
String get settingsAccountDeleteAccount => 'Delete account';
@override
String get settingsAccountDeleteModalTitle => 'Are you sure?';
@override
String get settingsAccountDeleteModalBody => 'Your account will be deleted. There is no change to restore it.';
@override
String get contactVerifyNumberTitle => 'Verify safety number';
@override
String get contactVerifyNumberMarkAsVerified => 'Mark as verified';
@override
String get contactVerifyNumberClearVerification => 'Clear verification';
@override
String contactVerifyNumberLongDesc(Object username) {
return 'To verify the end-to-end encryption with $username, compare the numbers with their device. The person can also scan your code with their device.';
}
@override
String get contactNickname => 'Nickname';
@override
String get contactNicknameNew => 'New nickname';
@override
String get deleteAllContactMessages => 'Delete all messages';
@override
String deleteAllContactMessagesBody(Object username) {
return 'This will remove all messages in your chat with $username. This will NOT delete the messages stored at ${username}s device!';
}
@override
String get contactBlock => 'Block';
@override
String contactBlockTitle(Object username) {
return 'Block $username';
}
@override
String get contactBlockBody => 'A blocked user will no longer be able to send you messages and their profile will be hidden from view. To unblock a user, simply navigate to Settings > Privacy > Blocked Users.';
@override
String get undo => 'Undo';
@override
String get redo => 'Redo';
@override
String get next => 'Next';
@override
String get close => 'Close';
@override
String get cancel => 'Cancel';
@override
String get ok => 'Ok';
@override
String get switchFrontAndBackCamera => 'Switch between front and back camera.';
@override
String get addTextItem => 'Text';
@override
String get protectAsARealTwonly => 'Send as real twonly!';
@override
String get addDrawing => 'Drawing';
@override
String get addEmoji => 'Emoji';
@override
String get toggleFlashLight => 'Toggle the flash light';
@override
String get toggleHighQuality => 'Toggle better resolution';
@override
String get userFound => 'User found';
@override
String get userFoundBody => 'Do you want to create a follow request?';
@override
String searchUsernameNotFoundLong(Object username) {
return '\"$username\" is not a twonly user. Please check the username and try again.';
}
@override
String get errorUnknown => 'An unexpected error has occurred. Please try again later.';
@override
String get errorBadRequest => 'The request could not be understood by the server due to malformed syntax. Please check your input and try again.';
@override
String get errorTooManyRequests => 'You have made too many requests in a short period. Please wait a moment before trying again.';
@override
String get errorInternalError => 'The server is currently not available. Please try again later.';
@override
String get errorInvalidInvitationCode => 'The invitation code you provided is invalid. Please check the code and try again.';
@override
String get errorUsernameAlreadyTaken => 'The username you want to use is already taken. Please choose a different username.';
@override
String get errorSignatureNotValid => 'The provided signature is not valid. Please check your credentials and try again.';
@override
String get errorUsernameNotFound => 'The username you entered does not exist. Please check the spelling or create a new account.';
@override
String get errorUsernameNotValid => 'The username you provided does not meet the required criteria. Please choose a valid username.';
@override
String get errorInvalidPublicKey => 'The public key you provided is invalid. Please check the key and try again.';
@override
String get errorSessionAlreadyAuthenticated => 'You are already logged in. Please log out if you want to log in with a different account.';
@override
String get errorSessionNotAuthenticated => 'Your session is not authenticated. Please log in to continue.';
@override
String get errorOnlyOneSessionAllowed => 'Only one active session is allowed per user. Please log out from other devices to continue.';
}

View file

@ -1,6 +1,6 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:twonly/src/utils/json.dart'; import 'dart:convert';
part 'signal_identity.g.dart'; part 'signal_identity.g.dart';
@JsonSerializable() @JsonSerializable()
@ -16,3 +16,16 @@ class SignalIdentity {
_$SignalIdentityFromJson(json); _$SignalIdentityFromJson(json);
Map<String, dynamic> toJson() => _$SignalIdentityToJson(this); Map<String, dynamic> toJson() => _$SignalIdentityToJson(this);
} }
class Uint8ListConverter implements JsonConverter<Uint8List, String> {
const Uint8ListConverter();
@override
Uint8List fromJson(String json) {
return base64Decode(json);
}
@override
String toJson(Uint8List object) {
return base64Encode(object);
}
}

View file

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'userdata.g.dart'; part 'userdata.g.dart';
@ -15,9 +16,12 @@ class UserData {
String? avatarSvg; String? avatarSvg;
String? avatarJson; String? avatarJson;
int? avatarCounter; int? avatarCounter;
// settings
int? defaultShowTime; int? defaultShowTime;
bool? useHighQuality; bool? useHighQuality;
List<String>? preSelectedEmojies; List<String>? preSelectedEmojies;
ThemeMode? themeMode;
final int userId; final int userId;

View file

@ -18,7 +18,8 @@ UserData _$UserDataFromJson(Map<String, dynamic> json) => UserData(
..useHighQuality = json['useHighQuality'] as bool? ..useHighQuality = json['useHighQuality'] as bool?
..preSelectedEmojies = (json['preSelectedEmojies'] as List<dynamic>?) ..preSelectedEmojies = (json['preSelectedEmojies'] as List<dynamic>?)
?.map((e) => e as String) ?.map((e) => e as String)
.toList(); .toList()
..themeMode = $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']);
Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'username': instance.username, 'username': instance.username,
@ -29,5 +30,12 @@ Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
'defaultShowTime': instance.defaultShowTime, 'defaultShowTime': instance.defaultShowTime,
'useHighQuality': instance.useHighQuality, 'useHighQuality': instance.useHighQuality,
'preSelectedEmojies': instance.preSelectedEmojies, 'preSelectedEmojies': instance.preSelectedEmojies,
'themeMode': _$ThemeModeEnumMap[instance.themeMode],
'userId': instance.userId, 'userId': instance.userId,
}; };
const _$ThemeModeEnumMap = {
ThemeMode.system: 'system',
ThemeMode.light: 'light',
ThemeMode.dark: 'dark',
};

View file

@ -7,9 +7,9 @@ import 'package:mutex/mutex.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/json_models/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:twonly/src/providers/api/api_utils.dart'; import 'package:twonly/src/providers/api/api_utils.dart';
import 'package:twonly/src/providers/hive.dart'; import 'package:twonly/src/providers/hive.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';

View file

@ -1,8 +1,10 @@
import 'package:fixnum/fixnum.dart'; import 'package:fixnum/fixnum.dart';
import 'package:twonly/src/proto/api/client_to_server.pb.dart' as client; import 'package:twonly/src/model/protobuf/api/client_to_server.pb.dart'
import 'package:twonly/src/proto/api/client_to_server.pbserver.dart'; as client;
import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart';
import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart'
as server;
class Result<T, E> { class Result<T, E> {
final T? value; final T? value;

View file

@ -4,11 +4,11 @@ import 'package:drift/drift.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/app.dart'; import 'package:twonly/app.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/proto/api/server_to_client.pb.dart'; import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/api_utils.dart'; import 'package:twonly/src/providers/api/api_utils.dart';
import 'package:twonly/src/providers/hive.dart'; import 'package:twonly/src/providers/hive.dart';

View file

@ -7,15 +7,17 @@ import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/app.dart'; import 'package:twonly/app.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/proto/api/client_to_server.pb.dart' as client; import 'package:twonly/src/model/protobuf/api/client_to_server.pb.dart'
import 'package:twonly/src/proto/api/client_to_server.pbserver.dart'; as client;
import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart';
import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:twonly/src/proto/api/server_to_client.pbserver.dart'; import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart'
as server;
import 'package:twonly/src/model/protobuf/api/server_to_client.pbserver.dart';
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/api_utils.dart'; import 'package:twonly/src/providers/api/api_utils.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';
@ -115,9 +117,6 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
return client.Response()..ok = ok; return client.Response()..ok = ok;
} }
// Uint8List? rawBytes =
// await SignalHelper.decryptBytes(downloadedBytes, fromUserId);
Message? msg = await twonlyDatabase.messagesDao Message? msg = await twonlyDatabase.messagesDao
.getMessageByMessageId(messageId) .getMessageByMessageId(messageId)
.getSingleOrNull(); .getSingleOrNull();

View file

@ -5,14 +5,16 @@ import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:fixnum/fixnum.dart'; import 'package:fixnum/fixnum.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/app.dart'; import 'package:twonly/app.dart';
import 'package:twonly/src/proto/api/client_to_server.pbserver.dart'; import 'package:twonly/src/model/protobuf/api/client_to_server.pbserver.dart';
import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server; import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart'
as server;
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/api_utils.dart'; import 'package:twonly/src/providers/api/api_utils.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';
@ -220,7 +222,7 @@ class ApiProvider {
} }
Future<bool> tryAuthenticateWithToken(int userId) async { Future<bool> tryAuthenticateWithToken(int userId) async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
String? apiAuthToken = await storage.read(key: "api_auth_token"); String? apiAuthToken = await storage.read(key: "api_auth_token");
if (apiAuthToken != null) { if (apiAuthToken != null) {
@ -296,7 +298,7 @@ class ApiProvider {
Uint8List apiAuthToken = result2.value.authtoken; Uint8List apiAuthToken = result2.value.authtoken;
String apiAuthTokenB64 = base64Encode(apiAuthToken); String apiAuthTokenB64 = base64Encode(apiAuthToken);
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
await storage.write(key: "api_auth_token", value: apiAuthTokenB64); await storage.write(key: "api_auth_token", value: apiAuthTokenB64);
await tryAuthenticateWithToken(userData.userId); await tryAuthenticateWithToken(userData.userId);

View file

@ -1,12 +1,12 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart';
Future initMediaStorage() async { Future initMediaStorage() async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
var containsEncryptionKey = var containsEncryptionKey =
await storage.containsKey(key: 'hive_encryption_key'); await storage.containsKey(key: 'hive_encryption_key');
if (!containsEncryptionKey) { if (!containsEncryptionKey) {
@ -23,7 +23,7 @@ Future initMediaStorage() async {
Future<Box> getMediaStorage() async { Future<Box> getMediaStorage() async {
try { try {
await initMediaStorage(); await initMediaStorage();
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
var encryptionKey = var encryptionKey =
base64Url.decode((await storage.read(key: 'hive_encryption_key'))!); base64Url.decode((await storage.read(key: 'hive_encryption_key'))!);

View file

@ -1,43 +1,30 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/services/settings_service.dart'; import 'package:twonly/src/utils/storage.dart';
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin { class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
// Make SettingsService a private variable so it is not used directly.
final SettingsService _settingsService = SettingsService();
// Make ThemeMode a private variable so it is not updated directly without
// also persisting the changes with the SettingsService.
late ThemeMode _themeMode; late ThemeMode _themeMode;
// Allow Widgets to read the user's preferred ThemeMode.
ThemeMode get themeMode => _themeMode; ThemeMode get themeMode => _themeMode;
/// Load the user's settings from the SettingsService. It may load from a
/// local database or the internet. The controller only knows it can load the
/// settings from the service.
Future<void> loadSettings() async { Future<void> loadSettings() async {
_themeMode = await _settingsService.themeMode(); _themeMode = (await getUser())?.themeMode ?? ThemeMode.system;
// Important! Inform listeners a change has occurred.
notifyListeners(); notifyListeners();
} }
/// Update and persist the ThemeMode based on the user's selection.
Future<void> updateThemeMode(ThemeMode? newThemeMode) async { Future<void> updateThemeMode(ThemeMode? newThemeMode) async {
if (newThemeMode == null) return; if (newThemeMode == null) return;
// Do not perform any work if new and old ThemeMode are identical
if (newThemeMode == _themeMode) return; if (newThemeMode == _themeMode) return;
// Otherwise, store the new ThemeMode in memory
_themeMode = newThemeMode; _themeMode = newThemeMode;
// Important! Inform listeners a change has occurred.
notifyListeners(); notifyListeners();
// Persist the changes to a local database or the internet using the var user = await getUser();
// SettingService. if (user != null) {
await _settingsService.updateThemeMode(newThemeMode); user.themeMode = newThemeMode;
await updateUser(user);
}
} }
} }

View file

@ -1,7 +1,7 @@
import 'package:twonly/src/signal/connect_identitiy_key_store.dart'; import 'package:twonly/src/providers/signal/connect_identitiy_key_store.dart';
import 'package:twonly/src/signal/connect_pre_key_store.dart'; import 'package:twonly/src/providers/signal/connect_pre_key_store.dart';
import 'package:twonly/src/signal/connect_session_store.dart'; import 'package:twonly/src/providers/signal/connect_session_store.dart';
import 'package:twonly/src/signal/connect_signed_pre_key_store.dart'; import 'package:twonly/src/providers/signal/connect_signed_pre_key_store.dart';
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
class ConnectSignalProtocolStore implements SignalProtocolStore { class ConnectSignalProtocolStore implements SignalProtocolStore {

View file

@ -1,14 +1,14 @@
import 'dart:collection'; import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
import 'package:twonly/src/utils/misc.dart';
class ConnectSignedPreKeyStore extends SignedPreKeyStore { class ConnectSignedPreKeyStore extends SignedPreKeyStore {
// final store = HashMap<int, Uint8List>(); // final store = HashMap<int, Uint8List>();
Future<HashMap<int, Uint8List>> getStore() async { Future<HashMap<int, Uint8List>> getStore() async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
final storeSerialized = await storage.read(key: "signed_pre_key_store"); final storeSerialized = await storage.read(key: "signed_pre_key_store");
var store = HashMap<int, Uint8List>(); var store = HashMap<int, Uint8List>();
if (storeSerialized == null) { if (storeSerialized == null) {
@ -22,7 +22,7 @@ class ConnectSignedPreKeyStore extends SignedPreKeyStore {
} }
Future safeStore(HashMap<int, Uint8List> store) async { Future safeStore(HashMap<int, Uint8List> store) async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
var storeHashMap = []; var storeHashMap = [];
for (final item in store.entries) { for (final item in store.entries) {
storeHashMap.add([item.key, base64Encode(item.value)]); storeHashMap.add([item.key, base64Encode(item.value)]);

View file

@ -1,8 +1,9 @@
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/app.dart'; import 'package:twonly/app.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
@ -14,7 +15,7 @@ import '../../firebase_options.dart';
Future initFCMAfterAuthenticated() async { Future initFCMAfterAuthenticated() async {
if (globalIsAppInBackground) return; if (globalIsAppInBackground) return;
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
String? storedToken = await storage.read(key: "google_fcm"); String? storedToken = await storage.read(key: "google_fcm");

View file

@ -14,9 +14,8 @@ import 'package:twonly/globals.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/json_models/message.dart' as my; import 'package:twonly/src/model/json/message.dart' as my;
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/utils/misc.dart';
class PushUser { class PushUser {
String displayName; String displayName;
@ -324,7 +323,7 @@ Future handlePushData(String pushDataJson) async {
} }
Future<Map<int, PushUser>> getPushKeys(String storageKey) async { Future<Map<int, PushUser>> getPushKeys(String storageKey) async {
var storage = getSecureStorage(); var storage = FlutterSecureStorage();
String? pushKeysJson = await storage.read( String? pushKeysJson = await storage.read(
key: storageKey, key: storageKey,
iOptions: IOSOptions( iOptions: IOSOptions(
@ -344,7 +343,7 @@ Future<Map<int, PushUser>> getPushKeys(String storageKey) async {
} }
Future setPushKeys(String storageKey, Map<int, PushUser> pushKeys) async { Future setPushKeys(String storageKey, Map<int, PushUser> pushKeys) async {
var storage = getSecureStorage(); var storage = FlutterSecureStorage();
Map<String, dynamic> jsonToSend = {}; Map<String, dynamic> jsonToSend = {};
pushKeys.forEach((key, value) { pushKeys.forEach((key, value) {
jsonToSend[key.toString()] = value.toJson(); jsonToSend[key.toString()] = value.toJson();

View file

@ -1,17 +0,0 @@
import 'package:flutter/material.dart';
/// A service that stores and retrieves user settings.
///
/// By default, this class does not persist user settings. If you'd like to
/// persist the user settings locally, use the shared_preferences package. If
/// you'd like to store settings on a web server, use the http package.
class SettingsService {
/// Loads the User's preferred ThemeMode from local or remote storage.
Future<ThemeMode> themeMode() async => ThemeMode.system;
/// Persists the user's preferred ThemeMode to local or remote storage.
Future<void> updateThemeMode(ThemeMode theme) async {
// Use the shared_preferences package to persist settings locally or the
// http package to persist settings over the network.
}
}

View file

@ -1,16 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
import 'dart:convert';
import 'dart:typed_data';
class Uint8ListConverter implements JsonConverter<Uint8List, String> {
const Uint8ListConverter();
@override
Uint8List fromJson(String json) {
return base64Decode(json);
}
@override
String toJson(Uint8List object) {
return base64Encode(object);
}
}

View file

@ -9,12 +9,10 @@ import 'package:gal/gal.dart';
import 'package:local_auth/local_auth.dart'; import 'package:local_auth/local_auth.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:pie_menu/pie_menu.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/model/protobuf/api/error.pb.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:twonly/src/localization/generated/app_localizations.dart';
extension ShortCutsExtension on BuildContext { extension ShortCutsExtension on BuildContext {
AppLocalizations get lang => AppLocalizations.of(this)!; AppLocalizations get lang => AppLocalizations.of(this)!;
@ -45,15 +43,6 @@ Future<bool> deleteLogFile() async {
return false; return false;
} }
// Just a helper function to get the secure storage
FlutterSecureStorage getSecureStorage() {
// ignore: no_leading_underscores_for_local_identifiers
AndroidOptions _getAndroidOptions() => const AndroidOptions(
encryptedSharedPreferences: true,
);
return FlutterSecureStorage(aOptions: _getAndroidOptions());
}
Future<String?> saveImageToGallery(Uint8List imageBytes) async { Future<String?> saveImageToGallery(Uint8List imageBytes) async {
final hasAccess = await Gal.hasAccess(); final hasAccess = await Gal.hasAccess();
if (!hasAccess) { if (!hasAccess) {
@ -181,30 +170,6 @@ Future<bool> isAllowedToDownload() async {
return true; return true;
} }
PieTheme getPieCanvasTheme(BuildContext context) {
return PieTheme(
brightness: Theme.of(context).brightness,
rightClickShowsMenu: true,
radius: 70,
buttonTheme: PieButtonTheme(
backgroundColor: Theme.of(context).colorScheme.tertiary,
iconColor: Theme.of(context).colorScheme.surfaceBright,
),
buttonThemeHovered: PieButtonTheme(
backgroundColor: Theme.of(context).colorScheme.primary,
iconColor: Theme.of(context).colorScheme.surfaceBright,
),
tooltipPadding: EdgeInsets.all(20),
overlayColor: const Color.fromARGB(41, 0, 0, 0),
// spacing: 0,
tooltipTextStyle: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w600,
),
);
}
void setupLogger() { void setupLogger() {
Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL; Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL;
Logger.root.onRecord.listen((record) async { Logger.root.onRecord.listen((record) async {
@ -215,3 +180,25 @@ void setupLogger() {
} }
}); });
} }
Uint8List intToBytes(int value) {
final byteData = ByteData(4);
byteData.setInt32(0, value, Endian.big);
return byteData.buffer.asUint8List();
}
int bytesToInt(Uint8List bytes) {
final byteData = ByteData.sublistView(bytes);
return byteData.getInt32(0, Endian.big);
}
List<Uint8List>? removeLastXBytes(Uint8List original, int count) {
if (original.length < count) {
return null;
}
final newList = Uint8List(original.length - count);
newList.setAll(0, original.sublist(0, original.length - count));
final lastXBytes = original.sublist(original.length - count);
return [newList, lastXBytes];
}

View file

@ -1,13 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/json_models/signal_identity.dart'; import 'package:twonly/src/model/json/signal_identity.dart';
import 'package:twonly/src/json_models/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/proto/api/server_to_client.pb.dart'; import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
import 'package:twonly/src/signal/connect_signal_protocol_store.dart'; import 'package:twonly/src/providers/signal/connect_signal_protocol_store.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
@ -88,7 +89,7 @@ Future<ConnectSignalProtocolStore?> getSignalStore() async {
Future<SignalIdentity?> getSignalIdentity() async { Future<SignalIdentity?> getSignalIdentity() async {
try { try {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
final signalIdentityJson = await storage.read(key: "signal_identity"); final signalIdentityJson = await storage.read(key: "signal_identity");
if (signalIdentityJson == null) { if (signalIdentityJson == null) {
return null; return null;
@ -120,7 +121,7 @@ Future<List<PreKeyRecord>> getPreKeys() async {
} }
Future createIfNotExistsSignalIdentity() async { Future createIfNotExistsSignalIdentity() async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
final signalIdentity = await storage.read(key: "signal_identity"); final signalIdentity = await storage.read(key: "signal_identity");
if (signalIdentity != null) { if (signalIdentity != null) {
@ -172,81 +173,6 @@ Future<Fingerprint?> generateSessionFingerPrint(int target) async {
} }
} }
Uint8List intToBytes(int value) {
final byteData = ByteData(4);
byteData.setInt32(0, value, Endian.big);
return byteData.buffer.asUint8List();
}
int bytesToInt(Uint8List bytes) {
final byteData = ByteData.sublistView(bytes);
return byteData.getInt32(0, Endian.big);
}
List<Uint8List>? removeLastFourBytes(Uint8List original) {
if (original.length < 4) {
return null;
}
final newList = Uint8List(original.length - 4);
newList.setAll(0, original.sublist(0, original.length - 4));
final lastFourBytes = original.sublist(original.length - 4);
return [newList, lastFourBytes];
}
Future<Uint8List?> encryptBytes(Uint8List bytes, int target) async {
try {
ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
SessionCipher session = SessionCipher.fromStore(
signalStore, SignalProtocolAddress(target.toString(), defaultDeviceId));
final ciphertext =
await session.encrypt(Uint8List.fromList(gzip.encode(bytes)));
var b = BytesBuilder();
b.add(ciphertext.serialize());
b.add(intToBytes(ciphertext.getType()));
return b.takeBytes();
} catch (e) {
Logger("utils/signal").shout(e.toString());
return null;
}
}
Future<Uint8List?> decryptBytes(Uint8List bytes, int target) async {
try {
ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
SessionCipher session = SessionCipher.fromStore(
signalStore, SignalProtocolAddress(target.toString(), defaultDeviceId));
List<Uint8List>? msgs = removeLastFourBytes(bytes);
if (msgs == null) return null;
Uint8List body = msgs[0];
int type = bytesToInt(msgs[1]);
Uint8List plaintext;
Logger("utils/signal").info("got signal type: $type!");
if (type == CiphertextMessage.prekeyType) {
PreKeySignalMessage pre = PreKeySignalMessage(body);
plaintext = await session.decrypt(pre);
} else if (type == CiphertextMessage.whisperType) {
SignalMessage signalMsg = SignalMessage.fromSerialized(body);
plaintext = await session.decryptFromSignal(signalMsg);
} else {
Logger("utils/signal").shout("signal type is not known: $type!");
return null;
}
List<int>? plainBytes = gzip.decode(Uint8List.fromList(plaintext));
return Uint8List.fromList(plainBytes);
} catch (e) {
Logger("utils/signal").shout(e.toString());
return null;
}
}
Future<Uint8List?> encryptMessage(MessageJson msg, int target) async { Future<Uint8List?> encryptMessage(MessageJson msg, int target) async {
try { try {
ConnectSignalProtocolStore signalStore = (await getSignalStore())!; ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
@ -275,7 +201,7 @@ Future<MessageJson?> getDecryptedText(int source, Uint8List msg) async {
SessionCipher session = SessionCipher.fromStore( SessionCipher session = SessionCipher.fromStore(
signalStore, SignalProtocolAddress(source.toString(), defaultDeviceId)); signalStore, SignalProtocolAddress(source.toString(), defaultDeviceId));
List<Uint8List>? msgs = removeLastFourBytes(msg); List<Uint8List>? msgs = removeLastXBytes(msg, 4);
if (msgs == null) return null; if (msgs == null) return null;
Uint8List body = msgs[0]; Uint8List body = msgs[0];
int type = bytesToInt(msgs[1]); int type = bytesToInt(msgs[1]);

View file

@ -1,8 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:twonly/src/json_models/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/utils/misc.dart';
Future<bool> isUserCreated() async { Future<bool> isUserCreated() async {
UserData? user = await getUser(); UserData? user = await getUser();
@ -13,7 +13,7 @@ Future<bool> isUserCreated() async {
} }
Future<UserData?> getUser() async { Future<UserData?> getUser() async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
String? userJson = await storage.read(key: "userData"); String? userJson = await storage.read(key: "userData");
if (userJson == null) { if (userJson == null) {
return null; return null;
@ -29,7 +29,7 @@ Future<UserData?> getUser() async {
} }
Future updateUser(UserData userData) async { Future updateUser(UserData userData) async {
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
storage.write(key: "userData", value: jsonEncode(userData)); storage.write(key: "userData", value: jsonEncode(userData));
} }
@ -38,7 +38,7 @@ Future<bool> deleteLocalUserData() async {
if (appDir.existsSync()) { if (appDir.existsSync()) {
appDir.deleteSync(recursive: true); appDir.deleteSync(recursive: true);
} }
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
await storage.deleteAll(); await storage.deleteAll();
return true; return true;
} }

View file

@ -1,21 +1,21 @@
import 'dart:io'; import 'dart:io';
import 'dart:typed_data';
import 'package:camera/camera.dart'; import 'package:camera/camera.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_volume_controller/flutter_volume_controller.dart'; import 'package:flutter_volume_controller/flutter_volume_controller.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:screenshot/screenshot.dart'; import 'package:screenshot/screenshot.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/zoom_selector.dart'; import 'package:twonly/src/views/camera/components/zoom_selector.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/views/camera/image_editor/action_button.dart';
import 'package:twonly/src/components/media_view_sizing.dart'; import 'package:twonly/src/views/components/media_view_sizing.dart';
import 'package:twonly/src/components/permissions_view.dart'; import 'package:twonly/src/views/components/permissions_view.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/camera_to_share/share_image_editor_view.dart'; import 'package:twonly/src/views/camera/share_image_editor_view.dart';
class CameraPreviewView extends StatefulWidget { class CameraPreviewView extends StatefulWidget {
const CameraPreviewView({super.key, this.sendTo}); const CameraPreviewView({super.key, this.sendTo});
@ -91,12 +91,16 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
setState(() { setState(() {
isZoomAble = false; isZoomAble = false;
}); });
controller = CameraController(gCameras[sCameraId], ResolutionPreset.high, controller = CameraController(
enableAudio: false); gCameras[sCameraId],
ResolutionPreset.high,
enableAudio: false,
);
controller.initialize().then((_) async { controller.initialize().then((_) async {
if (!mounted) { if (!mounted) {
return; return;
} }
await controller.lockCaptureOrientation(DeviceOrientation.portraitUp);
controller.setFlashMode(isFlashOn ? FlashMode.always : FlashMode.off); controller.setFlashMode(isFlashOn ? FlashMode.always : FlashMode.off);
isZoomAble = await controller.getMinZoomLevel() != isZoomAble = await controller.getMinZoomLevel() !=
@ -146,12 +150,15 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
await File(picture.path).delete(); await File(picture.path).delete();
return imageBytes; return imageBytes;
} catch (e) { } catch (e) {
if (context.mounted) {
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Error loading picture: $e'), content: Text('Error loading picture: $e'),
duration: Duration(seconds: 3), duration: Duration(seconds: 3),
), ),
); );
}
return null; return null;
} }
} }
@ -174,12 +181,18 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
final XFile picture = await controller.takePicture(); final XFile picture = await controller.takePicture();
imageBytes = loadAndDeletePictureFromFile(picture); imageBytes = loadAndDeletePictureFromFile(picture);
} catch (e) { } catch (e) {
try {
if (context.mounted) {
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Error taking picture: $e'), content: Text('Error taking picture: $e'),
duration: Duration(seconds: 3), duration: Duration(seconds: 3),
), ),
); );
}
// ignore: empty_catches
} catch (e) {}
return; return;
} }
} else { } else {
@ -237,6 +250,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
if (!context.mounted) return true; if (!context.mounted) return true;
if (shoudReturn != null && shoudReturn) { if (shoudReturn != null && shoudReturn) {
if (!context.mounted) return true; if (!context.mounted) return true;
// ignore: use_build_context_synchronously
Navigator.pop(context); Navigator.pop(context);
return true; return true;
} }
@ -409,8 +423,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
imageFile.readAsBytes())) { imageFile.readAsBytes())) {
return; return;
} }
} else {
print('No image selected.');
} }
setState(() { setState(() {
galleryLoadedImageIsShown = false; galleryLoadedImageIsShown = false;

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/views/camera_to_share/camera_preview_view.dart'; import 'package:twonly/src/views/camera/camera_preview_view.dart';
class CameraSendToView extends StatefulWidget { class CameraSendToView extends StatefulWidget {
const CameraSendToView(this.sendTo, {super.key}); const CameraSendToView(this.sendTo, {super.key});

View file

@ -1,13 +1,13 @@
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/verified_shield.dart'; import 'package:twonly/src/views/components/verified_shield.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/components/flame.dart'; import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/components/headline.dart'; import 'package:twonly/src/views/components/headline.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
class BestFriendsSelector extends StatelessWidget { class BestFriendsSelector extends StatelessWidget {
final List<Contact> users; final List<Contact> users;

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hand_signature/signature.dart'; import 'package:hand_signature/signature.dart';
import 'package:twonly/src/components/image_editor/data/image_item.dart'; import 'package:twonly/src/views/camera/image_editor/data/image_item.dart';
/// Layer class with some common properties /// Layer class with some common properties
class Layer { class Layer {

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
/// Main layer /// Main layer
class BackgroundLayer extends StatefulWidget { class BackgroundLayer extends StatefulWidget {

View file

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hand_signature/signature.dart'; import 'package:hand_signature/signature.dart';
import 'package:screenshot/screenshot.dart'; import 'package:screenshot/screenshot.dart';
import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/views/camera/image_editor/action_button.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
class DrawLayer extends StatefulWidget { class DrawLayer extends StatefulWidget {

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/views/camera/image_editor/action_button.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
/// Emoji layer /// Emoji layer
class EmojiLayer extends StatefulWidget { class EmojiLayer extends StatefulWidget {

View file

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
import 'package:twonly/src/components/image_editor/layers/filters/datetime_filter.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filters/datetime_filter.dart';
import 'package:twonly/src/components/image_editor/layers/filters/image_filter.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filters/image_filter.dart';
import 'package:twonly/src/components/image_editor/layers/filters/location_filter.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filters/location_filter.dart';
/// Main layer /// Main layer
class FilterLayer extends StatefulWidget { class FilterLayer extends StatefulWidget {

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart';
class DateTimeFilter extends StatelessWidget { class DateTimeFilter extends StatelessWidget {
const DateTimeFilter({super.key, this.color = Colors.white}); const DateTimeFilter({super.key, this.color = Colors.white});

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart';
class ImageFilter extends StatelessWidget { class ImageFilter extends StatelessWidget {
const ImageFilter({super.key, required this.imagePath}); const ImageFilter({super.key, required this.imagePath});

View file

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart';
import 'package:twonly/src/components/image_editor/layers/filters/datetime_filter.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filters/datetime_filter.dart';
import 'package:twonly/src/proto/api/server_to_client.pb.dart'; import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';

View file

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/views/camera/image_editor/action_button.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
/// Text layer /// Text layer
class TextLayer extends StatefulWidget { class TextLayer extends StatefulWidget {

View file

@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
import 'package:twonly/src/components/image_editor/layers/background_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/background_layer.dart';
import 'package:twonly/src/components/image_editor/layers/draw_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/draw_layer.dart';
import 'package:twonly/src/components/image_editor/layers/emoji_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/emoji_layer.dart';
import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/filter_layer.dart';
import 'package:twonly/src/components/image_editor/layers/text_layer.dart'; import 'package:twonly/src/views/camera/image_editor/layers/text_layer.dart';
/// View stacked layers (unbounded height, width) /// View stacked layers (unbounded height, width)
class LayersViewer extends StatelessWidget { class LayersViewer extends StatelessWidget {

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/image_editor/data/data.dart'; import 'package:twonly/src/views/camera/image_editor/data/data.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
class Emojis extends StatefulWidget { class Emojis extends StatefulWidget {
const Emojis({super.key}); const Emojis({super.key});

View file

@ -1,21 +1,21 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/image_editor/action_button.dart'; import 'package:twonly/src/views/camera/image_editor/action_button.dart';
import 'package:twonly/src/components/media_view_sizing.dart'; import 'package:twonly/src/views/components/media_view_sizing.dart';
import 'package:twonly/src/components/notification_badge.dart'; import 'package:twonly/src/views/components/notification_badge.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/camera_to_share/share_image_view.dart'; import 'package:twonly/src/views/camera/share_image_view.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:twonly/src/components/image_editor/data/image_item.dart'; import 'package:twonly/src/views/camera/image_editor/data/image_item.dart';
import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/views/camera/image_editor/data/layer.dart';
import 'package:twonly/src/components/image_editor/layers_viewer.dart'; import 'package:twonly/src/views/camera/image_editor/layers_viewer.dart';
import 'package:twonly/src/components/image_editor/modules/all_emojis.dart'; import 'package:twonly/src/views/camera/image_editor/modules/all_emojis.dart';
import 'package:screenshot/screenshot.dart'; import 'package:screenshot/screenshot.dart';
List<Layer> layers = []; List<Layer> layers = [];
@ -32,6 +32,7 @@ class ShareImageEditorView extends StatefulWidget {
} }
class _ShareImageEditorView extends State<ShareImageEditorView> { class _ShareImageEditorView extends State<ShareImageEditorView> {
bool imageLoadedReady = false;
bool _imageSaved = false; bool _imageSaved = false;
bool _imageSaving = false; bool _imageSaving = false;
bool _isRealTwonly = false; bool _isRealTwonly = false;
@ -246,6 +247,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
Future<void> loadImage(Future<Uint8List?> imageFile) async { Future<void> loadImage(Future<Uint8List?> imageFile) async {
Uint8List? imageBytes = await imageFile; Uint8List? imageBytes = await imageFile;
await currentImage.load(imageBytes); await currentImage.load(imageBytes);
if (!context.mounted) return; if (!context.mounted) return;
layers.clear(); layers.clear();
@ -256,7 +258,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
layers.add(FilterLayerData()); layers.add(FilterLayerData());
setState(() {}); setState(() {
imageLoadedReady = true;
});
} }
@override @override
@ -268,7 +272,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
} }
return Scaffold( return Scaffold(
backgroundColor: Colors.white.withAlpha(0), backgroundColor: imageLoadedReady ? null : Colors.white.withAlpha(0),
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand,

View file

@ -4,11 +4,11 @@ import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/best_friends_selector.dart'; import 'package:twonly/src/views/camera/components/best_friends_selector.dart';
import 'package:twonly/src/components/flame.dart'; import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/components/headline.dart'; import 'package:twonly/src/views/components/headline.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/components/verified_shield.dart'; import 'package:twonly/src/views/components/verified_shield.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';

View file

@ -5,19 +5,19 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/animate_icon.dart'; import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/components/better_text.dart'; import 'package:twonly/src/views/components/better_text.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/components/message_send_state_icon.dart'; import 'package:twonly/src/views/components/message_send_state_icon.dart';
import 'package:twonly/src/components/verified_shield.dart'; import 'package:twonly/src/views/components/verified_shield.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/views/camera_to_share/camera_send_to_view.dart'; import 'package:twonly/src/views/camera/camera_send_to_view.dart';
import 'package:twonly/src/views/chats/media_viewer_view.dart'; import 'package:twonly/src/views/chats/media_viewer_view.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/contact/contact_view.dart'; import 'package:twonly/src/views/contact/contact_view.dart';

View file

@ -3,20 +3,20 @@ import 'dart:convert';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/connection_state.dart'; import 'package:twonly/src/views/components/connection_state.dart';
import 'package:twonly/src/components/flame.dart'; import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/components/message_send_state_icon.dart'; import 'package:twonly/src/views/components/message_send_state_icon.dart';
import 'package:twonly/src/components/notification_badge.dart'; import 'package:twonly/src/views/components/notification_badge.dart';
import 'package:twonly/src/components/user_context_menu.dart'; import 'package:twonly/src/views/components/user_context_menu.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';
import 'package:twonly/src/providers/connection_provider.dart'; import 'package:twonly/src/providers/connection_provider.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/camera_to_share/camera_send_to_view.dart'; import 'package:twonly/src/views/camera/camera_send_to_view.dart';
import 'package:twonly/src/views/chats/chat_item_details_view.dart'; import 'package:twonly/src/views/chats/chat_item_details_view.dart';
import 'package:twonly/src/views/chats/media_viewer_view.dart'; import 'package:twonly/src/views/chats/media_viewer_view.dart';
import 'package:twonly/src/views/chats/start_new_chat.dart'; import 'package:twonly/src/views/chats/start_new_chat.dart';

View file

@ -6,17 +6,17 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:lottie/lottie.dart'; import 'package:lottie/lottie.dart';
import 'package:no_screenshot/no_screenshot.dart'; import 'package:no_screenshot/no_screenshot.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/animate_icon.dart'; import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/components/media_view_sizing.dart'; import 'package:twonly/src/views/components/media_view_sizing.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/api/media.dart'; import 'package:twonly/src/providers/api/media.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/camera_to_share/camera_send_to_view.dart'; import 'package:twonly/src/views/camera/camera_send_to_view.dart';
import 'package:twonly/src/views/chats/chat_item_details_view.dart'; import 'package:twonly/src/views/chats/chat_item_details_view.dart';
final _noScreenshot = NoScreenshot.instance; final _noScreenshot = NoScreenshot.instance;
@ -131,6 +131,7 @@ class _MediaViewerViewState extends State<MediaViewerView> {
if (isRealTwonly) { if (isRealTwonly) {
if (!context.mounted) return; if (!context.mounted) return;
// ignore: use_build_context_synchronously
bool isAuth = await authenticateUser(context.lang.mediaViewerAuthReason, bool isAuth = await authenticateUser(context.lang.mediaViewerAuthReason,
force: false); force: false);
if (!isAuth) { if (!isAuth) {
@ -464,7 +465,6 @@ class _MediaViewerViewState extends State<MediaViewerView> {
}, },
), ),
Expanded( Expanded(
child: Container(
child: TextField( child: TextField(
autofocus: true, autofocus: true,
controller: textMessageController, controller: textMessageController,
@ -477,7 +477,6 @@ class _MediaViewerViewState extends State<MediaViewerView> {
decoration: inputTextMessageDeco(context), decoration: inputTextMessageDeco(context),
), ),
), ),
),
IconButton( IconButton(
icon: FaIcon(FontAwesomeIcons.solidPaperPlane), icon: FaIcon(FontAwesomeIcons.solidPaperPlane),
onPressed: () { onPressed: () {
@ -628,7 +627,7 @@ class EmojiReactionWidget extends StatefulWidget {
}); });
@override @override
_EmojiReactionWidgetState createState() => _EmojiReactionWidgetState(); State<EmojiReactionWidget> createState() => _EmojiReactionWidgetState();
} }
class _EmojiReactionWidgetState extends State<EmojiReactionWidget> { class _EmojiReactionWidgetState extends State<EmojiReactionWidget> {

View file

@ -3,16 +3,16 @@ import 'package:drift/drift.dart' hide Column;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/src/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/headline.dart'; import 'package:twonly/src/views/components/headline.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
// ignore: library_prefixes // ignore: library_prefixes
import 'package:twonly/src/utils/signal.dart' as SignalHelper; import 'package:twonly/src/utils/signal.dart' as SignalHelper;

View file

@ -4,9 +4,9 @@ import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:pie_menu/pie_menu.dart'; import 'package:pie_menu/pie_menu.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/flame.dart'; import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/components/user_context_menu.dart'; import 'package:twonly/src/views/components/user_context_menu.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/animate_icon.dart'; import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
class FlameCounterWidget extends StatelessWidget { class FlameCounterWidget extends StatelessWidget {

View file

@ -1,8 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:logging/logging.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/json_models/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
class ContactAvatar extends StatelessWidget { class ContactAvatar extends StatelessWidget {
final Contact? contact; final Contact? contact;
@ -47,7 +48,7 @@ class ContactAvatar extends StatelessWidget {
child: SvgPicture.string( child: SvgPicture.string(
avatarSvg, avatarSvg,
errorBuilder: (context, error, stackTrace) { errorBuilder: (context, error, stackTrace) {
print("Error: $error"); Logger("ui.avater").shout("$error");
return Container(); return Container();
}, },
), ),

View file

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/tables/messages_table.dart';
import 'package:twonly/src/json_models/message.dart'; import 'package:twonly/src/model/json/message.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
enum MessageSendState { enum MessageSendState {

View file

@ -5,7 +5,7 @@ import 'package:pie_menu/pie_menu.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/camera_to_share/camera_send_to_view.dart'; import 'package:twonly/src/views/camera/camera_send_to_view.dart';
import 'package:twonly/src/views/chats/chat_item_details_view.dart'; import 'package:twonly/src/views/chats/chat_item_details_view.dart';
import 'package:twonly/src/views/contact/contact_verify_view.dart'; import 'package:twonly/src/views/contact/contact_verify_view.dart';
@ -89,3 +89,27 @@ class _UserContextMenuState extends State<UserContextMenu> {
); );
} }
} }
PieTheme getPieCanvasTheme(BuildContext context) {
return PieTheme(
brightness: Theme.of(context).brightness,
rightClickShowsMenu: true,
radius: 70,
buttonTheme: PieButtonTheme(
backgroundColor: Theme.of(context).colorScheme.tertiary,
iconColor: Theme.of(context).colorScheme.surfaceBright,
),
buttonThemeHovered: PieButtonTheme(
backgroundColor: Theme.of(context).colorScheme.primary,
iconColor: Theme.of(context).colorScheme.surfaceBright,
),
tooltipPadding: EdgeInsets.all(20),
overlayColor: const Color.fromARGB(41, 0, 0, 0),
// spacing: 0,
tooltipTextStyle: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w600,
),
);
}

View file

@ -4,7 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/format_long_string.dart'; import 'package:twonly/src/views/components/format_long_string.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';

View file

@ -1,11 +1,11 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/components/better_list_title.dart'; import 'package:twonly/src/views/components/better_list_title.dart';
import 'package:twonly/src/components/flame.dart'; import 'package:twonly/src/views/components/flame.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/components/verified_shield.dart'; import 'package:twonly/src/views/components/verified_shield.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';

View file

@ -1,9 +1,9 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:pie_menu/pie_menu.dart'; import 'package:pie_menu/pie_menu.dart';
import 'package:twonly/src/views/components/user_context_menu.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'camera/camera_preview_view.dart';
import 'camera_to_share/camera_preview_view.dart';
import 'chats/chat_list_view.dart'; import 'chats/chat_list_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View file

@ -1,11 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:twonly/src/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/json_models/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/signal.dart'; import 'package:twonly/src/utils/signal.dart';
@ -30,7 +31,7 @@ class _RegisterViewState extends State<RegisterView> {
_isTryingToRegister = true; _isTryingToRegister = true;
}); });
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
await createIfNotExistsSignalIdentity(); await createIfNotExistsSignalIdentity();
@ -57,6 +58,7 @@ class _RegisterViewState extends State<RegisterView> {
} }
if (context.mounted) { if (context.mounted) {
// ignore: use_build_context_synchronously
showAlertDialog(context, "Oh no!", errorCodeToText(context, res.error)); showAlertDialog(context, "Oh no!", errorCodeToText(context, res.error));
} }
} }

View file

@ -1,6 +1,6 @@
import 'package:restart_app/restart_app.dart'; import 'package:restart_app/restart_app.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/src/components/radio_button.dart'; import 'package:twonly/src/views/components/radio_button.dart';
import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/providers/settings_change_provider.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/src/components/animate_icon.dart'; import 'package:twonly/src/views/components/animate_icon.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/utils/storage.dart';

View file

@ -2,8 +2,9 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/alert_dialog.dart'; import 'package:twonly/src/views/components/alert_dialog.dart';
import 'package:twonly/src/services/fcm_service.dart'; import 'package:twonly/src/services/fcm_service.dart';
import 'package:twonly/src/services/notification_service.dart'; import 'package:twonly/src/services/notification_service.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
@ -25,7 +26,7 @@ class NotificationView extends StatelessWidget {
subtitle: Text(context.lang.settingsNotifyTroubleshootingDesc), subtitle: Text(context.lang.settingsNotifyTroubleshootingDesc),
onTap: () async { onTap: () async {
await initFCMAfterAuthenticated(); await initFCMAfterAuthenticated();
final storage = getSecureStorage(); final storage = FlutterSecureStorage();
String? storedToken = await storage.read(key: "google_fcm"); String? storedToken = await storage.read(key: "google_fcm");
await setupNotificationWithUsers(force: true); await setupNotificationWithUsers(force: true);
if (!context.mounted) return; if (!context.mounted) return;

View file

@ -1,7 +1,7 @@
import 'package:drift/drift.dart' hide Column; import 'package:drift/drift.dart' hide Column;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/initialsavatar.dart'; import 'package:twonly/src/views/components/initialsavatar.dart';
import 'package:twonly/src/database/daos/contacts_dao.dart'; import 'package:twonly/src/database/daos/contacts_dao.dart';
import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/database/twonly_database.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';

View file

@ -3,7 +3,7 @@ import 'package:avatar_maker/avatar_maker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/src/json_models/userdata.dart'; import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/providers/api/api.dart'; import 'package:twonly/src/providers/api/api.dart';
import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/providers/settings_change_provider.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';

Some files were not shown because too many files have changed in this diff Show more