mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 16:28:40 +00:00
refactor, update and rotation fix
This commit is contained in:
parent
8f29461f72
commit
f5b4e35e18
106 changed files with 2262 additions and 551 deletions
|
|
@ -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'
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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());
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -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(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
933
lib/src/localization/generated/app_localizations.dart
Normal file
933
lib/src/localization/generated/app_localizations.dart
Normal 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, you’ll need to edit this
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||||
|
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||||
|
/// project’s 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.'
|
||||||
|
);
|
||||||
|
}
|
||||||
424
lib/src/localization/generated/app_localizations_de.dart
Normal file
424
lib/src/localization/generated/app_localizations_de.dart
Normal 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.';
|
||||||
|
}
|
||||||
424
lib/src/localization/generated/app_localizations_en.dart
Normal file
424
lib/src/localization/generated/app_localizations_en.dart
Normal 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.';
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
@ -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',
|
||||||
|
};
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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'))!);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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)]);
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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});
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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});
|
||||||
|
|
@ -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});
|
||||||
|
|
@ -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';
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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});
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -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';
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -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 {
|
||||||
|
|
@ -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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in a new issue