[mob][photos] Face thumbnail fix + smooth scroll (#6616)
## Description - Fix internal issue with face thumbnail generation - Make all people page scroll more smooth ## Tests Tested on internal build.
This commit is contained in:
@@ -360,6 +360,10 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
}
|
||||
return mapRowToFace(faceMaps.first);
|
||||
}
|
||||
} else if (clusterID == null) {
|
||||
_logger.severe(
|
||||
"Didn't find any faces for personID $personID in `getCoverFaceForPerson`.",
|
||||
);
|
||||
}
|
||||
if (clusterID != null) {
|
||||
const String queryFaceID = '''
|
||||
@@ -380,11 +384,19 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
return face;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_logger.severe(
|
||||
"Didn't find any faces for clusterID $clusterID in `getCoverFaceForPerson`. faces: $faces",
|
||||
);
|
||||
}
|
||||
}
|
||||
if (personID == null && clusterID == null) {
|
||||
_logger.severe("personID and clusterID cannot be null both");
|
||||
throw Exception("personID and clusterID cannot be null");
|
||||
}
|
||||
_logger.severe(
|
||||
"Something went wrong finding a face from `getCoverFaceForPerson` (personID: $personID, clusterID: $clusterID)",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ import "package:ml_linalg/dtype.dart";
|
||||
import "package:ml_linalg/vector.dart";
|
||||
import "package:photos/generated/protos/ente/common/vector.pb.dart";
|
||||
import "package:photos/models/base/id.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart";
|
||||
import "package:photos/services/machine_learning/ml_result.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
|
||||
class FaceInfo {
|
||||
final String faceID;
|
||||
@@ -507,7 +507,8 @@ ClusteringResult _runCompleteClustering(Map args) {
|
||||
EVector.fromBuffer(entry.value).values,
|
||||
dtype: DType.float32,
|
||||
),
|
||||
fileCreationTime: fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
fileCreationTime:
|
||||
fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
|
||||
import "package:computer/computer.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/ml/face/box.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import "package:photos/utils/image_ml_util.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
|
||||
final Computer _computer = Computer.shared();
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
class FaceThumbnailGenerator extends SuperIsolate {
|
||||
@override
|
||||
Logger get logger => _logger;
|
||||
@@ -37,20 +35,30 @@ class FaceThumbnailGenerator extends SuperIsolate {
|
||||
String imagePath,
|
||||
List<FaceBox> faceBoxes,
|
||||
) async {
|
||||
final List<Map<String, dynamic>> faceBoxesJson =
|
||||
faceBoxes.map((box) => box.toJson()).toList();
|
||||
final List<Uint8List> faces = await runInIsolate(
|
||||
IsolateOperation.generateFaceThumbnails,
|
||||
{
|
||||
'imagePath': imagePath,
|
||||
'faceBoxesList': faceBoxesJson,
|
||||
},
|
||||
).then((value) => value.cast<Uint8List>());
|
||||
final compressedFaces =
|
||||
await compressFaceThumbnails({'listPngBytes': faces});
|
||||
_logger.fine(
|
||||
"Compressed face thumbnails from sizes ${faces.map((e) => e.length / 1024).toList()} to ${compressedFaces.map((e) => e.length / 1024).toList()} kilobytes",
|
||||
);
|
||||
return compressedFaces;
|
||||
try {
|
||||
_logger.info(
|
||||
"Generating face thumbnails for ${faceBoxes.length} face boxes in $imagePath",
|
||||
);
|
||||
final List<Map<String, dynamic>> faceBoxesJson =
|
||||
faceBoxes.map((box) => box.toJson()).toList();
|
||||
final List<Uint8List> faces = await runInIsolate(
|
||||
IsolateOperation.generateFaceThumbnails,
|
||||
{
|
||||
'imagePath': imagePath,
|
||||
'faceBoxesList': faceBoxesJson,
|
||||
},
|
||||
).then((value) => value.cast<Uint8List>());
|
||||
_logger.info("Generated face thumbnails");
|
||||
final compressedFaces =
|
||||
await compressFaceThumbnails({'listPngBytes': faces});
|
||||
_logger.fine(
|
||||
"Compressed face thumbnails from sizes ${faces.map((e) => e.length / 1024).toList()} to ${compressedFaces.map((e) => e.length / 1024).toList()} kilobytes",
|
||||
);
|
||||
return compressedFaces;
|
||||
} catch (e, s) {
|
||||
_logger.severe("Failed to generate face thumbnails", e, s);
|
||||
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import 'dart:async';
|
||||
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/ml/vector.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import "package:photos/services/machine_learning/ml_constants.dart";
|
||||
import "package:photos/services/machine_learning/semantic_search/clip/clip_text_encoder.dart";
|
||||
import "package:photos/services/machine_learning/semantic_search/query_result.dart";
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
class MLComputer extends SuperIsolate {
|
||||
|
||||
@@ -2,14 +2,14 @@ import "dart:async";
|
||||
|
||||
import "package:flutter/foundation.dart" show debugPrint;
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_service.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart';
|
||||
import "package:photos/services/machine_learning/ml_models_overview.dart";
|
||||
import 'package:photos/services/machine_learning/ml_result.dart';
|
||||
import "package:photos/services/machine_learning/semantic_search/clip/clip_image_encoder.dart";
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
import "package:photos/utils/ml_util.dart";
|
||||
import "package:photos/utils/network_util.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
@@ -21,6 +21,7 @@ class PersonFaceWidget extends StatefulWidget {
|
||||
final String? clusterID;
|
||||
final bool useFullFile;
|
||||
final VoidCallback? onErrorCallback;
|
||||
final bool keepAlive;
|
||||
|
||||
// PersonFaceWidget constructor checks that both personId and clusterID are not null
|
||||
// and that the file is not null
|
||||
@@ -29,6 +30,7 @@ class PersonFaceWidget extends StatefulWidget {
|
||||
this.clusterID,
|
||||
this.useFullFile = true,
|
||||
this.onErrorCallback,
|
||||
this.keepAlive = false,
|
||||
super.key,
|
||||
}) : assert(
|
||||
personId != null || clusterID != null,
|
||||
@@ -39,12 +41,16 @@ class PersonFaceWidget extends StatefulWidget {
|
||||
State<PersonFaceWidget> createState() => _PersonFaceWidgetState();
|
||||
}
|
||||
|
||||
class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
class _PersonFaceWidgetState extends State<PersonFaceWidget>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
Future<Uint8List?>? faceCropFuture;
|
||||
EnteFile? fileForFaceCrop;
|
||||
|
||||
bool get isPerson => widget.personId != null;
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => widget.keepAlive;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -64,6 +70,10 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(
|
||||
context,
|
||||
); // Calling super.build for AutomaticKeepAliveClientMixin
|
||||
|
||||
return FutureBuilder<Uint8List?>(
|
||||
future: faceCropFuture,
|
||||
builder: (context, snapshot) {
|
||||
@@ -163,7 +173,7 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
}
|
||||
}
|
||||
if (fileForFaceCrop == null) {
|
||||
_logger.warning(
|
||||
_logger.severe(
|
||||
"No suitable file found for face crop for person: ${widget.personId} or cluster: ${widget.clusterID}",
|
||||
);
|
||||
return null;
|
||||
@@ -176,7 +186,7 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
clusterID: widget.clusterID,
|
||||
);
|
||||
if (face == null) {
|
||||
debugPrint(
|
||||
_logger.severe(
|
||||
"No cover face for person: ${widget.personId} or cluster ${widget.clusterID} and fileID ${fileForFaceCrop.uploadedFileID!}",
|
||||
);
|
||||
return null;
|
||||
@@ -188,7 +198,13 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
personOrClusterID: personOrClusterId,
|
||||
useTempCache: false,
|
||||
);
|
||||
return cropMap?[face.faceID];
|
||||
final result = cropMap?[face.faceID];
|
||||
if (result == null) {
|
||||
_logger.severe(
|
||||
"Null cover face crop for person: ${widget.personId} or cluster ${widget.clusterID} and fileID ${fileForFaceCrop.uploadedFileID!}",
|
||||
);
|
||||
}
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
_logger.severe(
|
||||
"Error getting cover face for person: ${widget.personId} or cluster ${widget.clusterID}",
|
||||
|
||||
@@ -95,12 +95,14 @@ class SelectablePersonSearchExample extends StatelessWidget {
|
||||
final GenericSearchResult searchResult;
|
||||
final double size;
|
||||
final SelectedPeople selectedPeople;
|
||||
final bool isDefaultFace;
|
||||
|
||||
const SelectablePersonSearchExample({
|
||||
super.key,
|
||||
required this.searchResult,
|
||||
required this.selectedPeople,
|
||||
this.size = 102,
|
||||
this.isDefaultFace = false,
|
||||
});
|
||||
|
||||
void _handleTap(BuildContext context) {
|
||||
@@ -192,7 +194,10 @@ class SelectablePersonSearchExample extends StatelessWidget {
|
||||
searchResult.previewThumbnail()!,
|
||||
shouldShowSyncStatus: false,
|
||||
)
|
||||
: FaceSearchResult(searchResult);
|
||||
: FaceSearchResult(
|
||||
searchResult,
|
||||
isDefaultFace: isDefaultFace,
|
||||
);
|
||||
} else {
|
||||
child = const NoThumbnailWidget(
|
||||
addBorder: false,
|
||||
@@ -301,8 +306,13 @@ class SelectablePersonSearchExample extends StatelessWidget {
|
||||
|
||||
class FaceSearchResult extends StatelessWidget {
|
||||
final SearchResult searchResult;
|
||||
final bool isDefaultFace;
|
||||
|
||||
const FaceSearchResult(this.searchResult, {super.key});
|
||||
const FaceSearchResult(
|
||||
this.searchResult, {
|
||||
super.key,
|
||||
this.isDefaultFace = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -313,6 +323,7 @@ class FaceSearchResult extends StatelessWidget {
|
||||
key: params.containsKey(kPersonWidgetKey)
|
||||
? ValueKey(params[kPersonWidgetKey])
|
||||
: ValueKey(params[kPersonParamID] ?? params[kClusterParamId]),
|
||||
keepAlive: isDefaultFace,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -486,6 +497,7 @@ class _PeopleSectionAllWidgetState extends State<PeopleSectionAllWidget> {
|
||||
searchResult: normalFaces[index],
|
||||
size: itemSize,
|
||||
selectedPeople: widget.selectedPeople!,
|
||||
isDefaultFace: true,
|
||||
)
|
||||
: PersonSearchExample(
|
||||
searchResult: normalFaces[index],
|
||||
@@ -525,6 +537,7 @@ class _PeopleSectionAllWidgetState extends State<PeopleSectionAllWidget> {
|
||||
searchResult: extraFaces[index],
|
||||
size: itemSize,
|
||||
selectedPeople: widget.selectedPeople!,
|
||||
isDefaultFace: false,
|
||||
)
|
||||
: PersonSearchExample(
|
||||
searchResult: extraFaces[index],
|
||||
|
||||
@@ -129,7 +129,7 @@ Future<Map<String, Uint8List>?> getCachedFaceCrops(
|
||||
);
|
||||
faceIdToCrop[face.faceID] = data;
|
||||
} else {
|
||||
_logger.warning(
|
||||
_logger.severe(
|
||||
"Cached face crop for faceID ${face.faceID} is empty, deleting file ${faceCropCacheFile.path}",
|
||||
);
|
||||
await faceCropCacheFile.delete();
|
||||
@@ -231,7 +231,7 @@ Future<Map<String, Uint8List>?> getCachedFaceCrops(
|
||||
s,
|
||||
);
|
||||
} else {
|
||||
_logger.info(
|
||||
_logger.severe(
|
||||
"Stopped getting face crops for faceIDs: ${faces.map((face) => face.faceID).toList()} due to $e",
|
||||
);
|
||||
}
|
||||
@@ -334,12 +334,14 @@ Future<Map<String, Uint8List>?> _getFaceCrops(
|
||||
if (useFullFile && file.fileType != FileType.video) {
|
||||
final File? ioFile = await getFile(file);
|
||||
if (ioFile == null) {
|
||||
_logger.severe("Failed to get file for face crop generation");
|
||||
return null;
|
||||
}
|
||||
imagePath = ioFile.path;
|
||||
} else {
|
||||
final thumbnail = await getThumbnailForUploadedFile(file);
|
||||
if (thumbnail == null) {
|
||||
_logger.severe("Failed to get thumbnail for face crop generation");
|
||||
return null;
|
||||
}
|
||||
imagePath = thumbnail.path;
|
||||
|
||||
@@ -575,7 +575,7 @@ Future<List<Uint8List>> compressFaceThumbnails(Map args) async {
|
||||
}
|
||||
return await Future.wait(compressedBytesList);
|
||||
} catch (e, s) {
|
||||
_logger.warning(
|
||||
_logger.severe(
|
||||
'Failed to compress face thumbnail, using original. Size: ${listPngBytes.map((e) => e.length).toList()} bytes',
|
||||
e,
|
||||
s,
|
||||
|
||||
@@ -7,9 +7,10 @@ import "package:flutter/services.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/core/error-reporting/isolate_logging.dart";
|
||||
import "package:photos/models/base/id.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
abstract class SuperIsolate {
|
||||
Logger get logger;
|
||||
|
||||
@@ -80,6 +81,8 @@ abstract class SuperIsolate {
|
||||
if (rootToken != null) {
|
||||
BackgroundIsolateBinaryMessenger.ensureInitialized(rootToken);
|
||||
}
|
||||
final logger = Logger('SuperIsolate');
|
||||
logger.info('IsolateMain started');
|
||||
|
||||
receivePort.listen((message) async {
|
||||
final taskID = message[0] as String;
|
||||
@@ -87,6 +90,7 @@ abstract class SuperIsolate {
|
||||
final function = IsolateOperation.values[functionIndex];
|
||||
final args = message[2] as Map<String, dynamic>;
|
||||
final sendPort = message[3] as SendPort;
|
||||
logger.info("Starting isolate operation $function in isolate");
|
||||
|
||||
late final Object data;
|
||||
try {
|
||||
@@ -5,10 +5,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "72.0.0"
|
||||
version: "76.0.0"
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -21,7 +21,7 @@ packages:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
version: "0.3.3"
|
||||
adaptive_theme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -34,10 +34,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.7.0"
|
||||
version: "6.11.0"
|
||||
android_intent_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -130,10 +130,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
version: "2.12.0"
|
||||
battery_info:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -155,10 +155,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
brotli:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -268,10 +268,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -301,10 +301,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.2"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -317,10 +317,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
version: "1.19.1"
|
||||
computer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -619,10 +619,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.3.2"
|
||||
fast_base58:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -668,10 +668,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
version: "7.0.1"
|
||||
file_saver:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1416,18 +1416,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.5"
|
||||
version: "10.0.8"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.9"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1536,10 +1536,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
version: "0.1.3-main.0"
|
||||
maps_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1552,10 +1552,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
version: "0.12.17"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1645,10 +1645,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
mgrs_dart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1859,10 +1859,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.1"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2019,10 +2019,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.5"
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2068,10 +2068,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
|
||||
sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.2"
|
||||
version: "5.0.3"
|
||||
proj4dart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2309,7 +2309,7 @@ packages:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
version: "0.0.0"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2346,10 +2346,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.10.1"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2434,10 +2434,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
version: "1.12.1"
|
||||
step_progress_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2450,10 +2450,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2466,10 +2466,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.4.1"
|
||||
styled_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2522,34 +2522,34 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
|
||||
sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.25.7"
|
||||
version: "1.25.15"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
version: "0.7.4"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
|
||||
sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.4"
|
||||
version: "0.6.8"
|
||||
thermal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2813,10 +2813,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "14.3.1"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2877,10 +2877,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webdriver
|
||||
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
|
||||
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.4"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2978,5 +2978,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.7.0-0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
|
||||
Reference in New Issue
Block a user