mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 09:28:41 +00:00
fix #79
This commit is contained in:
parent
ebc4570b9b
commit
27fa177a2e
18 changed files with 266 additions and 106 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,3 +1,6 @@
|
|||
[submodule "dependencies/flutter_secure_storage"]
|
||||
path = dependencies/flutter_secure_storage
|
||||
url = https://github.com/juliansteenbakker/flutter_secure_storage
|
||||
[submodule "dependencies/flutter_zxing"]
|
||||
path = dependencies/flutter_zxing
|
||||
url = https://github.com/khoren93/flutter_zxing.git
|
||||
|
|
|
|||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"files.exclude": {
|
||||
"files.watcherExclude": {
|
||||
"dependencies": false
|
||||
}
|
||||
}
|
||||
|
|
@ -13,5 +13,9 @@ pub.dev or because they require some special installation.
|
|||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
|
||||
cd dependencies/flutter_zxing
|
||||
git submodule update --init --recursive
|
||||
./scripts/update_ios_macos_src.s
|
||||
```
|
||||
|
||||
|
|
|
|||
1
assets/animations/failed.json
Normal file
1
assets/animations/failed.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/animations/success.json
Normal file
1
assets/animations/success.json
Normal file
File diff suppressed because one or more lines are too long
1
dependencies/flutter_zxing
vendored
Submodule
1
dependencies/flutter_zxing
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ba65f2fb4a09f4e68f6de64aa1de41ba3dc4977e
|
||||
|
|
@ -71,6 +71,8 @@ PODS:
|
|||
- flutter_secure_storage_darwin (10.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- flutter_zxing (0.0.1):
|
||||
- Flutter
|
||||
- gal (1.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
|
|
@ -234,6 +236,7 @@ DEPENDENCIES:
|
|||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
|
||||
- flutter_zxing (from `.symlinks/plugins/flutter_zxing/ios`)
|
||||
- gal (from `.symlinks/plugins/gal/darwin`)
|
||||
- GoogleUtilities
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
|
|
@ -290,6 +293,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
flutter_secure_storage_darwin:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
|
||||
flutter_zxing:
|
||||
:path: ".symlinks/plugins/flutter_zxing/ios"
|
||||
gal:
|
||||
:path: ".symlinks/plugins/gal/darwin"
|
||||
image_picker_ios:
|
||||
|
|
@ -337,6 +342,7 @@ SPEC CHECKSUMS:
|
|||
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
|
||||
flutter_zxing: e8bcc43bd3056c70c271b732ed94e7a16fd62f93
|
||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||
GoogleAppMeasurement: 36684bfb3ee034e2b42b4321eb19da3a1b81e65d
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@
|
|||
"settingsAccountDeleteModalTitle": "Bist du sicher?",
|
||||
"settingsAccountDeleteModalBody": "Dein Konto wird gelöscht. Es gibt keine Möglichkeit, es wiederherzustellen.",
|
||||
"contactVerifyNumberTitle": "Sicherheitsnummer verifizieren",
|
||||
"contactVerifyNumberTapToScan": "Zum Scannen tippen",
|
||||
"contactVerifyNumberMarkAsVerified": "Als verifiziert markieren",
|
||||
"contactVerifyNumberClearVerification": "Verifizierung aufheben",
|
||||
"contactVerifyNumberLongDesc": "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.",
|
||||
|
|
|
|||
|
|
@ -231,6 +231,8 @@
|
|||
"@settingsAccountDeleteModalBody": {},
|
||||
"contactVerifyNumberTitle": "Verify safety number",
|
||||
"@contactVerifyNumberTitle": {},
|
||||
"contactVerifyNumberTapToScan": "Tap to scan",
|
||||
"@contactVerifyNumberTapToScan": {},
|
||||
"contactVerifyNumberMarkAsVerified": "Mark as verified",
|
||||
"@contactVerifyNumberMarkAsVerified": {},
|
||||
"contactVerifyNumberClearVerification": "Clear verification",
|
||||
|
|
|
|||
|
|
@ -788,6 +788,12 @@ abstract class AppLocalizations {
|
|||
/// **'Verify safety number'**
|
||||
String get contactVerifyNumberTitle;
|
||||
|
||||
/// No description provided for @contactVerifyNumberTapToScan.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Tap to scan'**
|
||||
String get contactVerifyNumberTapToScan;
|
||||
|
||||
/// No description provided for @contactVerifyNumberMarkAsVerified.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -385,6 +385,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
@override
|
||||
String get contactVerifyNumberTitle => 'Sicherheitsnummer verifizieren';
|
||||
|
||||
@override
|
||||
String get contactVerifyNumberTapToScan => 'Zum Scannen tippen';
|
||||
|
||||
@override
|
||||
String get contactVerifyNumberMarkAsVerified => 'Als verifiziert markieren';
|
||||
|
||||
|
|
|
|||
|
|
@ -380,6 +380,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get contactVerifyNumberTitle => 'Verify safety number';
|
||||
|
||||
@override
|
||||
String get contactVerifyNumberTapToScan => 'Tap to scan';
|
||||
|
||||
@override
|
||||
String get contactVerifyNumberMarkAsVerified => 'Mark as verified';
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class FormattedStringWidget extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return SelectableText(
|
||||
formatString(longString),
|
||||
style: TextStyle(fontSize: 18, color: Colors.black),
|
||||
style: TextStyle(fontSize: 16, color: Colors.black),
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:drift/drift.dart' hide Column;
|
||||
import 'package:flutter_zxing/flutter_zxing.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/services/signal/session.signal.dart';
|
||||
import 'package:twonly/src/views/components/format_long_string.dart';
|
||||
|
|
@ -10,7 +12,9 @@ import 'package:flutter/material.dart';
|
|||
import 'package:twonly/src/database/daos/contacts_dao.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/views/contact/contact_verify_qr_scan.view.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:image/image.dart' as imglib;
|
||||
|
||||
class ContactVerifyView extends StatefulWidget {
|
||||
const ContactVerifyView(this.contact, {super.key});
|
||||
|
|
@ -20,31 +24,127 @@ class ContactVerifyView extends StatefulWidget {
|
|||
State<ContactVerifyView> createState() => _ContactVerifyViewState();
|
||||
}
|
||||
|
||||
enum ScanResult { None, Success, Failed }
|
||||
|
||||
class _ContactVerifyViewState extends State<ContactVerifyView> {
|
||||
Fingerprint? fingerprint;
|
||||
Fingerprint? _fingerprint;
|
||||
late Contact _contact;
|
||||
late StreamSubscription<Contact?> _contactSub;
|
||||
ScanResult _scanResult = ScanResult.None;
|
||||
Uint8List? _qrCodeImageBytes;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_contact = widget.contact;
|
||||
loadAsync();
|
||||
}
|
||||
|
||||
Future loadAsync() async {
|
||||
fingerprint = await generateSessionFingerPrint(widget.contact.userId);
|
||||
setState(() {});
|
||||
@override
|
||||
void dispose() {
|
||||
_contactSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Future loadAsync() async {
|
||||
_fingerprint = await generateSessionFingerPrint(widget.contact.userId);
|
||||
|
||||
if (_fingerprint != null) {
|
||||
final Encode result = zx.encodeBarcode(
|
||||
contents: base64Encode(
|
||||
_fingerprint!.scannableFingerprint.fingerprints,
|
||||
),
|
||||
params: EncodeParams(
|
||||
format: Format.qrCode,
|
||||
width: 150,
|
||||
height: 150,
|
||||
margin: 0,
|
||||
eccLevel: EccLevel.low,
|
||||
),
|
||||
);
|
||||
if (result.isValid && result.data != null) {
|
||||
final img = imglib.Image.fromBytes(
|
||||
width: 150,
|
||||
height: 150,
|
||||
bytes: result.data!.buffer,
|
||||
numChannels: 1,
|
||||
);
|
||||
_qrCodeImageBytes = imglib.encodePng(img);
|
||||
}
|
||||
}
|
||||
|
||||
Stream<Contact?> contact = twonlyDB.contactsDao
|
||||
.getContactByUserId(widget.contact.userId)
|
||||
.watchSingleOrNull();
|
||||
_contactSub = contact.listen((contact) {
|
||||
if (contact == null) return;
|
||||
setState(() {
|
||||
_contact = contact;
|
||||
});
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future openQrScanner() async {
|
||||
if (_fingerprint == null) return;
|
||||
bool? isValid = await Navigator.push(context, MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return ContactVerifyQrScanView(
|
||||
widget.contact,
|
||||
fingerprint: _fingerprint!,
|
||||
);
|
||||
},
|
||||
));
|
||||
if (isValid == null) {
|
||||
return; // user just returned...
|
||||
}
|
||||
if (isValid) {
|
||||
_scanResult = ScanResult.Success;
|
||||
updateUserVerifyState(true);
|
||||
} else {
|
||||
_scanResult = ScanResult.Failed;
|
||||
updateUserVerifyState(false);
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future updateUserVerifyState(bool verified) async {
|
||||
final update = ContactsCompanion(verified: Value(verified));
|
||||
await twonlyDB.contactsDao.updateContact(_contact.userId, update);
|
||||
}
|
||||
|
||||
Widget get qrWidget => (_qrCodeImageBytes == null)
|
||||
? SizedBox(
|
||||
width: 150,
|
||||
height: 150,
|
||||
)
|
||||
: Image.memory(_qrCodeImageBytes!);
|
||||
Widget get resultAnimation => SizedBox(
|
||||
width: 150,
|
||||
child: Lottie.asset(
|
||||
(_scanResult == ScanResult.Success)
|
||||
? 'assets/animations/success.json'
|
||||
: 'assets/animations/failed.json',
|
||||
repeat: false,
|
||||
onLoaded: (p0) {
|
||||
Future.delayed(Duration(seconds: 3), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_scanResult = ScanResult.None;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(context.lang.contactVerifyNumberTitle),
|
||||
),
|
||||
body: (fingerprint == null)
|
||||
body: (_fingerprint == null)
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: ListView(
|
||||
children: [
|
||||
|
|
@ -57,55 +157,57 @@ class _ContactVerifyViewState extends State<ContactVerifyView> {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Colors.white,
|
||||
child: GestureDetector(
|
||||
onTap: openQrScanner,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Colors.white,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
(_scanResult == ScanResult.None)
|
||||
? qrWidget
|
||||
: resultAnimation,
|
||||
SizedBox(height: 10),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: Text(
|
||||
(_scanResult == ScanResult.None)
|
||||
? context
|
||||
.lang.contactVerifyNumberTapToScan
|
||||
: "",
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 15,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: QrImageView(
|
||||
data: base64Encode(fingerprint!
|
||||
.scannableFingerprint.fingerprints),
|
||||
version: QrVersions.auto,
|
||||
size: 150.0,
|
||||
SizedBox(height: 20),
|
||||
FormattedStringWidget(
|
||||
_fingerprint!.displayableFingerprint
|
||||
.getDisplayText(),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: Text(
|
||||
"QR Code scanning is coming soon. Please compare the numbers manual.",
|
||||
style:
|
||||
TextStyle(color: Colors.black, fontSize: 10),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
FormattedStringWidget(
|
||||
fingerprint!.displayableFingerprint
|
||||
.getDisplayText(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
StreamBuilder(
|
||||
stream: contact,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || snapshot.data == null) {
|
||||
return Container();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Text(
|
||||
context.lang.contactVerifyNumberLongDesc(
|
||||
getContactDisplayName(snapshot.data!)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
},
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
||||
child: Text(
|
||||
context.lang.contactVerifyNumberLongDesc(
|
||||
getContactDisplayName(_contact)),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
|
|
@ -133,36 +235,19 @@ class _ContactVerifyViewState extends State<ContactVerifyView> {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
StreamBuilder(
|
||||
stream: contact,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || snapshot.data == null) {
|
||||
return Container();
|
||||
}
|
||||
final contact = snapshot.data!;
|
||||
if (contact.verified) {
|
||||
return OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
final update =
|
||||
ContactsCompanion(verified: Value(false));
|
||||
twonlyDB.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
},
|
||||
(_contact.verified)
|
||||
? OutlinedButton.icon(
|
||||
onPressed: () => updateUserVerifyState(false),
|
||||
label: Text(
|
||||
context.lang.contactVerifyNumberClearVerification),
|
||||
);
|
||||
}
|
||||
return FilledButton.icon(
|
||||
icon: FaIcon(FontAwesomeIcons.shieldHeart),
|
||||
onPressed: () {
|
||||
final update = ContactsCompanion(verified: Value(true));
|
||||
twonlyDB.contactsDao
|
||||
.updateContact(contact.userId, update);
|
||||
},
|
||||
label: Text(context.lang.contactVerifyNumberMarkAsVerified),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: FilledButton.icon(
|
||||
icon: FaIcon(FontAwesomeIcons.shieldHeart),
|
||||
onPressed: () => updateUserVerifyState(true),
|
||||
label: Text(
|
||||
context.lang.contactVerifyNumberMarkAsVerified,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
43
lib/src/views/contact/contact_verify_qr_scan.view.dart
Normal file
43
lib/src/views/contact/contact_verify_qr_scan.view.dart
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_zxing/flutter_zxing.dart';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
|
||||
class ContactVerifyQrScanView extends StatefulWidget {
|
||||
const ContactVerifyQrScanView(this.contact,
|
||||
{super.key, required this.fingerprint});
|
||||
final Fingerprint fingerprint;
|
||||
final Contact contact;
|
||||
|
||||
@override
|
||||
State<ContactVerifyQrScanView> createState() =>
|
||||
_ContactVerifyQrScanViewState();
|
||||
}
|
||||
|
||||
class _ContactVerifyQrScanViewState extends State<ContactVerifyQrScanView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ReaderWidget(
|
||||
onScan: (result) async {
|
||||
bool isValid = false;
|
||||
try {
|
||||
if (result.text != null) {
|
||||
Uint8List otherFingerPrint = base64Decode(result.text!);
|
||||
isValid = widget.fingerprint.scannableFingerprint.compareTo(
|
||||
otherFingerPrint,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error("$e");
|
||||
}
|
||||
return Navigator.pop(context, isValid);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -63,40 +63,51 @@ class CreditsView extends StatelessWidget {
|
|||
)),
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Free selfie fast Animation",
|
||||
title: "selfie fast Animation",
|
||||
subtitle: "Brandon Ambuila",
|
||||
url:
|
||||
"https://lottiefiles.com/free-animation/selfie-fast-JZx4Ftrg1E",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Free Security status - Safe Animation",
|
||||
title: "Security status - Safe Animation",
|
||||
subtitle: "Yogesh Pal",
|
||||
url:
|
||||
"https://lottiefiles.com/free-animation/security-status-safe-CePJPAwLVx",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Free send mail Animation",
|
||||
title: "send mail Animation",
|
||||
subtitle: "jignesh gajjar",
|
||||
url: "https://lottiefiles.com/free-animation/send-mail-3pvzm2kmNq",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Free Present for you Animation",
|
||||
title: "Present for you Animation",
|
||||
subtitle: "Tatsiana Melnikova",
|
||||
url:
|
||||
"https://lottiefiles.com/free-animation/present-for-you-QalWyuNptY",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Free Take a photo Animation",
|
||||
title: "Take a photo Animation",
|
||||
subtitle: "Nguyễn Như Lân",
|
||||
url:
|
||||
"https://lottiefiles.com/free-animation/take-a-photo-CzOUerxwPP?color-palette=true",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Kostenlose Valentine's Day-Animation",
|
||||
title: "Valentine's Day-Animation",
|
||||
subtitle: "Strezha",
|
||||
url:
|
||||
"https://lottiefiles.com/de/free-animation/valentines-day-1UiMkPHnPK?color-palette=true",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "success-Animation",
|
||||
subtitle: "Aman Awasthy",
|
||||
url:
|
||||
"https://lottiefiles.com/de/free-animation/success-tick-cuwjLHAR7g",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Failed-Animation",
|
||||
subtitle: "Ahmed Shami أحمد شامي",
|
||||
url: "https://lottiefiles.com/de/free-animation/failed-e5cQFDEtLv",
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
title: Center(
|
||||
|
|
@ -105,18 +116,6 @@ class CreditsView extends StatelessWidget {
|
|||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
)),
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Germany",
|
||||
subtitle: "by GDJ",
|
||||
url:
|
||||
"https://pixabay.com/vectors/republic-germany-deutschland-map-1220652/",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Frankfurt am Main",
|
||||
subtitle: "by GDJ",
|
||||
url:
|
||||
"https://pixabay.com/vectors/frankfurt-germany-skyline-cityscape-3166262/",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Avo Cardio",
|
||||
subtitle: "by RalfDesign",
|
||||
|
|
@ -129,12 +128,6 @@ class CreditsView extends StatelessWidget {
|
|||
url:
|
||||
"https://pixabay.com/illustrations/sloth-swimming-summer-pool-cartoon-4575121/",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Sloth",
|
||||
subtitle: "by RalfDesign",
|
||||
url:
|
||||
"https://pixabay.com/illustrations/sloth-swimming-summer-pool-cartoon-4575121/",
|
||||
),
|
||||
UrlListTitle(
|
||||
title: "Duck",
|
||||
subtitle: "by lachkegeetanjali",
|
||||
|
|
|
|||
|
|
@ -716,6 +716,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_zxing:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "dependencies/flutter_zxing"
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.1.0"
|
||||
font_awesome_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ dependencies:
|
|||
# flutter_secure_storage: ^10.0.0-beta.4
|
||||
flutter_secure_storage:
|
||||
path: ./dependencies/flutter_secure_storage/flutter_secure_storage
|
||||
flutter_zxing:
|
||||
path: ./dependencies/flutter_zxing
|
||||
font_awesome_flutter: ^10.8.0
|
||||
gal: ^2.3.1
|
||||
hand_signature: ^3.0.3
|
||||
|
|
@ -46,7 +48,6 @@ dependencies:
|
|||
protobuf: ^4.0.0
|
||||
cryptography_plus: ^2.7.0
|
||||
provider: ^6.1.2
|
||||
qr_flutter: ^4.1.0
|
||||
restart_app: ^1.3.2
|
||||
screenshot: ^3.0.0
|
||||
url_launcher: ^6.3.1
|
||||
|
|
|
|||
Loading…
Reference in a new issue