chore: bump dart sdk to 3.8 (#20355)

* chore: bump dart sdk to 3.8

* chore: make build

* make pigeon

* chore: format files

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong 2025-07-29 00:34:03 +05:30 committed by GitHub
parent 9b3718120b
commit e52b9d15b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
643 changed files with 32561 additions and 35292 deletions

View file

@ -5,20 +5,12 @@ import 'package:immich_mobile/domain/services/setting.service.dart';
import 'package:immich_mobile/presentation/widgets/images/local_image_provider.dart';
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
ImageProvider getFullImageProvider(
BaseAsset asset, {
Size size = const Size(1080, 1920),
}) {
ImageProvider getFullImageProvider(BaseAsset asset, {Size size = const Size(1080, 1920)}) {
// Create new provider and cache it
final ImageProvider provider;
if (_shouldUseLocalAsset(asset)) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).localId!;
provider = LocalFullImageProvider(
id: id,
name: asset.name,
size: size,
type: asset.type,
);
provider = LocalFullImageProvider(id: id, name: asset.name, size: size, type: asset.type);
} else {
final String assetId;
if (asset is LocalAsset && asset.hasRemote) {
@ -34,15 +26,8 @@ ImageProvider getFullImageProvider(
return provider;
}
ImageProvider getThumbnailImageProvider({
BaseAsset? asset,
String? remoteId,
Size size = const Size.square(256),
}) {
assert(
asset != null || remoteId != null,
'Either asset or remoteId must be provided',
);
ImageProvider getThumbnailImageProvider({BaseAsset? asset, String? remoteId, Size size = const Size.square(256)}) {
assert(asset != null || remoteId != null, 'Either asset or remoteId must be provided');
if (remoteId != null) {
return RemoteThumbProvider(assetId: remoteId);
@ -50,12 +35,7 @@ ImageProvider getThumbnailImageProvider({
if (_shouldUseLocalAsset(asset!)) {
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).localId!;
return LocalThumbProvider(
id: id,
updatedAt: asset.updatedAt,
name: asset.name,
size: size,
);
return LocalThumbProvider(id: id, updatedAt: asset.updatedAt, name: asset.name, size: size);
}
final String assetId;

View file

@ -5,10 +5,7 @@ import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart'
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
class LocalAlbumThumbnail extends ConsumerWidget {
const LocalAlbumThumbnail({
super.key,
required this.albumId,
});
const LocalAlbumThumbnail({super.key, required this.albumId});
final String albumId;
@override
@ -21,34 +18,21 @@ class LocalAlbumThumbnail extends ConsumerWidget {
decoration: BoxDecoration(
color: context.colorScheme.surfaceContainer,
borderRadius: const BorderRadius.all(Radius.circular(16)),
border: Border.all(
color: context.colorScheme.outline.withAlpha(50),
width: 1,
),
),
child: Icon(
Icons.collections,
size: 24,
color: context.primaryColor,
border: Border.all(color: context.colorScheme.outline.withAlpha(50), width: 1),
),
child: Icon(Icons.collections, size: 24, color: context.primaryColor),
);
}
return ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(16)),
child: Thumbnail(
asset: data,
),
child: Thumbnail(asset: data),
);
},
error: (error, stack) {
return const Icon(Icons.error, size: 24);
},
loading: () => const SizedBox(
width: 24,
height: 24,
child: Center(child: CircularProgressIndicator()),
),
loading: () => const SizedBox(width: 24, height: 24, child: Center(child: CircularProgressIndicator())),
);
}
}

View file

@ -39,10 +39,7 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
}
@override
ImageStreamCompleter loadImage(
LocalThumbProvider key,
ImageDecoderCallback decode,
) {
ImageStreamCompleter loadImage(LocalThumbProvider key, ImageDecoderCallback decode) {
final cache = cacheManager ?? ThumbnailImageCacheManager();
return MultiFrameImageStreamCompleter(
codec: _codec(key, cache, decode),
@ -57,11 +54,7 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
);
}
Future<Codec> _codec(
LocalThumbProvider key,
CacheManager cache,
ImageDecoderCallback decode,
) async {
Future<Codec> _codec(LocalThumbProvider key, CacheManager cache, ImageDecoderCallback decode) async {
final cacheKey = '${key.id}-${key.updatedAt}-${key.size.width}x${key.size.height}';
final fileFromCache = await cache.getFileFromCache(cacheKey);
@ -75,9 +68,7 @@ class LocalThumbProvider extends ImageProvider<LocalThumbProvider> {
final thumbnailBytes = await _assetMediaRepository.getThumbnail(key.id, size: key.size);
if (thumbnailBytes == null) {
PaintingBinding.instance.imageCache.evict(key);
throw StateError(
"Loading thumb for local photo ${key.name} failed",
);
throw StateError("Loading thumb for local photo ${key.name} failed");
}
final buffer = await ImmutableBuffer.fromUint8List(thumbnailBytes);
@ -107,12 +98,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
final Size size;
final AssetType type;
const LocalFullImageProvider({
required this.id,
required this.name,
required this.size,
required this.type,
});
const LocalFullImageProvider({required this.id, required this.name, required this.size, required this.type});
@override
Future<LocalFullImageProvider> obtainKey(ImageConfiguration configuration) {
@ -120,10 +106,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
}
@override
ImageStreamCompleter loadImage(
LocalFullImageProvider key,
ImageDecoderCallback decode,
) {
ImageStreamCompleter loadImage(LocalFullImageProvider key, ImageDecoderCallback decode) {
return MultiImageStreamCompleter(
codec: _codec(key, decode),
scale: 1.0,
@ -134,10 +117,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
}
// Streams in each stage of the image as we ask for it
Stream<Codec> _codec(
LocalFullImageProvider key,
ImageDecoderCallback decode,
) async* {
Stream<Codec> _codec(LocalFullImageProvider key, ImageDecoderCallback decode) async* {
try {
switch (key.type) {
case AssetType.image:
@ -156,16 +136,11 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
}
} catch (error, stack) {
Logger('ImmichLocalImageProvider').severe('Error loading local image ${key.name}', error, stack);
throw const ImageLoadingException(
'Could not load image from local storage',
);
throw const ImageLoadingException('Could not load image from local storage');
}
}
Future<Codec?> _getThumbnailCodec(
LocalFullImageProvider key,
ImageDecoderCallback decode,
) async {
Future<Codec?> _getThumbnailCodec(LocalFullImageProvider key, ImageDecoderCallback decode) async {
final thumbBytes = await _assetMediaRepository.getThumbnail(key.id, size: key.size);
if (thumbBytes == null) {
return null;
@ -174,10 +149,7 @@ class LocalFullImageProvider extends ImageProvider<LocalFullImageProvider> {
return decode(buffer);
}
Stream<Codec> _decodeProgressive(
LocalFullImageProvider key,
ImageDecoderCallback decode,
) async* {
Stream<Codec> _decodeProgressive(LocalFullImageProvider key, ImageDecoderCallback decode) async* {
final file = await _storageRepository.getFileForAsset(key.id);
if (file == null) {
throw StateError("Opening file for asset ${key.name} failed");

View file

@ -15,10 +15,7 @@ class RemoteThumbProvider extends ImageProvider<RemoteThumbProvider> {
final String assetId;
final CacheManager? cacheManager;
const RemoteThumbProvider({
required this.assetId,
this.cacheManager,
});
const RemoteThumbProvider({required this.assetId, this.cacheManager});
@override
Future<RemoteThumbProvider> obtainKey(ImageConfiguration configuration) {
@ -26,10 +23,7 @@ class RemoteThumbProvider extends ImageProvider<RemoteThumbProvider> {
}
@override
ImageStreamCompleter loadImage(
RemoteThumbProvider key,
ImageDecoderCallback decode,
) {
ImageStreamCompleter loadImage(RemoteThumbProvider key, ImageDecoderCallback decode) {
final cache = cacheManager ?? RemoteImageCacheManager();
final chunkController = StreamController<ImageChunkEvent>();
return MultiFrameImageStreamCompleter(
@ -49,9 +43,7 @@ class RemoteThumbProvider extends ImageProvider<RemoteThumbProvider> {
ImageDecoderCallback decode,
StreamController<ImageChunkEvent> chunkController,
) async {
final preview = getThumbnailUrlForRemoteId(
key.assetId,
);
final preview = getThumbnailUrlForRemoteId(key.assetId);
return ImageLoader.loadImageFromCache(
preview,
@ -79,10 +71,7 @@ class RemoteFullImageProvider extends ImageProvider<RemoteFullImageProvider> {
final String assetId;
final CacheManager? cacheManager;
const RemoteFullImageProvider({
required this.assetId,
this.cacheManager,
});
const RemoteFullImageProvider({required this.assetId, this.cacheManager});
@override
Future<RemoteFullImageProvider> obtainKey(ImageConfiguration configuration) {
@ -90,10 +79,7 @@ class RemoteFullImageProvider extends ImageProvider<RemoteFullImageProvider> {
}
@override
ImageStreamCompleter loadImage(
RemoteFullImageProvider key,
ImageDecoderCallback decode,
) {
ImageStreamCompleter loadImage(RemoteFullImageProvider key, ImageDecoderCallback decode) {
final cache = cacheManager ?? RemoteImageCacheManager();
final chunkEvents = StreamController<ImageChunkEvent>();
return MultiImageStreamCompleter(

View file

@ -8,9 +8,7 @@ import 'package:thumbhash/thumbhash.dart';
class ThumbHashProvider extends ImageProvider<ThumbHashProvider> {
final String thumbHash;
const ThumbHashProvider({
required this.thumbHash,
});
const ThumbHashProvider({required this.thumbHash});
@override
Future<ThumbHashProvider> obtainKey(ImageConfiguration configuration) {
@ -18,20 +16,11 @@ class ThumbHashProvider extends ImageProvider<ThumbHashProvider> {
}
@override
ImageStreamCompleter loadImage(
ThumbHashProvider key,
ImageDecoderCallback decode,
) {
return MultiFrameImageStreamCompleter(
codec: _loadCodec(key, decode),
scale: 1.0,
);
ImageStreamCompleter loadImage(ThumbHashProvider key, ImageDecoderCallback decode) {
return MultiFrameImageStreamCompleter(codec: _loadCodec(key, decode), scale: 1.0);
}
Future<Codec> _loadCodec(
ThumbHashProvider key,
ImageDecoderCallback decode,
) async {
Future<Codec> _loadCodec(ThumbHashProvider key, ImageDecoderCallback decode) async {
final image = thumbHashToRGBA(base64Decode(key.thumbHash));
return decode(await ImmutableBuffer.fromUint8List(rgbaToBmp(image)));
}

View file

@ -8,16 +8,8 @@ import 'package:logging/logging.dart';
import 'package:octo_image/octo_image.dart';
class Thumbnail extends StatelessWidget {
const Thumbnail({
this.asset,
this.remoteId,
this.size = const Size.square(256),
this.fit = BoxFit.cover,
super.key,
}) : assert(
asset != null || remoteId != null,
'Either asset or remoteId must be provided',
);
const Thumbnail({this.asset, this.remoteId, this.size = const Size.square(256), this.fit = BoxFit.cover, super.key})
: assert(asset != null || remoteId != null, 'Either asset or remoteId must be provided');
final BaseAsset? asset;
final String? remoteId;
@ -33,12 +25,7 @@ class Thumbnail extends StatelessWidget {
image: provider,
octoSet: OctoSet(
placeholderBuilder: _blurHashPlaceholderBuilder(thumbHash, fit: fit),
errorBuilder: _blurHashErrorBuilder(
thumbHash,
provider: provider,
fit: fit,
asset: asset,
),
errorBuilder: _blurHashErrorBuilder(thumbHash, provider: provider, fit: fit, asset: asset),
),
fadeOutDuration: const Duration(milliseconds: 100),
fadeInDuration: Duration.zero,
@ -50,10 +37,7 @@ class Thumbnail extends StatelessWidget {
}
}
OctoPlaceholderBuilder _blurHashPlaceholderBuilder(
String? thumbHash, {
BoxFit? fit,
}) {
OctoPlaceholderBuilder _blurHashPlaceholderBuilder(String? thumbHash, {BoxFit? fit}) {
return (context) => thumbHash == null
? const ThumbnailPlaceholder()
: FadeInPlaceholderImage(
@ -63,12 +47,7 @@ OctoPlaceholderBuilder _blurHashPlaceholderBuilder(
);
}
OctoErrorBuilder _blurHashErrorBuilder(
String? blurhash, {
BaseAsset? asset,
ImageProvider? provider,
BoxFit? fit,
}) =>
OctoErrorBuilder _blurHashErrorBuilder(String? blurhash, {BaseAsset? asset, ImageProvider? provider, BoxFit? fit}) =>
(context, e, s) {
Logger("ImThumbnail").warning("Error loading thumbnail for ${asset?.name}", e, s);
provider?.evict();
@ -76,10 +55,7 @@ OctoErrorBuilder _blurHashErrorBuilder(
alignment: Alignment.center,
children: [
_blurHashPlaceholderBuilder(blurhash, fit: fit)(context),
const Opacity(
opacity: 0.75,
child: Icon(Icons.error_outline_rounded),
),
const Opacity(opacity: 0.75, child: Icon(Icons.error_outline_rounded)),
],
);
};

View file

@ -30,29 +30,25 @@ class ThumbnailTile extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final heroIndex = heroOffset ?? TabsRouterScope.of(context)?.controller.activeIndex ?? 0;
final assetContainerColor =
context.isDarkTheme ? context.primaryColor.darken(amount: 0.4) : context.primaryColor.lighten(amount: 0.75);
final assetContainerColor = context.isDarkTheme
? context.primaryColor.darken(amount: 0.4)
: context.primaryColor.lighten(amount: 0.75);
final isSelected = ref.watch(
multiSelectProvider.select(
(multiselect) => multiselect.selectedAssets.contains(asset),
),
multiSelectProvider.select((multiselect) => multiselect.selectedAssets.contains(asset)),
);
final borderStyle = lockSelection
? BoxDecoration(
color: context.colorScheme.surfaceContainerHighest,
border: Border.all(
color: context.colorScheme.surfaceContainerHighest,
width: 6,
),
border: Border.all(color: context.colorScheme.surfaceContainerHighest, width: 6),
)
: isSelected
? BoxDecoration(
color: assetContainerColor,
border: Border.all(color: assetContainerColor, width: 6),
)
: const BoxDecoration();
? BoxDecoration(
color: assetContainerColor,
border: Border.all(color: assetContainerColor, width: 6),
)
: const BoxDecoration();
final hasStack = asset is RemoteAsset && (asset as RemoteAsset).stackId != null;
@ -63,28 +59,22 @@ class ThumbnailTile extends ConsumerWidget {
curve: Curves.decelerate,
decoration: borderStyle,
child: ClipRRect(
borderRadius:
isSelected || lockSelection ? const BorderRadius.all(Radius.circular(15.0)) : BorderRadius.zero,
borderRadius: isSelected || lockSelection
? const BorderRadius.all(Radius.circular(15.0))
: BorderRadius.zero,
child: Stack(
children: [
Positioned.fill(
child: Hero(
tag: '${asset.heroTag}_$heroIndex',
child: Thumbnail(
asset: asset,
fit: fit,
size: size,
),
child: Thumbnail(asset: asset, fit: fit, size: size),
),
),
if (hasStack)
Align(
alignment: Alignment.topRight,
child: Padding(
padding: EdgeInsets.only(
right: 10.0,
top: asset.isVideo ? 24.0 : 6.0,
),
padding: EdgeInsets.only(right: 10.0, top: asset.isVideo ? 24.0 : 6.0),
child: const _TileOverlayIcon(Icons.burst_mode_rounded),
),
),
@ -99,26 +89,26 @@ class ThumbnailTile extends ConsumerWidget {
if (showStorageIndicator)
switch (asset.storage) {
AssetState.local => const Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10.0, bottom: 6.0),
child: _TileOverlayIcon(Icons.cloud_off_outlined),
),
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10.0, bottom: 6.0),
child: _TileOverlayIcon(Icons.cloud_off_outlined),
),
),
AssetState.remote => const Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10.0, bottom: 6.0),
child: _TileOverlayIcon(Icons.cloud_outlined),
),
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10.0, bottom: 6.0),
child: _TileOverlayIcon(Icons.cloud_outlined),
),
),
AssetState.merged => const Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10.0, bottom: 6.0),
child: _TileOverlayIcon(Icons.cloud_done_outlined),
),
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 10.0, bottom: 6.0),
child: _TileOverlayIcon(Icons.cloud_done_outlined),
),
),
},
if (asset.isFavorite)
const Align(
@ -154,41 +144,22 @@ class _SelectionIndicator extends StatelessWidget {
final bool isLocked;
final Color? color;
const _SelectionIndicator({
required this.isSelected,
required this.isLocked,
this.color,
});
const _SelectionIndicator({required this.isSelected, required this.isLocked, this.color});
@override
Widget build(BuildContext context) {
if (isLocked) {
return DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color,
),
child: const Icon(
Icons.check_circle_rounded,
color: Colors.grey,
),
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
child: const Icon(Icons.check_circle_rounded, color: Colors.grey),
);
} else if (isSelected) {
return DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color,
),
child: Icon(
Icons.check_circle_rounded,
color: context.primaryColor,
),
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
child: Icon(Icons.check_circle_rounded, color: context.primaryColor),
);
} else {
return const Icon(
Icons.circle_outlined,
color: Colors.white,
);
return const Icon(Icons.circle_outlined, color: Colors.white);
}
}
}
@ -212,12 +183,7 @@ class _VideoIndicator extends StatelessWidget {
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
shadows: [
Shadow(
blurRadius: 5.0,
color: Color.fromRGBO(0, 0, 0, 0.6),
),
],
shadows: [Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6))],
),
),
const _TileOverlayIcon(Icons.play_circle_outline_rounded),
@ -237,13 +203,7 @@ class _TileOverlayIcon extends StatelessWidget {
icon,
color: Colors.white,
size: 16,
shadows: [
const Shadow(
blurRadius: 5.0,
color: Color.fromRGBO(0, 0, 0, 0.6),
offset: Offset(0.0, 0.0),
),
],
shadows: [const Shadow(blurRadius: 5.0, color: Color.fromRGBO(0, 0, 0, 0.6), offset: Offset(0.0, 0.0))],
);
}
}