switch to google fcm fix #14

This commit is contained in:
otsmr 2025-02-12 01:00:14 +01:00
parent 7a8e14c3be
commit 1b1da8c481
24 changed files with 558 additions and 65 deletions

25
.vscode/launch.json vendored
View file

@ -1,25 +0,0 @@
{
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Connect-App",
"request": "launch",
"type": "dart",
},
{
"name": "Connect-App (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "Connect-App (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View file

@ -1,5 +0,0 @@
{
"cSpell.words": [
"thounthends"
]
}

View file

@ -1,10 +1,19 @@
plugins { plugins {
id "com.android.application" id "com.android.application"
// START: FlutterFire Configuration
id 'com.google.gms.google-services'
// END: FlutterFire Configuration
id "kotlin-android" id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin" id "dev.flutter.flutter-gradle-plugin"
} }
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android { android {
namespace = "com.example.connect" namespace = "com.example.connect"
// compileSdk = flutter.compileSdkVersion // compileSdk = flutter.compileSdkVersion
@ -33,12 +42,18 @@ android {
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName
} }
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. signingConfig signingConfigs.release
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
} }
} }
} }

View file

@ -0,0 +1,48 @@
{
"project_info": {
"project_number": "650346093942",
"project_id": "twonly-ff605",
"storage_bucket": "twonly-ff605.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:650346093942:android:040816fb819b1bfb81ae57",
"android_client_info": {
"package_name": "eu.twonly"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyA4d5ORP11WpuVgmoYtWmOcMzZYWLPVtBk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650346093942:android:706cb87c3131dabe81ae57",
"android_client_info": {
"package_name": "eu.twonly.testing"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyA4d5ORP11WpuVgmoYtWmOcMzZYWLPVtBk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View file

@ -19,6 +19,9 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.3.2" apply false id "com.android.application" version "8.3.2" apply false
// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.3.15" apply false
// END: FlutterFire Configuration
id "org.jetbrains.kotlin.android" version "2.0.20" apply false id "org.jetbrains.kotlin.android" version "2.0.20" apply false
} }

1
firebase.json Normal file
View file

@ -0,0 +1 @@
{"flutter":{"platforms":{"android":{"default":{"projectId":"twonly-ff605","appId":"1:650346093942:android:706cb87c3131dabe81ae57","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"twonly-ff605","appId":"1:650346093942:ios:e80075ff3de823c581ae57","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"twonly-ff605","configurations":{"android":"1:650346093942:android:706cb87c3131dabe81ae57","ios":"1:650346093942:ios:e80075ff3de823c581ae57"}}}}}}

View file

@ -14,6 +14,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F3C66D726A2EB28484DF0B10 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -42,6 +43,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
@ -94,6 +96,7 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
16FBC6F5B58E1C6646F5D447 /* GoogleService-Info.plist */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -216,6 +219,7 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
F3C66D726A2EB28484DF0B10 /* GoogleService-Info.plist in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>AIzaSyDr7MEoz2XvrYxU0kYvZVVjej53q0gANnE</string>
<key>GCM_SENDER_ID</key>
<string>650346093942</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.example.connect</string>
<key>PROJECT_ID</key>
<string>twonly-ff605</string>
<key>STORAGE_BUCKET</key>
<string>twonly-ff605.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:650346093942:ios:e80075ff3de823c581ae57</string>
</dict>
</plist>

68
lib/firebase_options.dart Normal file
View file

@ -0,0 +1,68 @@
// File generated by FlutterFire CLI.
// ignore_for_file: type=lint
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for web - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyA4d5ORP11WpuVgmoYtWmOcMzZYWLPVtBk',
appId: '1:650346093942:android:706cb87c3131dabe81ae57',
messagingSenderId: '650346093942',
projectId: 'twonly-ff605',
storageBucket: 'twonly-ff605.firebasestorage.app',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyDr7MEoz2XvrYxU0kYvZVVjej53q0gANnE',
appId: '1:650346093942:ios:e80075ff3de823c581ae57',
messagingSenderId: '650346093942',
projectId: 'twonly-ff605',
storageBucket: 'twonly-ff605.firebasestorage.app',
iosBundleId: 'com.example.connect',
);
}

View file

@ -12,7 +12,9 @@ import 'package:twonly/src/providers/messages_change_provider.dart';
import 'package:twonly/src/providers/contacts_change_provider.dart'; import 'package:twonly/src/providers/contacts_change_provider.dart';
import 'package:twonly/src/providers/send_next_media_to.dart'; import 'package:twonly/src/providers/send_next_media_to.dart';
import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/providers/settings_change_provider.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 'src/app.dart'; import 'src/app.dart';
void main() async { void main() async {
@ -26,16 +28,16 @@ void main() async {
Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL; Logger.root.level = kReleaseMode ? Level.INFO : Level.ALL;
Logger.root.onRecord.listen((record) { Logger.root.onRecord.listen((record) {
// if (kReleaseMode) { writeLogToFile(record);
// writeLogToFile(record); if (kDebugMode) {
// } else {
print( print(
'${record.level.name}: twonly:${record.loggerName}: ${record.message}'); '${record.level.name}: twonly:${record.loggerName}: ${record.message}');
// } }
}); });
await setupPushNotification(); await setupPushNotification();
await initMediaStorage(); await initMediaStorage();
await initFCMService();
dbProvider = DbProvider(); dbProvider = DbProvider();
await dbProvider.ready; await dbProvider.ready;

View file

@ -73,17 +73,17 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
.updateLastMessageFor(userId, messageId); .updateLastMessageFor(userId, messageId);
}; };
WidgetsBinding.instance.addPostFrameCallback((_) { // WidgetsBinding.instance.addPostFrameCallback((_) {
_requestPermissions(); // _requestPermissions();
_initService(); // _initService();
}); // });
initAsync(); initAsync();
} }
Future initAsync() async { Future initAsync() async {
// make sure the front end service will be killed // make sure the front end service will be killed
FlutterForegroundTask.sendDataToTask(""); // FlutterForegroundTask.sendDataToTask("");
await FlutterForegroundTask.stopService(); // await FlutterForegroundTask.stopService();
// connect async to the backend api // connect async to the backend api
apiProvider.connect(); apiProvider.connect();
} }
@ -177,13 +177,15 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
if (state == AppLifecycleState.resumed) { if (state == AppLifecycleState.resumed) {
if (wasPaused) { if (wasPaused) {
globalIsAppInBackground = false; globalIsAppInBackground = false;
_stopService(); apiProvider.connect();
// _stopService();
} }
} else if (state == AppLifecycleState.paused) { } else if (state == AppLifecycleState.paused) {
wasPaused = true; wasPaused = true;
globalIsAppInBackground = true; globalIsAppInBackground = true;
apiProvider.close(() { apiProvider.close(() {
_startService(); // use this only when uploading an image
// _startService();
}); });
} }
} }

View file

@ -57,6 +57,7 @@
"settingsNotification": "Benachrichtigung", "settingsNotification": "Benachrichtigung",
"settingsHelp": "Hilfe", "settingsHelp": "Hilfe",
"settingsHelpSupport": "Support-Center", "settingsHelpSupport": "Support-Center",
"settingsHelpDiagnostics": "Diagnoseprotokoll",
"settingsHelpVersion": "Version", "settingsHelpVersion": "Version",
"settingsHelpLicenses": "Lizenzen", "settingsHelpLicenses": "Lizenzen",
"settingsHelpLegal": "Nutzungsbedingungen & Datenschutzrichtlinie", "settingsHelpLegal": "Nutzungsbedingungen & Datenschutzrichtlinie",

View file

@ -56,6 +56,7 @@
"settingsPrivacyBlockUsersCount": "{len} contact(s)", "settingsPrivacyBlockUsersCount": "{len} contact(s)",
"settingsNotification": "Notification", "settingsNotification": "Notification",
"settingsHelp": "Help", "settingsHelp": "Help",
"settingsHelpDiagnostics": "Diagnostic protocol",
"settingsHelpSupport": "Support Center", "settingsHelpSupport": "Support Center",
"settingsHelpVersion": "Version", "settingsHelpVersion": "Version",
"settingsHelpLicenses": "Licenses", "settingsHelpLicenses": "Licenses",

View file

@ -641,6 +641,56 @@ class ApplicationData_GetUserByUsername extends $pb.GeneratedMessage {
void clearUsername() => clearField(1); void clearUsername() => clearField(1);
} }
class ApplicationData_UpdateGoogleFcmToken extends $pb.GeneratedMessage {
factory ApplicationData_UpdateGoogleFcmToken({
$core.String? googleFcm,
}) {
final $result = create();
if (googleFcm != null) {
$result.googleFcm = googleFcm;
}
return $result;
}
ApplicationData_UpdateGoogleFcmToken._() : super();
factory ApplicationData_UpdateGoogleFcmToken.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory ApplicationData_UpdateGoogleFcmToken.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ApplicationData.UpdateGoogleFcmToken', package: const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'), createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'googleFcm')
..hasRequiredFields = false
;
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
ApplicationData_UpdateGoogleFcmToken clone() => ApplicationData_UpdateGoogleFcmToken()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
ApplicationData_UpdateGoogleFcmToken copyWith(void Function(ApplicationData_UpdateGoogleFcmToken) updates) => super.copyWith((message) => updates(message as ApplicationData_UpdateGoogleFcmToken)) as ApplicationData_UpdateGoogleFcmToken;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static ApplicationData_UpdateGoogleFcmToken create() => ApplicationData_UpdateGoogleFcmToken._();
ApplicationData_UpdateGoogleFcmToken createEmptyInstance() => create();
static $pb.PbList<ApplicationData_UpdateGoogleFcmToken> createRepeated() => $pb.PbList<ApplicationData_UpdateGoogleFcmToken>();
@$core.pragma('dart2js:noInline')
static ApplicationData_UpdateGoogleFcmToken getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ApplicationData_UpdateGoogleFcmToken>(create);
static ApplicationData_UpdateGoogleFcmToken? _defaultInstance;
@$pb.TagNumber(1)
$core.String get googleFcm => $_getSZ(0);
@$pb.TagNumber(1)
set googleFcm($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasGoogleFcm() => $_has(0);
@$pb.TagNumber(1)
void clearGoogleFcm() => clearField(1);
}
class ApplicationData_GetUserById extends $pb.GeneratedMessage { class ApplicationData_GetUserById extends $pb.GeneratedMessage {
factory ApplicationData_GetUserById({ factory ApplicationData_GetUserById({
$fixnum.Int64? userId, $fixnum.Int64? userId,
@ -923,6 +973,7 @@ enum ApplicationData_ApplicationData {
uploaddata, uploaddata,
getuserbyid, getuserbyid,
downloaddata, downloaddata,
updategooglefcmtoken,
notSet notSet
} }
@ -935,6 +986,7 @@ class ApplicationData extends $pb.GeneratedMessage {
ApplicationData_UploadData? uploaddata, ApplicationData_UploadData? uploaddata,
ApplicationData_GetUserById? getuserbyid, ApplicationData_GetUserById? getuserbyid,
ApplicationData_DownloadData? downloaddata, ApplicationData_DownloadData? downloaddata,
ApplicationData_UpdateGoogleFcmToken? updategooglefcmtoken,
}) { }) {
final $result = create(); final $result = create();
if (textmessage != null) { if (textmessage != null) {
@ -958,6 +1010,9 @@ class ApplicationData extends $pb.GeneratedMessage {
if (downloaddata != null) { if (downloaddata != null) {
$result.downloaddata = downloaddata; $result.downloaddata = downloaddata;
} }
if (updategooglefcmtoken != null) {
$result.updategooglefcmtoken = updategooglefcmtoken;
}
return $result; return $result;
} }
ApplicationData._() : super(); ApplicationData._() : super();
@ -972,10 +1027,11 @@ class ApplicationData extends $pb.GeneratedMessage {
5 : ApplicationData_ApplicationData.uploaddata, 5 : ApplicationData_ApplicationData.uploaddata,
6 : ApplicationData_ApplicationData.getuserbyid, 6 : ApplicationData_ApplicationData.getuserbyid,
7 : ApplicationData_ApplicationData.downloaddata, 7 : ApplicationData_ApplicationData.downloaddata,
8 : ApplicationData_ApplicationData.updategooglefcmtoken,
0 : ApplicationData_ApplicationData.notSet 0 : ApplicationData_ApplicationData.notSet
}; };
static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ApplicationData', package: const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'), createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ApplicationData', package: const $pb.PackageName(_omitMessageNames ? '' : 'client_to_server'), createEmptyInstance: create)
..oo(0, [1, 2, 3, 4, 5, 6, 7]) ..oo(0, [1, 2, 3, 4, 5, 6, 7, 8])
..aOM<ApplicationData_TextMessage>(1, _omitFieldNames ? '' : 'textmessage', subBuilder: ApplicationData_TextMessage.create) ..aOM<ApplicationData_TextMessage>(1, _omitFieldNames ? '' : 'textmessage', subBuilder: ApplicationData_TextMessage.create)
..aOM<ApplicationData_GetUserByUsername>(2, _omitFieldNames ? '' : 'getuserbyusername', subBuilder: ApplicationData_GetUserByUsername.create) ..aOM<ApplicationData_GetUserByUsername>(2, _omitFieldNames ? '' : 'getuserbyusername', subBuilder: ApplicationData_GetUserByUsername.create)
..aOM<ApplicationData_GetPrekeysByUserId>(3, _omitFieldNames ? '' : 'getprekeysbyuserid', subBuilder: ApplicationData_GetPrekeysByUserId.create) ..aOM<ApplicationData_GetPrekeysByUserId>(3, _omitFieldNames ? '' : 'getprekeysbyuserid', subBuilder: ApplicationData_GetPrekeysByUserId.create)
@ -983,6 +1039,7 @@ class ApplicationData extends $pb.GeneratedMessage {
..aOM<ApplicationData_UploadData>(5, _omitFieldNames ? '' : 'uploaddata', subBuilder: ApplicationData_UploadData.create) ..aOM<ApplicationData_UploadData>(5, _omitFieldNames ? '' : 'uploaddata', subBuilder: ApplicationData_UploadData.create)
..aOM<ApplicationData_GetUserById>(6, _omitFieldNames ? '' : 'getuserbyid', subBuilder: ApplicationData_GetUserById.create) ..aOM<ApplicationData_GetUserById>(6, _omitFieldNames ? '' : 'getuserbyid', subBuilder: ApplicationData_GetUserById.create)
..aOM<ApplicationData_DownloadData>(7, _omitFieldNames ? '' : 'downloaddata', subBuilder: ApplicationData_DownloadData.create) ..aOM<ApplicationData_DownloadData>(7, _omitFieldNames ? '' : 'downloaddata', subBuilder: ApplicationData_DownloadData.create)
..aOM<ApplicationData_UpdateGoogleFcmToken>(8, _omitFieldNames ? '' : 'updategooglefcmtoken', subBuilder: ApplicationData_UpdateGoogleFcmToken.create)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -1086,6 +1143,17 @@ class ApplicationData extends $pb.GeneratedMessage {
void clearDownloaddata() => clearField(7); void clearDownloaddata() => clearField(7);
@$pb.TagNumber(7) @$pb.TagNumber(7)
ApplicationData_DownloadData ensureDownloaddata() => $_ensure(6); ApplicationData_DownloadData ensureDownloaddata() => $_ensure(6);
@$pb.TagNumber(8)
ApplicationData_UpdateGoogleFcmToken get updategooglefcmtoken => $_getN(7);
@$pb.TagNumber(8)
set updategooglefcmtoken(ApplicationData_UpdateGoogleFcmToken v) { setField(8, v); }
@$pb.TagNumber(8)
$core.bool hasUpdategooglefcmtoken() => $_has(7);
@$pb.TagNumber(8)
void clearUpdategooglefcmtoken() => clearField(8);
@$pb.TagNumber(8)
ApplicationData_UpdateGoogleFcmToken ensureUpdategooglefcmtoken() => $_ensure(7);
} }
class Response_PreKey extends $pb.GeneratedMessage { class Response_PreKey extends $pb.GeneratedMessage {

View file

@ -122,8 +122,9 @@ const ApplicationData$json = {
{'1': 'uploaddata', '3': 5, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.UploadData', '9': 0, '10': 'uploaddata'}, {'1': 'uploaddata', '3': 5, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.UploadData', '9': 0, '10': 'uploaddata'},
{'1': 'getuserbyid', '3': 6, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.GetUserById', '9': 0, '10': 'getuserbyid'}, {'1': 'getuserbyid', '3': 6, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.GetUserById', '9': 0, '10': 'getuserbyid'},
{'1': 'downloaddata', '3': 7, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.DownloadData', '9': 0, '10': 'downloaddata'}, {'1': 'downloaddata', '3': 7, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.DownloadData', '9': 0, '10': 'downloaddata'},
{'1': 'updategooglefcmtoken', '3': 8, '4': 1, '5': 11, '6': '.client_to_server.ApplicationData.UpdateGoogleFcmToken', '9': 0, '10': 'updategooglefcmtoken'},
], ],
'3': [ApplicationData_TextMessage$json, ApplicationData_GetUserByUsername$json, ApplicationData_GetUserById$json, ApplicationData_GetPrekeysByUserId$json, ApplicationData_GetUploadToken$json, ApplicationData_UploadData$json, ApplicationData_DownloadData$json], '3': [ApplicationData_TextMessage$json, ApplicationData_GetUserByUsername$json, ApplicationData_UpdateGoogleFcmToken$json, ApplicationData_GetUserById$json, ApplicationData_GetPrekeysByUserId$json, ApplicationData_GetUploadToken$json, ApplicationData_UploadData$json, ApplicationData_DownloadData$json],
'8': [ '8': [
{'1': 'ApplicationData'}, {'1': 'ApplicationData'},
], ],
@ -146,6 +147,14 @@ const ApplicationData_GetUserByUsername$json = {
], ],
}; };
@$core.Deprecated('Use applicationDataDescriptor instead')
const ApplicationData_UpdateGoogleFcmToken$json = {
'1': 'UpdateGoogleFcmToken',
'2': [
{'1': 'google_fcm', '3': 1, '4': 1, '5': 9, '10': 'googleFcm'},
],
};
@$core.Deprecated('Use applicationDataDescriptor instead') @$core.Deprecated('Use applicationDataDescriptor instead')
const ApplicationData_GetUserById$json = { const ApplicationData_GetUserById$json = {
'1': 'GetUserById', '1': 'GetUserById',
@ -199,14 +208,17 @@ final $typed_data.Uint8List applicationDataDescriptor = $convert.base64Decode(
'dGlvbkRhdGEuVXBsb2FkRGF0YUgAUgp1cGxvYWRkYXRhElEKC2dldHVzZXJieWlkGAYgASgLMi' 'dGlvbkRhdGEuVXBsb2FkRGF0YUgAUgp1cGxvYWRkYXRhElEKC2dldHVzZXJieWlkGAYgASgLMi'
'0uY2xpZW50X3RvX3NlcnZlci5BcHBsaWNhdGlvbkRhdGEuR2V0VXNlckJ5SWRIAFILZ2V0dXNl' '0uY2xpZW50X3RvX3NlcnZlci5BcHBsaWNhdGlvbkRhdGEuR2V0VXNlckJ5SWRIAFILZ2V0dXNl'
'cmJ5aWQSVAoMZG93bmxvYWRkYXRhGAcgASgLMi4uY2xpZW50X3RvX3NlcnZlci5BcHBsaWNhdG' 'cmJ5aWQSVAoMZG93bmxvYWRkYXRhGAcgASgLMi4uY2xpZW50X3RvX3NlcnZlci5BcHBsaWNhdG'
'lvbkRhdGEuRG93bmxvYWREYXRhSABSDGRvd25sb2FkZGF0YRo6CgtUZXh0TWVzc2FnZRIXCgd1' 'lvbkRhdGEuRG93bmxvYWREYXRhSABSDGRvd25sb2FkZGF0YRJsChR1cGRhdGVnb29nbGVmY210'
'c2VyX2lkGAEgASgDUgZ1c2VySWQSEgoEYm9keRgDIAEoDFIEYm9keRovChFHZXRVc2VyQnlVc2' 'b2tlbhgIIAEoCzI2LmNsaWVudF90b19zZXJ2ZXIuQXBwbGljYXRpb25EYXRhLlVwZGF0ZUdvb2'
'VybmFtZRIaCgh1c2VybmFtZRgBIAEoCVIIdXNlcm5hbWUaJgoLR2V0VXNlckJ5SWQSFwoHdXNl' 'dsZUZjbVRva2VuSABSFHVwZGF0ZWdvb2dsZWZjbXRva2VuGjoKC1RleHRNZXNzYWdlEhcKB3Vz'
'cl9pZBgBIAEoA1IGdXNlcklkGi0KEkdldFByZWtleXNCeVVzZXJJZBIXCgd1c2VyX2lkGAEgAS' 'ZXJfaWQYASABKANSBnVzZXJJZBISCgRib2R5GAMgASgMUgRib2R5Gi8KEUdldFVzZXJCeVVzZX'
'gDUgZ1c2VySWQaEAoOR2V0VXBsb2FkVG9rZW4aWwoKVXBsb2FkRGF0YRIhCgx1cGxvYWRfdG9r' 'JuYW1lEhoKCHVzZXJuYW1lGAEgASgJUgh1c2VybmFtZRo1ChRVcGRhdGVHb29nbGVGY21Ub2tl'
'ZW4YASABKAxSC3VwbG9hZFRva2VuEhYKBm9mZnNldBgCIAEoDVIGb2Zmc2V0EhIKBGRhdGEYAy' 'bhIdCgpnb29nbGVfZmNtGAEgASgJUglnb29nbGVGY20aJgoLR2V0VXNlckJ5SWQSFwoHdXNlcl'
'ABKAxSBGRhdGEaSQoMRG93bmxvYWREYXRhEiEKDHVwbG9hZF90b2tlbhgBIAEoDFILdXBsb2Fk' '9pZBgBIAEoA1IGdXNlcklkGi0KEkdldFByZWtleXNCeVVzZXJJZBIXCgd1c2VyX2lkGAEgASgD'
'VG9rZW4SFgoGb2Zmc2V0GAIgASgNUgZvZmZzZXRCEQoPQXBwbGljYXRpb25EYXRh'); 'UgZ1c2VySWQaEAoOR2V0VXBsb2FkVG9rZW4aWwoKVXBsb2FkRGF0YRIhCgx1cGxvYWRfdG9rZW'
'4YASABKAxSC3VwbG9hZFRva2VuEhYKBm9mZnNldBgCIAEoDVIGb2Zmc2V0EhIKBGRhdGEYAyAB'
'KAxSBGRhdGEaSQoMRG93bmxvYWREYXRhEiEKDHVwbG9hZF90b2tlbhgBIAEoDFILdXBsb2FkVG'
'9rZW4SFgoGb2Zmc2V0GAIgASgNUgZvZmZzZXRCEQoPQXBwbGljYXRpb25EYXRh');
@$core.Deprecated('Use responseDescriptor instead') @$core.Deprecated('Use responseDescriptor instead')
const Response$json = { const Response$json = {

View file

@ -30,6 +30,7 @@ class ErrorCode extends $pb.ProtobufEnum {
static const ErrorCode UploadLimitReached = ErrorCode._(1011, _omitEnumNames ? '' : 'UploadLimitReached'); static const ErrorCode UploadLimitReached = ErrorCode._(1011, _omitEnumNames ? '' : 'UploadLimitReached');
static const ErrorCode InvalidUpdateToken = ErrorCode._(1012, _omitEnumNames ? '' : 'InvalidUpdateToken'); static const ErrorCode InvalidUpdateToken = ErrorCode._(1012, _omitEnumNames ? '' : 'InvalidUpdateToken');
static const ErrorCode InvalidOffset = ErrorCode._(1013, _omitEnumNames ? '' : 'InvalidOffset'); static const ErrorCode InvalidOffset = ErrorCode._(1013, _omitEnumNames ? '' : 'InvalidOffset');
static const ErrorCode InvalidGoogleFcmToken = ErrorCode._(1014, _omitEnumNames ? '' : 'InvalidGoogleFcmToken');
static const $core.List<ErrorCode> values = <ErrorCode> [ static const $core.List<ErrorCode> values = <ErrorCode> [
Unknown, Unknown,
@ -48,6 +49,7 @@ class ErrorCode extends $pb.ProtobufEnum {
UploadLimitReached, UploadLimitReached,
InvalidUpdateToken, InvalidUpdateToken,
InvalidOffset, InvalidOffset,
InvalidGoogleFcmToken,
]; ];
static final $core.Map<$core.int, ErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values); static final $core.Map<$core.int, ErrorCode> _byValue = $pb.ProtobufEnum.initByValue(values);

View file

@ -33,6 +33,7 @@ const ErrorCode$json = {
{'1': 'UploadLimitReached', '2': 1011}, {'1': 'UploadLimitReached', '2': 1011},
{'1': 'InvalidUpdateToken', '2': 1012}, {'1': 'InvalidUpdateToken', '2': 1012},
{'1': 'InvalidOffset', '2': 1013}, {'1': 'InvalidOffset', '2': 1013},
{'1': 'InvalidGoogleFcmToken', '2': 1014},
], ],
}; };
@ -45,5 +46,5 @@ final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode(
'bGljS2V5EO8HEiAKG1Nlc3Npb25BbHJlYWR5QXV0aGVudGljYXRlZBDwBxIcChdTZXNzaW9uTm' 'bGljS2V5EO8HEiAKG1Nlc3Npb25BbHJlYWR5QXV0aGVudGljYXRlZBDwBxIcChdTZXNzaW9uTm'
'90QXV0aGVudGljYXRlZBDxBxIaChVPbmx5T25lU2Vzc2lvbkFsbG93ZWQQ8gcSFwoSVXBsb2Fk' '90QXV0aGVudGljYXRlZBDxBxIaChVPbmx5T25lU2Vzc2lvbkFsbG93ZWQQ8gcSFwoSVXBsb2Fk'
'TGltaXRSZWFjaGVkEPMHEhcKEkludmFsaWRVcGRhdGVUb2tlbhD0BxISCg1JbnZhbGlkT2Zmc2' 'TGltaXRSZWFjaGVkEPMHEhcKEkludmFsaWRVcGRhdGVUb2tlbhD0BxISCg1JbnZhbGlkT2Zmc2'
'V0EPUH'); 'V0EPUHEhoKFUludmFsaWRHb29nbGVGY21Ub2tlbhD2Bw==');

View file

@ -11,6 +11,7 @@ import 'package:twonly/src/proto/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/server_messages.dart'; import 'package:twonly/src/providers/api/server_messages.dart';
import 'package:twonly/src/services/fcm_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';
// ignore: library_prefixes // ignore: library_prefixes
@ -59,6 +60,11 @@ class ApiProvider {
} }
} }
// Function is called after the user is authenticated at the server
Future onAuthenticated() async {
initFCMAfterAuthenticated();
}
Future onConnected() async { Future onConnected() async {
await authenticate(); await authenticate();
globalCallbackConnectionState(true); globalCallbackConnectionState(true);
@ -212,7 +218,6 @@ class ApiProvider {
} }
Future authenticate() async { Future authenticate() async {
print("try authenticate $isAuthenticated");
if (isAuthenticated) return; if (isAuthenticated) return;
if (await SignalHelper.getSignalIdentity() == null) { if (await SignalHelper.getSignalIdentity() == null) {
return; return;
@ -221,7 +226,6 @@ class ApiProvider {
var handshake = Handshake()..getchallenge = Handshake_GetChallenge(); var handshake = Handshake()..getchallenge = Handshake_GetChallenge();
var req = createClientToServerFromHandshake(handshake); var req = createClientToServerFromHandshake(handshake);
print("try authenticate send to server");
final result = await _sendRequestV0(req, authenticated: false); final result = await _sendRequestV0(req, authenticated: false);
if (result.isError) { if (result.isError) {
log.shout("Error auth", result); log.shout("Error auth", result);
@ -253,6 +257,7 @@ class ApiProvider {
} }
log.info("Authenticated!"); log.info("Authenticated!");
onAuthenticated();
isAuthenticated = true; isAuthenticated = true;
} }
@ -329,6 +334,13 @@ class ApiProvider {
return await _sendRequestV0(req); return await _sendRequestV0(req);
} }
Future<Result> updateFCMToken(String googleFcm) async {
var get = ApplicationData_UpdateGoogleFcmToken()..googleFcm = googleFcm;
var appData = ApplicationData()..updategooglefcmtoken = get;
var req = createClientToServerFromApplicationData(appData);
return await _sendRequestV0(req);
}
Future<Result> sendTextMessage(Int64 target, Uint8List msg) async { Future<Result> sendTextMessage(Int64 target, Uint8List msg) async {
var testMessage = ApplicationData_TextMessage() var testMessage = ApplicationData_TextMessage()
..userId = target ..userId = target

View file

@ -0,0 +1,100 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:logging/logging.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/app.dart';
import 'package:twonly/src/providers/api_provider.dart';
import 'package:twonly/src/providers/db_provider.dart';
import 'package:twonly/src/utils/misc.dart';
import '../../firebase_options.dart';
// see more here: https://firebase.google.com/docs/cloud-messaging/flutter/receive?hl=de
Future initFCMAfterAuthenticated() async {
if (globalIsAppInBackground) return;
final storage = getSecureStorage();
String? storedToken = await storage.read(key: "google_fcm");
final fcmToken = await FirebaseMessaging.instance.getToken();
if (fcmToken == null) {
Logger("init_fcm_service").shout("Error getting fcmToken");
return;
}
if (storedToken == null || fcmToken != storedToken) {
await apiProvider.updateFCMToken(fcmToken);
await storage.write(key: "google_fcm", value: fcmToken);
}
FirebaseMessaging.instance.onTokenRefresh.listen((fcmToken) async {
await apiProvider.updateFCMToken(fcmToken);
await storage.write(key: "google_fcm", value: fcmToken);
}).onError((err) {
// Logger("init_fcm_service").shout("Error getting fcmToken");
});
}
Future initFCMService() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// You may set the permission requests to "provisional" which allows the user to choose what type
// of notifications they would like to receive once the user receives a notification.
// final notificationSettings =
await FirebaseMessaging.instance.requestPermission(provisional: true);
// For apple platforms, ensure the APNS token is available before making any FCM plugin API calls
// final apnsToken = await FirebaseMessaging.instance.getAPNSToken();
// if (apnsToken != null) {
// APNS token is available, make FCM plugin API requests...
// }
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});
}
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
// Wenn Tasks länger als 30 Sekunden ausgeführt werden, wird der Prozess möglicherweise automatisch vom Gerät beendet.
// -> offer backend via http?
print("Handling a background message: ${message.messageId}");
bool gotMessage = false;
globalCallBackOnMessageChange = (a, b) async {
gotMessage = true;
print("Got message can exit");
};
dbProvider = DbProvider();
await dbProvider.ready;
apiProvider = ApiProvider();
await apiProvider.connect();
final stopwatch = Stopwatch()..start();
while (!gotMessage) {
print("gotMessage: $gotMessage");
if (stopwatch.elapsed >= Duration(seconds: 20)) {
Logger("firebase-background").shout('Timeout reached. Exiting the loop.');
break; // Exit the loop if the timeout is reached.
}
await Future.delayed(Duration(milliseconds: 10));
}
await apiProvider.close(() {});
}

View file

@ -34,7 +34,7 @@ Future<void> writeLogToFile(LogRecord record) async {
// Prepare the log message // Prepare the log message
final logMessage = final logMessage =
'${record.level.name}: ${record.loggerName}: ${record.message}\n'; '${DateTime.now()}: ${record.level.name}: ${record.loggerName}: ${record.message}\n';
// Append the log message to the file // Append the log message to the file
await logFile.writeAsString(logMessage, mode: FileMode.append); await logFile.writeAsString(logMessage, mode: FileMode.append);

View file

@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/services.dart';
class DiagnosticsView extends StatelessWidget {
const DiagnosticsView({super.key});
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: _loadLogFile(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
final logText = snapshot.data ?? '';
return Scaffold(
appBar: AppBar(title: const Text('Diagnostics')),
body: Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Text(logText),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
Clipboard.setData(ClipboardData(text: logText));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Log copied to clipboard!')),
);
},
child: const Text('Copy All Text'),
),
TextButton(
onPressed: () async {
final directory =
await getApplicationDocumentsDirectory();
final logFile = File('${directory.path}/app.log');
if (await logFile.exists()) {
await logFile.delete();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Log file deleted!')),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Log file does not exist.')),
);
}
},
child: const Text('Delete Log File'),
),
],
),
),
],
),
);
}
},
);
}
Future<String> _loadLogFile() async {
final directory = await getApplicationDocumentsDirectory();
final logFile = File('${directory.path}/app.log');
if (await logFile.exists()) {
return await logFile.readAsString();
} else {
return 'Log file does not exist.';
}
}
}

View file

@ -2,6 +2,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:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/views/settings/diagnostics_view.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class HelpView extends StatelessWidget { class HelpView extends StatelessWidget {
@ -43,9 +44,15 @@ class HelpView extends StatelessWidget {
showLicensePage(context: context); showLicensePage(context: context);
}, },
), ),
ListTile(
// Diagnoseprotokoll title: Text(context.lang.settingsHelpDiagnostics),
onTap: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) {
return DiagnosticsView();
}));
},
),
ListTile( ListTile(
title: Text(context.lang.settingsHelpLegal), title: Text(context.lang.settingsHelpLegal),
onTap: () { onTap: () {

View file

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "80.0.0" version: "80.0.0"
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: e051259913915ea5bc8fe18664596bea08592fd123930605d562969cd7315fcd
url: "https://pub.dev"
source: hosted
version: "1.3.51"
adaptive_number: adaptive_number:
dependency: transitive dependency: transitive
description: description:
@ -305,6 +313,54 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.1" version: "7.0.1"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "93dc4dd12f9b02c5767f235307f609e61ed9211047132d07f9e02c668f0bfc33"
url: "https://pub.dev"
source: hosted
version: "3.11.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf
url: "https://pub.dev"
source: hosted
version: "5.4.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: "0e13c80f0de8acaa5d0519cbe23c8b4cc138a2d5d508b5755c861bdfc9762678"
url: "https://pub.dev"
source: hosted
version: "2.20.0"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "3dee3b0cbfe719e64773cb7d1cad57c58b2235a8c136f5715fe733a54058c783"
url: "https://pub.dev"
source: hosted
version: "15.2.2"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: e9ea726b9bb864fc6223bb66422bd9877b9973ae51967754a769b0d01e201c1e
url: "https://pub.dev"
source: hosted
version: "4.6.2"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "5f7b40e8bf861a37f8b8196e347d8a919750421a45f0b45d1bb74e98fa72726e"
url: "https://pub.dev"
source: hosted
version: "3.10.2"
fixnum: fixnum:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -17,6 +17,8 @@ dependencies:
connectivity_plus: ^6.1.2 connectivity_plus: ^6.1.2
cv: ^1.1.3 cv: ^1.1.3
exif: ^3.3.0 exif: ^3.3.0
firebase_core: ^3.11.0
firebase_messaging: ^15.2.2
fixnum: ^1.1.1 fixnum: ^1.1.1
flutter: flutter:
sdk: flutter sdk: flutter