remove face filters

This commit is contained in:
otsmr 2026-03-10 21:08:00 +01:00
parent 6df40e93df
commit 074211a815
21 changed files with 249 additions and 921 deletions

View file

@ -23,12 +23,12 @@ android {
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "17"
}
defaultConfig {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

View file

@ -49,55 +49,55 @@ PODS:
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Firebase (12.8.0):
- Firebase/Core (= 12.8.0)
- Firebase/Core (12.8.0):
- Firebase (12.9.0):
- Firebase/Core (= 12.9.0)
- Firebase/Core (12.9.0):
- Firebase/CoreOnly
- FirebaseAnalytics (~> 12.8.0)
- Firebase/CoreOnly (12.8.0):
- FirebaseCore (~> 12.8.0)
- Firebase/Messaging (12.8.0):
- FirebaseAnalytics (~> 12.9.0)
- Firebase/CoreOnly (12.9.0):
- FirebaseCore (~> 12.9.0)
- Firebase/Messaging (12.9.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 12.8.0)
- firebase_core (4.4.0):
- Firebase/CoreOnly (= 12.8.0)
- FirebaseMessaging (~> 12.9.0)
- firebase_core (4.5.0):
- Firebase/CoreOnly (= 12.9.0)
- Flutter
- firebase_messaging (16.1.1):
- Firebase/Messaging (= 12.8.0)
- firebase_messaging (16.1.2):
- Firebase/Messaging (= 12.9.0)
- firebase_core
- Flutter
- FirebaseAnalytics (12.8.0):
- FirebaseAnalytics/Default (= 12.8.0)
- FirebaseCore (~> 12.8.0)
- FirebaseInstallations (~> 12.8.0)
- FirebaseAnalytics (12.9.0):
- FirebaseAnalytics/Default (= 12.9.0)
- FirebaseCore (~> 12.9.0)
- FirebaseInstallations (~> 12.9.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- FirebaseAnalytics/Default (12.8.0):
- FirebaseCore (~> 12.8.0)
- FirebaseInstallations (~> 12.8.0)
- GoogleAppMeasurement/Default (= 12.8.0)
- FirebaseAnalytics/Default (12.9.0):
- FirebaseCore (~> 12.9.0)
- FirebaseInstallations (~> 12.9.0)
- GoogleAppMeasurement/Default (= 12.9.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- FirebaseCore (12.8.0):
- FirebaseCoreInternal (~> 12.8.0)
- FirebaseCore (12.9.0):
- FirebaseCoreInternal (~> 12.9.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1)
- FirebaseCoreInternal (12.8.0):
- FirebaseCoreInternal (12.9.0):
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- FirebaseInstallations (12.8.0):
- FirebaseCore (~> 12.8.0)
- FirebaseInstallations (12.9.0):
- FirebaseCore (~> 12.9.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- PromisesObjC (~> 2.4)
- FirebaseMessaging (12.8.0):
- FirebaseCore (~> 12.8.0)
- FirebaseInstallations (~> 12.8.0)
- FirebaseMessaging (12.9.0):
- FirebaseCore (~> 12.9.0)
- FirebaseInstallations (~> 12.9.0)
- GoogleDataTransport (~> 10.1)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/Environment (~> 8.1)
@ -140,23 +140,23 @@ PODS:
- GoogleUtilities/Logger (~> 8.1)
- GoogleUtilities/Network (~> 8.1)
- nanopb (~> 3.30910.0)
- GoogleAppMeasurement/Core (12.8.0):
- GoogleAppMeasurement/Core (12.9.0):
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- GoogleAppMeasurement/Default (12.8.0):
- GoogleAppMeasurement/Default (12.9.0):
- GoogleAdsOnDeviceConversion (~> 3.2.0)
- GoogleAppMeasurement/Core (= 12.8.0)
- GoogleAppMeasurement/IdentitySupport (= 12.8.0)
- GoogleAppMeasurement/Core (= 12.9.0)
- GoogleAppMeasurement/IdentitySupport (= 12.9.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1)
- "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- GoogleAppMeasurement/IdentitySupport (12.8.0):
- GoogleAppMeasurement/Core (= 12.8.0)
- GoogleAppMeasurement/IdentitySupport (12.9.0):
- GoogleAppMeasurement/Core (= 12.9.0)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/MethodSwizzler (~> 8.1)
- GoogleUtilities/Network (~> 8.1)
@ -276,7 +276,7 @@ PODS:
- pro_video_editor (0.0.1):
- Flutter
- PromisesObjC (2.4.0)
- restart_app (0.0.1):
- restart_app (1.7.2):
- Flutter
- SDWebImage (5.21.6):
- SDWebImage/Core (= 5.21.6)
@ -285,7 +285,7 @@ PODS:
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- Sentry/HybridSDK (8.56.2)
- sentry_flutter (9.13.0):
- sentry_flutter (9.14.0):
- Flutter
- FlutterMacOS
- Sentry/HybridSDK (= 8.56.2)
@ -331,6 +331,8 @@ PODS:
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS
- workmanager_apple (0.0.1):
- Flutter
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
@ -377,6 +379,7 @@ DEPENDENCIES:
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_compress (from `.symlinks/plugins/video_compress/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
- workmanager_apple (from `.symlinks/plugins/workmanager_apple/ios`)
SPEC REPOS:
trunk:
@ -488,6 +491,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/video_compress/ios"
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
workmanager_apple:
:path: ".symlinks/plugins/workmanager_apple/ios"
SPEC CHECKSUMS:
app_links: a754cbec3c255bd4bbb4d236ecc06f28cd9a7ce8
@ -501,14 +506,14 @@ SPEC CHECKSUMS:
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
Firebase: 9a58fdbc9d8655ed7b79a19cf9690bb007d3d46d
firebase_core: ee30637e6744af8e0c12a6a1e8a9718506ec2398
firebase_messaging: 343de01a8d3e18b60df0c6d37f7174c44ae38e02
FirebaseAnalytics: f20bbad8cb7f65d8a5eaefeb424ae8800a31bdfc
FirebaseCore: 0dbad74bda10b8fb9ca34ad8f375fb9dd3ebef7c
FirebaseCoreInternal: fe5fa466aeb314787093a7dce9f0beeaad5a2a21
FirebaseInstallations: 6a14ab3d694ebd9f839c48d330da5547e9ca9dc0
FirebaseMessaging: 7f42cfd10ec64181db4e01b305a613791c8e782c
Firebase: 065f2bb395062046623036d8e6dc857bc2521d56
firebase_core: afac1aac13c931e0401c7e74ed1276112030efab
firebase_messaging: 7cb2727feb789751fc6936bcc8e08408970e2820
FirebaseAnalytics: cd7d01d352f3c237c9a0e31552c257cd0b0c0352
FirebaseCore: 428912f751178b06bef0a1793effeb4a5e09a9b8
FirebaseCoreInternal: b321eafae5362113bc182956fafc9922cfc77b72
FirebaseInstallations: 7b64ffd006032b2b019a59b803858df5112d9eaa
FirebaseMessaging: 7d6cdbff969127c4151c824fe432f0e301210f15
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f
@ -521,7 +526,7 @@ SPEC CHECKSUMS:
google_mlkit_commons: a5e4ffae5bc59ea4c7b9025dc72cb6cb79dc1166
google_mlkit_face_detection: ee4b72cfae062b4c972204be955d83055a4bfd36
GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f
GoogleAppMeasurement: 72c9a682fec6290327ea5e3c4b829b247fcb2c17
GoogleAppMeasurement: fce7c1c90640d2f9f5c56771f71deacb2ba3f98c
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleMLKit: b1eee21a41c57704fe72483b15c85cb2c0cd7444
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
@ -543,11 +548,11 @@ SPEC CHECKSUMS:
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
pro_video_editor: 44ef9a6d48dbd757ed428cf35396dd05f35c7830
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
restart_app: 9cda5378aacc5000e3f66ee76a9201534e7d3ecf
restart_app: 98825697952793b5a8e489df3d52ed5ac4fd536d
SDWebImage: 1bb6a1b84b6fe87b972a102bdc77dd589df33477
SDWebImageWebPCoder: 0e06e365080397465cc73a7a9b472d8a3bd0f377
Sentry: b53951377b78e21a734f5dc8318e333dbfc682d7
sentry_flutter: dbed9a62ae39716b685a80140705c330d200d941
sentry_flutter: 841fa2fe08dc72eb95e2320b76e3f751f3400cf5
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
@ -558,6 +563,7 @@ SPEC CHECKSUMS:
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
video_compress: f2133a07762889d67f0711ac831faa26f956980e
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
workmanager_apple: 904529ae31e97fc5be632cf628507652294a0778
PODFILE CHECKSUM: ae041999f13ba7b2285ff9ad9bc688ed647bbcb7

View file

@ -536,12 +536,14 @@ class Handshake_Authenticate extends $pb.GeneratedMessage {
$core.List<$core.int>? authToken,
$core.String? appVersion,
$fixnum.Int64? deviceId,
$core.bool? inBackground,
}) {
final result = create();
if (userId != null) result.userId = userId;
if (authToken != null) result.authToken = authToken;
if (appVersion != null) result.appVersion = appVersion;
if (deviceId != null) result.deviceId = deviceId;
if (inBackground != null) result.inBackground = inBackground;
return result;
}
@ -564,6 +566,7 @@ class Handshake_Authenticate extends $pb.GeneratedMessage {
2, _omitFieldNames ? '' : 'authToken', $pb.PbFieldType.OY)
..aOS(3, _omitFieldNames ? '' : 'appVersion')
..aInt64(4, _omitFieldNames ? '' : 'deviceId')
..aOB(5, _omitFieldNames ? '' : 'inBackground')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -624,6 +627,15 @@ class Handshake_Authenticate extends $pb.GeneratedMessage {
$core.bool hasDeviceId() => $_has(3);
@$pb.TagNumber(4)
void clearDeviceId() => $_clearField(4);
@$pb.TagNumber(5)
$core.bool get inBackground => $_getBF(4);
@$pb.TagNumber(5)
set inBackground($core.bool value) => $_setBool(4, value);
@$pb.TagNumber(5)
$core.bool hasInBackground() => $_has(4);
@$pb.TagNumber(5)
void clearInBackground() => $_clearField(5);
}
enum Handshake_Handshake {

View file

@ -229,10 +229,20 @@ const Handshake_Authenticate$json = {
'10': 'deviceId',
'17': true
},
{
'1': 'in_background',
'3': 5,
'4': 1,
'5': 8,
'9': 2,
'10': 'inBackground',
'17': true
},
],
'8': [
{'1': '_app_version'},
{'1': '_device_id'},
{'1': '_in_background'},
],
};
@ -254,10 +264,11 @@ final $typed_data.Uint8List handshakeDescriptor = $convert.base64Decode(
'QSFQoGaXNfaW9zGAggASgIUgVpc0lvcxIbCglsYW5nX2NvZGUYCSABKAlSCGxhbmdDb2RlEiIK'
'DXByb29mX29mX3dvcmsYCiABKANSC3Byb29mT2ZXb3JrQg4KDF9pbnZpdGVfY29kZRoSChBHZX'
'RBdXRoQ2hhbGxlbmdlGkMKDEdldEF1dGhUb2tlbhIXCgd1c2VyX2lkGAEgASgDUgZ1c2VySWQS'
'GgoIcmVzcG9uc2UYAiABKAxSCHJlc3BvbnNlGqwBCgxBdXRoZW50aWNhdGUSFwoHdXNlcl9pZB'
'GgoIcmVzcG9uc2UYAiABKAxSCHJlc3BvbnNlGugBCgxBdXRoZW50aWNhdGUSFwoHdXNlcl9pZB'
'gBIAEoA1IGdXNlcklkEh0KCmF1dGhfdG9rZW4YAiABKAxSCWF1dGhUb2tlbhIkCgthcHBfdmVy'
'c2lvbhgDIAEoCUgAUgphcHBWZXJzaW9uiAEBEiAKCWRldmljZV9pZBgEIAEoA0gBUghkZXZpY2'
'VJZIgBAUIOCgxfYXBwX3ZlcnNpb25CDAoKX2RldmljZV9pZEILCglIYW5kc2hha2U=');
'VJZIgBARIoCg1pbl9iYWNrZ3JvdW5kGAUgASgISAJSDGluQmFja2dyb3VuZIgBAUIOCgxfYXBw'
'X3ZlcnNpb25CDAoKX2RldmljZV9pZEIQCg5faW5fYmFja2dyb3VuZEILCglIYW5kc2hha2U=');
@$core.Deprecated('Use applicationDataDescriptor instead')
const ApplicationData$json = {

View file

@ -91,6 +91,8 @@ class ErrorCode extends $pb.ProtobufEnum {
ErrorCode._(1034, _omitEnumNames ? '' : 'IPAPaymentExpired');
static const ErrorCode UserIsNotInFreePlan =
ErrorCode._(1035, _omitEnumNames ? '' : 'UserIsNotInFreePlan');
static const ErrorCode ForegroundSessionConnected =
ErrorCode._(1036, _omitEnumNames ? '' : 'ForegroundSessionConnected');
static const $core.List<ErrorCode> values = <ErrorCode>[
Unknown,
@ -131,6 +133,7 @@ class ErrorCode extends $pb.ProtobufEnum {
RegistrationDisabled,
IPAPaymentExpired,
UserIsNotInFreePlan,
ForegroundSessionConnected,
];
static final $core.Map<$core.int, ErrorCode> _byValue =

View file

@ -56,6 +56,7 @@ const ErrorCode$json = {
{'1': 'RegistrationDisabled', '2': 1033},
{'1': 'IPAPaymentExpired', '2': 1034},
{'1': 'UserIsNotInFreePlan', '2': 1035},
{'1': 'ForegroundSessionConnected', '2': 1036},
],
};
@ -77,4 +78,5 @@ final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode(
'duZWRQcmVLZXkQgwgSEwoOVXNlcklkTm90Rm91bmQQhAgSFwoSVXNlcklkQWxyZWFkeVRha2Vu'
'EIUIEhcKEkFwcFZlcnNpb25PdXRkYXRlZBCGCBIYChNOZXdEZXZpY2VSZWdpc3RlcmVkEIcIEh'
'cKEkludmFsaWRQcm9vZk9mV29yaxCICBIZChRSZWdpc3RyYXRpb25EaXNhYmxlZBCJCBIWChFJ'
'UEFQYXltZW50RXhwaXJlZBCKCBIYChNVc2VySXNOb3RJbkZyZWVQbGFuEIsI');
'UEFQYXltZW50RXhwaXJlZBCKCBIYChNVc2VySXNOb3RJbkZyZWVQbGFuEIsIEh8KGkZvcmVncm'
'91bmRTZXNzaW9uQ29ubmVjdGVkEIwI');

View file

@ -46,10 +46,6 @@ class MainCameraPreview extends StatelessWidget {
Positioned.fill(
child: mainCameraController.customPaint!,
),
if (mainCameraController.facePaint != null)
Positioned.fill(
child: mainCameraController.facePaint!,
),
],
),
),

View file

@ -22,7 +22,6 @@ import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/qr.dart';
import 'package:twonly/src/utils/screenshot.dart';
import 'package:twonly/src/utils/storage.dart';
import 'package:twonly/src/views/camera/camera_preview_components/face_filters.dart';
import 'package:twonly/src/views/camera/camera_preview_components/main_camera_controller.dart';
import 'package:twonly/src/views/camera/camera_preview_components/permissions_view.dart';
import 'package:twonly/src/views/camera/camera_preview_components/send_to.dart';
@ -458,36 +457,6 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
});
}
Future<void> pressSideButtonLeft() async {
if (!mc.isSelectingFaceFilters) {
return pickImageFromGallery();
}
if (mc.currentFilterType.index == 1) {
mc.setFilter(FaceFilterType.none);
setState(() {
mc.isSelectingFaceFilters = false;
});
return;
}
mc.setFilter(mc.currentFilterType.goLeft());
}
Future<void> pressSideButtonRight() async {
if (!mc.isSelectingFaceFilters) {
setState(() {
mc.isSelectingFaceFilters = true;
});
}
if (mc.currentFilterType.index == FaceFilterType.values.length - 1) {
mc.setFilter(FaceFilterType.none);
setState(() {
mc.isSelectingFaceFilters = false;
});
return;
}
mc.setFilter(mc.currentFilterType.goRight());
}
Future<void> startVideoRecording() async {
if (mc.cameraController != null &&
mc.cameraController!.value.isRecordingVideo) {
@ -724,84 +693,27 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
),
),
const SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (!mc.isVideoRecording)
GestureDetector(
onTap: pressSideButtonLeft,
child: Align(
child: Container(
height: 50,
width: 80,
padding: const EdgeInsets.all(2),
child: Center(
child: FaIcon(
mc.isSelectingFaceFilters
? mc.currentFilterType.index == 1
? FontAwesomeIcons.xmark
: FontAwesomeIcons.arrowLeft
: FontAwesomeIcons.photoFilm,
color: Colors.white,
size: 25,
),
),
),
),
),
GestureDetector(
onTap: takePicture,
// onLongPress: startVideoRecording,
key: keyTriggerButton,
child: Align(
child: Container(
height: 100,
width: 100,
clipBehavior: Clip.antiAliasWithSaveLayer,
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 7,
color: mc.isVideoRecording
? Colors.red
: Colors.white,
),
),
child: mc.currentFilterType.preview,
GestureDetector(
onTap: takePicture,
// onLongPress: startVideoRecording,
key: keyTriggerButton,
child: Align(
child: Container(
height: 100,
width: 100,
clipBehavior: Clip.antiAliasWithSaveLayer,
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 7,
color: mc.isVideoRecording
? Colors.red
: Colors.white,
),
),
),
if (!mc.isVideoRecording)
if (isFront)
GestureDetector(
onTap: pressSideButtonRight,
child: Align(
child: Container(
height: 50,
width: 80,
padding: const EdgeInsets.all(2),
child: Center(
child: FaIcon(
mc.isSelectingFaceFilters
? mc.currentFilterType.index ==
FaceFilterType
.values.length -
1
? FontAwesomeIcons.xmark
: FontAwesomeIcons.arrowRight
: FontAwesomeIcons
.faceGrinTongueSquint,
color: Colors.white,
size: 25,
),
),
),
),
)
else
const SizedBox(width: 80),
],
),
),
],
),

View file

@ -1,36 +0,0 @@
import 'package:flutter/material.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart';
enum FaceFilterType {
none,
dogBrown,
beardUpperLipGreen,
beardUpperLip,
}
extension FaceFilterTypeExtension on FaceFilterType {
FaceFilterType goRight() {
final nextIndex = (index + 1) % FaceFilterType.values.length;
return FaceFilterType.values[nextIndex];
}
FaceFilterType goLeft() {
final prevIndex = (index - 1 + FaceFilterType.values.length) %
FaceFilterType.values.length;
return FaceFilterType.values[prevIndex];
}
Widget get preview {
switch (this) {
case FaceFilterType.none:
return Container();
case FaceFilterType.dogBrown:
return DogFilterPainter.getPreview();
case FaceFilterType.beardUpperLip:
return BeardFilterPainter.getPreview(this);
case FaceFilterType.beardUpperLipGreen:
return BeardFilterPainter.getPreview(this);
}
}
}

View file

@ -6,7 +6,6 @@ import 'package:drift/drift.dart' show Value;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/src/database/daos/contacts.dao.dart';
@ -18,26 +17,16 @@ import 'package:twonly/src/utils/misc.dart';
import 'package:twonly/src/utils/qr.dart';
import 'package:twonly/src/utils/screenshot.dart';
import 'package:twonly/src/views/camera/camera_preview_components/camera_preview_controller_view.dart';
import 'package:twonly/src/views/camera/camera_preview_components/face_filters.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/barcode_detector_painter.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/beard_filter_painter.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/dog_filter_painter.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart';
class ScannedVerifiedContact {
ScannedVerifiedContact({
required this.contact,
required this.verificationOk,
});
ScannedVerifiedContact({required this.contact, required this.verificationOk});
Contact contact;
bool verificationOk;
}
class ScannedNewProfile {
ScannedNewProfile({
required this.profile,
this.isLoading = false,
});
ScannedNewProfile({required this.profile, this.isLoading = false});
PublicProfile profile;
bool isLoading;
}
@ -53,7 +42,6 @@ class MainCameraController {
String? scannedUrl;
GlobalKey zoomButtonKey = GlobalKey();
GlobalKey cameraPreviewKey = GlobalKey();
bool isSelectingFaceFilters = false;
bool isSharePreviewIsShown = false;
bool isVideoRecording = false;
@ -71,21 +59,10 @@ class MainCameraController {
}
final BarcodeScanner _barcodeScanner = BarcodeScanner();
final FaceDetector _faceDetector = FaceDetector(
options: FaceDetectorOptions(
enableContours: true,
enableLandmarks: true,
),
);
bool _isBusy = false;
bool _isBusyFaces = false;
CustomPaint? customPaint;
CustomPaint? facePaint;
Offset? focusPointOffset;
FaceFilterType _currentFilterType = FaceFilterType.none;
FaceFilterType get currentFilterType => _currentFilterType;
Future<void> closeCamera() async {
contactsVerified = {};
scannedNewProfiles = {};
@ -159,8 +136,9 @@ class MainCameraController {
}
}
await cameraController
?.lockCaptureOrientation(DeviceOrientation.portraitUp);
await cameraController?.lockCaptureOrientation(
DeviceOrientation.portraitUp,
);
await cameraController?.setFlashMode(
selectedCameraDetails.isFlashOn ? FlashMode.always : FlashMode.off,
);
@ -174,10 +152,7 @@ class MainCameraController {
..cameraLoaded = true
..cameraId = cameraId;
facePaint = null;
customPaint = null;
isSelectingFaceFilters = false;
setFilter(FaceFilterType.none);
zoomButtonKey = GlobalKey();
setState();
}
@ -214,18 +189,6 @@ class MainCameraController {
setState();
}
void setFilter(FaceFilterType type) {
_currentFilterType = type;
if (_currentFilterType == FaceFilterType.none) {
faceFilterPainter = null;
facePaint = null;
_isBusyFaces = false;
}
setState();
}
FaceFilterPainter? faceFilterPainter;
final Map<DeviceOrientation, int> _orientations = {
DeviceOrientation.portraitUp: 0,
DeviceOrientation.landscapeLeft: 90,
@ -240,15 +203,6 @@ class MainCameraController {
final inputImage = _inputImageFromCameraImage(image);
if (inputImage == null) return;
_processBarcode(inputImage);
// check if front camera is selected
if (cameraController?.description.lensDirection ==
CameraLensDirection.front) {
if (_currentFilterType != FaceFilterType.none) {
_processFaces(inputImage);
}
} else {
_processBarcode(inputImage);
}
}
InputImage? _inputImageFromCameraImage(CameraImage image) {
@ -338,16 +292,19 @@ class MainCameraController {
if (profile == null) continue;
final contact =
await twonlyDB.contactsDao.getContactById(profile.userId.toInt());
final contact = await twonlyDB.contactsDao.getContactById(
profile.userId.toInt(),
);
if (contact != null && contact.accepted) {
if (contactsVerified[contact.userId] == null) {
final storedPublicKey =
await getPublicKeyFromContact(contact.userId);
final storedPublicKey = await getPublicKeyFromContact(
contact.userId,
);
if (storedPublicKey != null) {
final verificationOk =
profile.publicIdentityKey.equals(storedPublicKey.toList());
final verificationOk = profile.publicIdentityKey.equals(
storedPublicKey.toList(),
);
contactsVerified[contact.userId] = ScannedVerifiedContact(
contact: contact,
verificationOk: verificationOk,
@ -390,53 +347,4 @@ class MainCameraController {
_isBusy = false;
setState();
}
Future<void> _processFaces(InputImage inputImage) async {
if (_isBusyFaces) return;
_isBusyFaces = true;
final faces = await _faceDetector.processImage(inputImage);
if (inputImage.metadata?.size != null &&
inputImage.metadata?.rotation != null &&
cameraController != null) {
if (faces.isNotEmpty) {
CustomPainter? painter;
switch (_currentFilterType) {
case FaceFilterType.dogBrown:
painter = DogFilterPainter(
faces,
inputImage.metadata!.size,
inputImage.metadata!.rotation,
cameraController!.description.lensDirection,
);
case FaceFilterType.beardUpperLip:
case FaceFilterType.beardUpperLipGreen:
painter = BeardFilterPainter(
_currentFilterType,
faces,
inputImage.metadata!.size,
inputImage.metadata!.rotation,
cameraController!.description.lensDirection,
);
case FaceFilterType.none:
break;
}
if (painter != null) {
facePaint = CustomPaint(painter: painter);
// Also set the correct FaceFilterPainter reference if needed for other logic,
// though currently facePaint is what's used for display.
if (painter is FaceFilterPainter) {
faceFilterPainter = painter;
}
} else {
facePaint = null;
faceFilterPainter = null;
}
} else {
facePaint = null;
}
}
_isBusyFaces = false;
setState();
}
}

View file

@ -1,193 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/views/camera/camera_preview_components/face_filters.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/coordinates_translator.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart';
class BeardFilterPainter extends FaceFilterPainter {
BeardFilterPainter(
FaceFilterType beardType,
super.faces,
super.imageSize,
super.rotation,
super.cameraLensDirection,
) {
_loadAssets(beardType);
}
static FaceFilterType? _lastLoadedBeardType;
static ui.Image? _beardImage;
static bool _loading = false;
static String getAssetPath(FaceFilterType beardType) {
switch (beardType) {
case FaceFilterType.beardUpperLip:
return 'assets/filters/beard_upper_lip.webp';
case FaceFilterType.beardUpperLipGreen:
return 'assets/filters/beard_upper_lip_green.webp';
case FaceFilterType.dogBrown:
case FaceFilterType.none:
return '';
}
}
static Future<void> _loadAssets(FaceFilterType beardType) async {
if ((_loading || _beardImage != null) &&
_lastLoadedBeardType == beardType) {
return;
}
_loading = true;
try {
_beardImage = await _loadImage(getAssetPath(beardType));
} catch (e) {
Log.error('Failed to load filter assets: $e');
} finally {
_loading = false;
}
}
static Future<ui.Image> _loadImage(String assetPath) async {
final data = await rootBundle.load(assetPath);
final list = Uint8List.view(data.buffer);
final completer = Completer<ui.Image>();
ui.decodeImageFromList(list, completer.complete);
return completer.future;
}
@override
void paint(Canvas canvas, Size size) {
if (_beardImage == null) return;
for (final face in faces) {
final noseBase = face.landmarks[FaceLandmarkType.noseBase];
final mouthLeft = face.landmarks[FaceLandmarkType.leftMouth];
final mouthRight = face.landmarks[FaceLandmarkType.rightMouth];
final bottomMouth = face.landmarks[FaceLandmarkType.bottomMouth];
if (noseBase != null &&
mouthLeft != null &&
mouthRight != null &&
bottomMouth != null) {
final noseX = translateX(
noseBase.position.x.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final noseY = translateY(
noseBase.position.y.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final mouthLeftX = translateX(
mouthLeft.position.x.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final mouthLeftY = translateY(
mouthLeft.position.y.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final mouthRightX = translateX(
mouthRight.position.x.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final mouthRightY = translateY(
mouthRight.position.y.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final mouthCenterX = (mouthLeftX + mouthRightX) / 2;
final mouthCenterY = (mouthLeftY + mouthRightY) / 2;
final beardCenterX = (noseX + mouthCenterX) / 2;
final beardCenterY = (noseY + mouthCenterY) / 2;
final dx = mouthRightX - mouthLeftX;
final dy = mouthRightY - mouthLeftY;
final angle = atan2(dy, dx);
final mouthWidth = sqrt(dx * dx + dy * dy);
final beardWidth = mouthWidth * 1.5;
final yaw = face.headEulerAngleY ?? 0;
final scaleX = cos(yaw * pi / 180).abs();
_drawImage(
canvas,
_beardImage!,
Offset(beardCenterX, beardCenterY),
beardWidth,
angle,
scaleX,
);
}
}
}
void _drawImage(
Canvas canvas,
ui.Image image,
Offset position,
double width,
double rotation,
double scaleX,
) {
canvas
..save()
..translate(position.dx, position.dy)
..rotate(rotation)
..scale(scaleX, Platform.isAndroid ? -1 : 1);
final srcRect =
Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble());
final aspectRatio = image.width / image.height;
final dstWidth = width;
final dstHeight = width / aspectRatio;
final dstRect = Rect.fromCenter(
center: Offset.zero,
width: dstWidth,
height: dstHeight,
);
canvas
..drawImageRect(image, srcRect, dstRect, Paint())
..restore();
}
static Widget getPreview(FaceFilterType beardType) {
return Preview(
child: Padding(
padding: const EdgeInsets.all(8),
child: Image.asset(
getAssetPath(beardType),
fit: BoxFit.contain,
),
),
);
}
}

View file

@ -1,243 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/coordinates_translator.dart';
import 'package:twonly/src/views/camera/camera_preview_components/painters/face_filters/face_filter_painter.dart';
class DogFilterPainter extends FaceFilterPainter {
DogFilterPainter(
super.faces,
super.imageSize,
super.rotation,
super.cameraLensDirection,
) {
_loadAssets();
}
static ui.Image? _earImage;
static ui.Image? _noseImage;
static bool _loading = false;
static Future<void> _loadAssets() async {
if (_loading || (_earImage != null && _noseImage != null)) return;
_loading = true;
try {
_earImage = await _loadImage('assets/filters/dog_brown_ear.webp');
_noseImage = await _loadImage('assets/filters/dog_brown_nose.webp');
} catch (e) {
Log.error('Failed to load filter assets: $e');
} finally {
_loading = false;
}
}
static Future<ui.Image> _loadImage(String assetPath) async {
final data = await rootBundle.load(assetPath);
final list = Uint8List.view(data.buffer);
final completer = Completer<ui.Image>();
ui.decodeImageFromList(list, completer.complete);
return completer.future;
}
@override
void paint(Canvas canvas, Size size) {
if (_earImage == null || _noseImage == null) return;
for (final face in faces) {
final faceContour = face.contours[FaceContourType.face];
final noseBase = face.landmarks[FaceLandmarkType.noseBase];
if (faceContour != null && noseBase != null) {
final points = faceContour.points;
if (points.isEmpty) continue;
final upperPoints =
points.where((p) => p.y < noseBase.position.y).toList();
if (upperPoints.isEmpty) continue;
Point<int>? leftMost;
Point<int>? rightMost;
Point<int>? topMost;
for (final point in upperPoints) {
if (leftMost == null || point.x < leftMost.x) {
leftMost = point;
}
if (rightMost == null || point.x > rightMost.x) {
rightMost = point;
}
if (topMost == null || point.y < topMost.y) {
topMost = point;
}
}
if (leftMost == null || rightMost == null || topMost == null) continue;
final leftEarX = translateX(
leftMost.x.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final leftEarY = translateY(
topMost.y.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final rightEarX = translateX(
rightMost.x.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final rightEarY = translateY(
topMost.y.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final noseX = translateX(
noseBase.position.x.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final noseY = translateY(
noseBase.position.y.toDouble(),
size,
imageSize,
rotation,
cameraLensDirection,
);
final dx = rightEarX - leftEarX;
final dy = rightEarY - leftEarY;
final faceWidth = sqrt(dx * dx + dy * dy) * 1.5;
final angle = atan2(dy, dx);
final yaw = face.headEulerAngleY ?? 0;
final scaleX = cos(yaw * pi / 180).abs();
final earSize = faceWidth / 2.5;
_drawImage(
canvas,
_earImage!,
Offset(leftEarX, leftEarY + earSize * 0.3),
earSize,
angle,
scaleX,
);
_drawImage(
canvas,
_earImage!,
Offset(rightEarX, rightEarY + earSize * 0.3),
earSize,
angle,
scaleX,
isFlipped: true,
);
final noseSize = faceWidth * 0.4;
_drawImage(
canvas,
_noseImage!,
Offset(noseX, noseY + noseSize * 0.1),
noseSize,
angle,
scaleX,
);
}
}
}
void _drawImage(
Canvas canvas,
ui.Image image,
Offset position,
double size,
double rotation,
double scaleX, {
bool isFlipped = false,
}) {
canvas
..save()
..translate(position.dx, position.dy)
..rotate(rotation);
if (isFlipped) {
canvas.scale(-scaleX, Platform.isAndroid ? -1 : 1);
} else {
canvas.scale(scaleX, Platform.isAndroid ? -1 : 1);
}
final srcRect =
Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble());
final aspectRatio = image.width / image.height;
final dstWidth = size;
final dstHeight = size / aspectRatio;
final dstRect = Rect.fromCenter(
center: Offset.zero,
width: dstWidth,
height: dstHeight,
);
canvas
..drawImageRect(image, srcRect, dstRect, Paint())
..restore();
}
static Widget getPreview() {
return Preview(
child: Stack(
alignment: Alignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 25),
child: Image.asset(
'assets/filters/dog_brown_nose.webp',
width: 25,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/filters/dog_brown_ear.webp',
width: 20,
),
const SizedBox(width: 15),
Transform.scale(
scaleX: -1,
child: Image.asset(
'assets/filters/dog_brown_ear.webp',
width: 20,
),
),
],
),
),
],
),
);
}
}

View file

@ -1,44 +0,0 @@
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
abstract class FaceFilterPainter extends CustomPainter {
FaceFilterPainter(
this.faces,
this.imageSize,
this.rotation,
this.cameraLensDirection,
);
final List<Face> faces;
final Size imageSize;
final InputImageRotation rotation;
final CameraLensDirection cameraLensDirection;
@override
bool shouldRepaint(covariant FaceFilterPainter oldDelegate) {
return oldDelegate.imageSize != imageSize ||
oldDelegate.faces != faces ||
oldDelegate.rotation != rotation ||
oldDelegate.cameraLensDirection != cameraLensDirection;
}
}
class Preview extends StatelessWidget {
const Preview({required this.child, super.key});
final Widget child;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.withValues(alpha: 0.2),
),
child: Center(
child: child,
),
);
}
}

View file

@ -67,6 +67,16 @@ class _FlameCounterWidgetState extends State<FlameCounterWidget> {
@override
Widget build(BuildContext context) {
if (flameCounter < 1) return Container();
var flameEmoji = '🔥';
if (isBestFriend) flameEmoji = '❤️‍🔥';
if (flameCounter == 100) flameEmoji = '💯';
if (flameCounter >= 365 && flameCounter % 365 == 0) {
flameEmoji = '🎂';
}
return Row(
children: [
if (widget.prefix) const SizedBox(width: 5),
@ -79,7 +89,7 @@ class _FlameCounterWidgetState extends State<FlameCounterWidget> {
SizedBox(
height: 15,
child: EmojiAnimation(
emoji: isBestFriend ? '❤️‍🔥' : '🔥',
emoji: flameEmoji,
),
),
],

View file

@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: _flutterfire_internals
sha256: cd83f7d6bd4e4c0b0b4fef802e8796784032e1cc23d7b0e982cf5d05d9bbe182
sha256: afe15ce18a287d2f89da95566e62892df339b1936bbe9b83587df45b944ee72a
url: "https://pub.dev"
source: hosted
version: "1.3.66"
version: "1.3.67"
adaptive_number:
dependency: "direct overridden"
description:
@ -68,10 +68,10 @@ packages:
dependency: "direct main"
description:
name: archive
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff
url: "https://pub.dev"
source: hosted
version: "4.0.7"
version: "4.0.9"
args:
dependency: transitive
description:
@ -108,10 +108,10 @@ packages:
dependency: "direct main"
description:
name: background_downloader
sha256: "2ea5322fe836c0aaf96aefd29ef1936771c71927f687cf18168dcc119666a45f"
sha256: "4cb23d9ad4f5060944f38164e7b90d4bf99b57b2472a3bd4676e59b2db4afd06"
url: "https://pub.dev"
source: hosted
version: "9.5.2"
version: "9.5.4"
boolean_selector:
dependency: transitive
description:
@ -164,10 +164,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: "7931c90b84bc573fef103548e354258ae4c9d28d140e41961df6843c5d60d4d8"
sha256: "6ae8a6435a8c6520c7077b107e77f1fb4ba7009633259a4d49a8afd8e7efc5e9"
url: "https://pub.dev"
source: hosted
version: "8.12.3"
version: "8.12.4"
cached_network_image:
dependency: "direct main"
description:
@ -196,10 +196,10 @@ packages:
dependency: "direct main"
description:
name: camera
sha256: a005c6b9783d895a3a9808d65d06773d13587e22a186b6fe8ef3801b0d12f8cf
sha256: "4142a19a38e388d3bab444227636610ba88982e36dff4552d5191a86f65dc437"
url: "https://pub.dev"
source: hosted
version: "0.11.3+1"
version: "0.11.4"
camera_android_camerax:
dependency: "direct overridden"
description:
@ -365,10 +365,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "15a7db352c8fc6a4d2bc475ba901c25b39fe7157541da4c16eacce6f8be83e49"
sha256: "6f6b30cba0301e7b38f32bdc9a6bdae6f5921a55f0a1eb9450e1e6515645dbb2"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
version: "3.1.6"
dbus:
dependency: transitive
description:
@ -508,10 +508,10 @@ packages:
dependency: "direct main"
description:
name: firebase_core
sha256: "923085c881663ef685269b013e241b428e1fb03cdd0ebde265d9b40ff18abf80"
sha256: f0997fee80fbb6d2c658c5b88ae87ba1f9506b5b37126db64fc2e75d8e977fbb
url: "https://pub.dev"
source: hosted
version: "4.4.0"
version: "4.5.0"
firebase_core_platform_interface:
dependency: transitive
description:
@ -524,34 +524,34 @@ packages:
dependency: transitive
description:
name: firebase_core_web
sha256: "83e7356c704131ca4d8d8dd57e360d8acecbca38b1a3705c7ae46cc34c708084"
sha256: "856ca92bf2d75a63761286ab8e791bda3a85184c2b641764433b619647acfca6"
url: "https://pub.dev"
source: hosted
version: "3.4.0"
version: "3.5.0"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "06fad40ea14771e969a8f2bbce1944aa20ee2f4f57f4eca5b3ba346b65f3f644"
sha256: bd17823b70e629877904d384841cda72ed2cc197517404c0c90da5c0ba786a8c
url: "https://pub.dev"
source: hosted
version: "16.1.1"
version: "16.1.2"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: "6c49e901c77e6e10e86d98e32056a087eb1ca1b93acdf58524f1961e617657b7"
sha256: "550435235cc7d53683f32bf0762c28ef8cfc20a8d36318a033676ae09526d7fb"
url: "https://pub.dev"
source: hosted
version: "4.7.6"
version: "4.7.7"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "2756f8fea583ffb9d294d15ddecb3a9ad429b023b70c9990c151fc92c54a32b3"
sha256: "6b1b93ed90309fbce91c219e3cd32aa831e8eccaf4a61f3afaea1625479275d2"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
version: "4.1.3"
fixnum:
dependency: "direct main"
description:
@ -868,14 +868,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.11.1"
google_mlkit_face_detection:
dependency: "direct main"
description:
name: google_mlkit_face_detection
sha256: "7b6ddcc69dbd6fbfa313fb2d974ad0f0c3a0d1657560f0da6be465baf1889687"
url: "https://pub.dev"
source: hosted
version: "0.13.2"
graphs:
dependency: transitive
description:
@ -957,10 +949,10 @@ packages:
dependency: "direct main"
description:
name: image
sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c"
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
url: "https://pub.dev"
source: hosted
version: "4.7.2"
version: "4.8.0"
image_picker:
dependency: "direct main"
description:
@ -973,10 +965,10 @@ packages:
dependency: transitive
description:
name: image_picker_android
sha256: "518a16108529fc18657a3e6dde4a043dc465d16596d20ab2abd49a4cac2e703d"
sha256: eda9b91b7e266d9041084a42d605a74937d996b87083395c5e47835916a86156
url: "https://pub.dev"
source: hosted
version: "0.8.13+13"
version: "0.8.13+14"
image_picker_for_web:
dependency: transitive
description:
@ -1053,10 +1045,10 @@ packages:
dependency: transitive
description:
name: in_app_purchase_storekit
sha256: f7cbbd7fb47ab5a4fb736fc3f20ae81a4f6def0af9297b3c525ca727761e2589
sha256: "2f1a1db44798158076ced07d401b349880dd24a29c7c50a1b1a0de230b7f2f62"
url: "https://pub.dev"
source: hosted
version: "0.4.7"
version: "0.4.8"
intl:
dependency: "direct main"
description:
@ -1100,26 +1092,18 @@ packages:
dependency: "direct main"
description:
name: json_annotation
sha256: "805fa86df56383000f640384b282ce0cb8431f1a7a2396de92fb66186d8c57df"
sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8
url: "https://pub.dev"
source: hosted
version: "4.10.0"
json_schema:
dependency: transitive
description:
name: json_schema
sha256: f37d9c3fdfe8c9aae55fdfd5af815d24ce63c3a0f6a2c1f0982c30f43643fa1a
url: "https://pub.dev"
source: hosted
version: "5.2.2"
version: "4.11.0"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
sha256: "93fba3ad139dab2b1ce59ecc6fdce6da46a42cdb6c4399ecda30f1e7e725760d"
sha256: "44729f5c45748e6748f6b9a57ab8f7e4336edc8ae41fc295070e3814e616a6c0"
url: "https://pub.dev"
source: hosted
version: "6.12.0"
version: "6.13.0"
leak_tracker:
dependency: transitive
description:
@ -1163,26 +1147,26 @@ packages:
dependency: "direct main"
description:
name: local_auth
sha256: a4f1bf57f0236a4aeb5e8f0ec180e197f4b112a3456baa6c1e73b546630b0422
sha256: ae6f382f638108c6becd134318d7c3f0a93875383a54010f61d7c97ac05d5137
url: "https://pub.dev"
source: hosted
version: "3.0.0"
version: "3.0.1"
local_auth_android:
dependency: transitive
description:
name: local_auth_android
sha256: "162b8e177fd9978c4620da2a8002a5c6bed4d20f0c6daf5137e72e9a8b767d2e"
sha256: dc9663a7bc8ac33d7d988e63901974f63d527ebef260eabd19c479447cc9c911
url: "https://pub.dev"
source: hosted
version: "2.0.4"
version: "2.0.5"
local_auth_darwin:
dependency: transitive
description:
name: local_auth_darwin
sha256: "176480aa855ebedeed195e26ac7d6601a45e6b255dfc7433f353e0c1aeafa9a2"
sha256: a8c3d4e17454111f7fd31ff72a31222359f6059f7fe956c2dcfe0f88f49826d4
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.0.3"
local_auth_platform_interface:
dependency: transitive
description:
@ -1447,10 +1431,10 @@ packages:
dependency: transitive
description:
name: petitparser
sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1"
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
url: "https://pub.dev"
source: hosted
version: "7.0.1"
version: "7.0.2"
photo_view:
dependency: "direct main"
description:
@ -1493,18 +1477,18 @@ packages:
dependency: transitive
description:
name: posix
sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61"
sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07"
url: "https://pub.dev"
source: hosted
version: "6.0.3"
version: "6.5.0"
pro_video_editor:
dependency: "direct main"
description:
name: pro_video_editor
sha256: "0d985f7653c59e2b521d19db49351476eb74eb4001689b33fb8112ab1a9c4330"
sha256: "5aa37aed1399333a3ac4b78ce00c7dcba77c5e407b6420960bba43751895fa22"
url: "https://pub.dev"
source: hosted
version: "1.6.1"
version: "1.6.2"
protobuf:
dependency: "direct main"
description:
@ -1551,14 +1535,6 @@ packages:
relative: true
source: path
version: "4.1.0"
quiver:
dependency: transitive
description:
name: quiver
sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2
url: "https://pub.dev"
source: hosted
version: "3.2.2"
recase:
dependency: transitive
description:
@ -1571,18 +1547,10 @@ packages:
dependency: "direct main"
description:
name: restart_app
sha256: "00d5ec3e9de871cedbe552fc41e615b042b5ec654385e090e0983f6d02f655ed"
sha256: "0fd0a14cedfcd65d429588c204de44493866438391a9ee97ecf910ce591323ae"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
rfc_6901:
dependency: transitive
description:
name: rfc_6901
sha256: "6a43b1858dca2febaf93e15639aa6b0c49ccdfd7647775f15a499f872b018154"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
version: "1.7.2"
rxdart:
dependency: transitive
description:
@ -1603,18 +1571,18 @@ packages:
dependency: transitive
description:
name: sentry
sha256: e57e57123968b673c8ca19892eecf93113b4811b8e5cd5d165749ca7f7319fdb
sha256: "605ad1f6f1ae5b72018cbe8fc20f490fa3bd53e58882e5579566776030d8c8c1"
url: "https://pub.dev"
source: hosted
version: "9.13.0"
version: "9.14.0"
sentry_flutter:
dependency: "direct main"
description:
name: sentry_flutter
sha256: c8f5b805c0346cd0c93b09e584675af7ed8c3ef36c3589181ad19b4adce35954
sha256: "7fd0fb80050c1f6a77ae185bda997a76d384326d6777cf5137a6c38952c4ac7d"
url: "https://pub.dev"
source: hosted
version: "9.13.0"
version: "9.14.0"
share_plus:
dependency: "direct main"
description:
@ -1643,10 +1611,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_android
sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f
sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41"
url: "https://pub.dev"
source: hosted
version: "2.4.20"
version: "2.4.21"
shared_preferences_foundation:
dependency: transitive
description:
@ -1848,10 +1816,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "19a78f63e83d3a61f00826d09bc2f60e191bf3504183c001262be6ac75589fb8"
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.8"
version: "0.7.9"
timezone:
dependency: transitive
description:
@ -1868,14 +1836,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
uri:
dependency: transitive
description:
name: uri
sha256: "889eea21e953187c6099802b7b4cf5219ba8f3518f604a1033064d45b1b8268a"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
url_launcher:
dependency: "direct main"
description:
@ -1896,10 +1856,10 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
sha256: b1aca26728b7cc7a3af971bb6f601554a8ae9df2e0a006de8450ba06a17ad36a
sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0"
url: "https://pub.dev"
source: hosted
version: "6.4.0"
version: "6.4.1"
url_launcher_linux:
dependency: transitive
description:
@ -1944,10 +1904,10 @@ packages:
dependency: transitive
description:
name: uuid
sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8
sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489"
url: "https://pub.dev"
source: hosted
version: "4.5.2"
version: "4.5.3"
vector_graphics:
dependency: "direct main"
description:
@ -1968,10 +1928,10 @@ packages:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "201e876b5d52753626af64b6359cd13ac6011b80728731428fd34bc840f71c9b"
sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74"
url: "https://pub.dev"
source: hosted
version: "1.1.20"
version: "1.2.0"
vector_math:
dependency: transitive
description:
@ -1984,10 +1944,10 @@ packages:
dependency: "direct dev"
description:
name: very_good_analysis
sha256: "27927d1140ce1b140f998b6340f730a626faa5b95110b3e34a238ff254d731d0"
sha256: d1cb1d66a5aae2c702d68caca6c8347306d35e728fd94555fa21fa0448a972e0
url: "https://pub.dev"
source: hosted
version: "10.1.0"
version: "10.2.0"
video_compress:
dependency: "direct main"
description:
@ -2000,18 +1960,18 @@ packages:
dependency: "direct main"
description:
name: video_player
sha256: "096bc28ce10d131be80dfb00c223024eb0fba301315a406728ab43dd99c45bdf"
sha256: "08bfba72e311d48219acad4e191b1f9c27ff8cf928f2c7234874592d9c9d7341"
url: "https://pub.dev"
source: hosted
version: "2.10.1"
version: "2.11.0"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: ee4fd520b0cafa02e4a867a0f882092e727cdaa1a2d24762171e787f8a502b0a
sha256: "9862c67c4661c98f30fe707bc1a4f97d6a0faa76784f485d282668e4651a7ac3"
url: "https://pub.dev"
source: hosted
version: "2.9.1"
version: "2.9.4"
video_player_avfoundation:
dependency: transitive
description:
@ -2092,6 +2052,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
workmanager:
dependency: "direct main"
description:
name: workmanager
sha256: "065673b2a465865183093806925419d311a9a5e0995aa74ccf8920fd695e2d10"
url: "https://pub.dev"
source: hosted
version: "0.9.0+3"
workmanager_android:
dependency: transitive
description:
name: workmanager_android
sha256: "9ae744db4ef891f5fcd2fb8671fccc712f4f96489a487a1411e0c8675e5e8cb7"
url: "https://pub.dev"
source: hosted
version: "0.9.0+2"
workmanager_apple:
dependency: transitive
description:
name: workmanager_apple
sha256: "1cc12ae3cbf5535e72f7ba4fde0c12dd11b757caf493a28e22d684052701f2ca"
url: "https://pub.dev"
source: hosted
version: "0.9.1+2"
workmanager_platform_interface:
dependency: transitive
description:
name: workmanager_platform_interface
sha256: f40422f10b970c67abb84230b44da22b075147637532ac501729256fcea10a47
url: "https://pub.dev"
source: hosted
version: "0.9.1+1"
x25519:
dependency: "direct overridden"
description:
@ -2124,5 +2116,5 @@ packages:
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.10.3 <4.0.0"
dart: ">=3.11.0 <4.0.0"
flutter: ">=3.38.4"

View file

@ -48,6 +48,7 @@ dependencies:
font_awesome_flutter: ^10.10.0
share_plus: ^12.0.0
package_info_plus: ^9.0.0
workmanager: ^0.9.0+3
# Trustworthy publishers
@ -63,10 +64,27 @@ dependencies:
drift: ^2.25.1
drift_flutter: ^0.2.4
flutter_local_notifications: ^19.1.0
sentry_flutter: ^9.8.0
sentry_flutter: ^9.14.0
# With high download
# Overwritten by self-controlled repository
emoji_picker_flutter: ^4.3.0
# Packages which got overwritten using the twonly-app-dependencies repository
# Idea: Every change goes though a git commit, where every change can be reviewed.
restart_app: ^1.3.2
photo_view: ^0.15.0
hashlib: ^2.0.0
libsignal_protocol_dart: ^0.7.4
lottie: ^3.3.1
mutex: ^3.1.0
introduction_screen: ^4.0.0
qr_flutter: ^4.1.0
hand_signature: ^3.0.3
flutter_sharing_intent: ^2.0.4
no_screenshot: ^0.3.1
# With high download. (But should be checked nonetheless.)
app_links: ^7.0.0 # 1.6 mio
image: ^4.3.0 # 3.3 mio
archive: ^4.0.7 # 6.5 mio
@ -75,7 +93,6 @@ dependencies:
flutter_secure_storage: ^10.0.0 # 1.85 mio
permission_handler: ^12.0.0+1 # 2 mio
# Not yet checked
audio_waveforms: ^2.0.0
avatar_maker: ^0.4.0
@ -88,30 +105,6 @@ dependencies:
flutter_volume_controller: ^1.3.4
gal: ^2.3.1
google_mlkit_barcode_scanning: ^0.14.1
# flutter_secure_storage:
# git:
# url: https://github.com/juliansteenbakker/flutter_secure_storage.git
# ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop
# path: flutter_secure_storage/
# Overwritten by self-controlled repository
emoji_picker_flutter: ^4.3.0
# Packages which got overwritten using the twonly-app-dependencies repository
restart_app: ^1.3.2
photo_view: ^0.15.0
hashlib: ^2.0.0
libsignal_protocol_dart: ^0.7.4
lottie: ^3.3.1
mutex: ^3.1.0
introduction_screen: ^4.0.0
qr_flutter: ^4.1.0
hand_signature: ^3.0.3
flutter_sharing_intent: ^2.0.4
no_screenshot: ^0.3.1
google_mlkit_face_detection: ^0.13.1
pro_video_editor: ^1.6.1
video_compress: ^3.1.4
@ -208,6 +201,5 @@ flutter:
- assets/animated_icons/
- assets/animations/
- assets/passwords/
- assets/filters/
- CHANGELOG.md