mirror of
https://github.com/immich-app/immich.git
synced 2025-09-29 15:31:13 -04:00
feat: resurrect advanced info (#21633)
* feat: resurrect advanced info * display null values as well * add exif details --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
39eee6a634
commit
67a8cab286
@ -1978,6 +1978,7 @@
|
|||||||
"trash_page_select_assets_btn": "Select assets",
|
"trash_page_select_assets_btn": "Select assets",
|
||||||
"trash_page_title": "Trash ({count})",
|
"trash_page_title": "Trash ({count})",
|
||||||
"trashed_items_will_be_permanently_deleted_after": "Trashed items will be permanently deleted after {days, plural, one {# day} other {# days}}.",
|
"trashed_items_will_be_permanently_deleted_after": "Trashed items will be permanently deleted after {days, plural, one {# day} other {# days}}.",
|
||||||
|
"troubleshoot": "Troubleshoot",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"unable_to_change_pin_code": "Unable to change PIN code",
|
"unable_to_change_pin_code": "Unable to change PIN code",
|
||||||
"unable_to_setup_pin_code": "Unable to setup PIN code",
|
"unable_to_setup_pin_code": "Unable to setup PIN code",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/local_asset.repository.dart';
|
||||||
@ -27,6 +28,14 @@ class AssetService {
|
|||||||
return asset is LocalAsset ? _localAssetRepository.watch(id) : _remoteAssetRepository.watch(id);
|
return asset is LocalAsset ? _localAssetRepository.watch(id) : _remoteAssetRepository.watch(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<LocalAsset?>> getLocalAssetsByChecksum(String checksum) {
|
||||||
|
return _localAssetRepository.getByChecksum(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<RemoteAsset?> getRemoteAssetByChecksum(String checksum) {
|
||||||
|
return _remoteAssetRepository.getByChecksum(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
Future<RemoteAsset?> getRemoteAsset(String id) {
|
Future<RemoteAsset?> getRemoteAsset(String id) {
|
||||||
return _remoteAssetRepository.get(id);
|
return _remoteAssetRepository.get(id);
|
||||||
}
|
}
|
||||||
@ -89,4 +98,8 @@ class AssetService {
|
|||||||
Future<int> getLocalHashedCount() {
|
Future<int> getLocalHashedCount() {
|
||||||
return _localAssetRepository.getHashedCount();
|
return _localAssetRepository.getHashedCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<LocalAlbum>> getSourceAlbums(String localAssetId, {BackupSelection? backupSelection}) {
|
||||||
|
return _localAssetRepository.getSourceAlbums(localAssetId, backupSelection: backupSelection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import 'package:drift/drift.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
@ -138,22 +137,4 @@ class DriftBackupRepository extends DriftDatabaseRepository {
|
|||||||
|
|
||||||
return query.map((localAsset) => localAsset.toDto()).get();
|
return query.map((localAsset) => localAsset.toDto()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<List<LocalAlbum>> getSourceAlbums(String localAssetId) {
|
|
||||||
final query = _db.localAlbumEntity.select()
|
|
||||||
..where(
|
|
||||||
(lae) =>
|
|
||||||
existsQuery(
|
|
||||||
_db.localAlbumAssetEntity.selectOnly()
|
|
||||||
..addColumns([_db.localAlbumAssetEntity.albumId])
|
|
||||||
..where(
|
|
||||||
_db.localAlbumAssetEntity.albumId.equalsExp(lae.id) &
|
|
||||||
_db.localAlbumAssetEntity.assetId.equals(localAssetId),
|
|
||||||
),
|
|
||||||
) &
|
|
||||||
lae.backupSelection.equalsValue(BackupSelection.selected),
|
|
||||||
)
|
|
||||||
..orderBy([(lae) => OrderingTerm.asc(lae.name)]);
|
|
||||||
return query.map((localAlbum) => localAlbum.toDto()).get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/infrastructure/entities/local_album.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.dart';
|
||||||
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
import 'package:immich_mobile/infrastructure/entities/local_asset.entity.drift.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
@ -26,6 +28,12 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
|||||||
|
|
||||||
Future<LocalAsset?> get(String id) => _assetSelectable(id).getSingleOrNull();
|
Future<LocalAsset?> get(String id) => _assetSelectable(id).getSingleOrNull();
|
||||||
|
|
||||||
|
Future<List<LocalAsset?>> getByChecksum(String checksum) {
|
||||||
|
final query = _db.localAssetEntity.select()..where((lae) => lae.checksum.equals(checksum));
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).get();
|
||||||
|
}
|
||||||
|
|
||||||
Stream<LocalAsset?> watch(String id) => _assetSelectable(id).watchSingleOrNull();
|
Stream<LocalAsset?> watch(String id) => _assetSelectable(id).watchSingleOrNull();
|
||||||
|
|
||||||
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
Future<void> updateHashes(Iterable<LocalAsset> hashes) {
|
||||||
@ -69,4 +77,23 @@ class DriftLocalAssetRepository extends DriftDatabaseRepository {
|
|||||||
Future<int> getHashedCount() {
|
Future<int> getHashedCount() {
|
||||||
return _db.managers.localAssetEntity.filter((e) => e.checksum.isNull().not()).count();
|
return _db.managers.localAssetEntity.filter((e) => e.checksum.isNull().not()).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<LocalAlbum>> getSourceAlbums(String localAssetId, {BackupSelection? backupSelection}) {
|
||||||
|
final query = _db.localAlbumEntity.select()
|
||||||
|
..where(
|
||||||
|
(lae) => existsQuery(
|
||||||
|
_db.localAlbumAssetEntity.selectOnly()
|
||||||
|
..addColumns([_db.localAlbumAssetEntity.albumId])
|
||||||
|
..where(
|
||||||
|
_db.localAlbumAssetEntity.albumId.equalsExp(lae.id) &
|
||||||
|
_db.localAlbumAssetEntity.assetId.equals(localAssetId),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
..orderBy([(lae) => OrderingTerm.asc(lae.name)]);
|
||||||
|
if (backupSelection != null) {
|
||||||
|
query.where((lae) => lae.backupSelection.equalsValue(backupSelection));
|
||||||
|
}
|
||||||
|
return query.map((localAlbum) => localAlbum.toDto()).get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,12 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
|||||||
return _assetSelectable(id).getSingleOrNull();
|
return _assetSelectable(id).getSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<RemoteAsset?> getByChecksum(String checksum) {
|
||||||
|
final query = _db.remoteAssetEntity.select()..where((row) => row.checksum.equals(checksum));
|
||||||
|
|
||||||
|
return query.map((row) => row.toDto()).getSingleOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<RemoteAsset>> getStackChildren(RemoteAsset asset) {
|
Future<List<RemoteAsset>> getStackChildren(RemoteAsset asset) {
|
||||||
if (asset.stackId == null) {
|
if (asset.stackId == null) {
|
||||||
return Future.value([]);
|
return Future.value([]);
|
||||||
|
345
mobile/lib/presentation/pages/drift_asset_troubleshoot.page.dart
Normal file
345
mobile/lib/presentation/pages/drift_asset_troubleshoot.page.dart
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
|
|
||||||
|
@RoutePage()
|
||||||
|
class AssetTroubleshootPage extends ConsumerWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
const AssetTroubleshootPage({super.key, required this.asset});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: const Text("Asset Troubleshoot")),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: _AssetDetailsView(asset: asset),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AssetDetailsView extends ConsumerWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
const _AssetDetailsView({required this.asset});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_AssetPropertiesSection(asset: asset),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text('Matching Assets', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
||||||
|
if (asset.checksum != null) ...[
|
||||||
|
_LocalAssetsSection(asset: asset),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_RemoteAssetSection(asset: asset),
|
||||||
|
] else ...[
|
||||||
|
const _PropertySectionCard(
|
||||||
|
title: 'Local Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Status', value: 'No checksum available - cannot fetch local assets')],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const _PropertySectionCard(
|
||||||
|
title: 'Remote Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Status', value: 'No checksum available - cannot fetch remote asset')],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AssetPropertiesSection extends ConsumerStatefulWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
const _AssetPropertiesSection({required this.asset});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState createState() => _AssetPropertiesSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AssetPropertiesSectionState extends ConsumerState<_AssetPropertiesSection> {
|
||||||
|
List<_PropertyItem> properties = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_buildAssetProperties(widget.asset).whenComplete(() {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final title = _getAssetTypeTitle(widget.asset);
|
||||||
|
|
||||||
|
return _PropertySectionCard(title: title, properties: properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _buildAssetProperties(BaseAsset asset) async {
|
||||||
|
_addCommonProperties();
|
||||||
|
|
||||||
|
if (asset is LocalAsset) {
|
||||||
|
await _addLocalAssetProperties(asset);
|
||||||
|
} else if (asset is RemoteAsset) {
|
||||||
|
await _addRemoteAssetProperties(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addCommonProperties() {
|
||||||
|
final asset = widget.asset;
|
||||||
|
properties.addAll([
|
||||||
|
_PropertyItem(label: 'Name', value: asset.name),
|
||||||
|
_PropertyItem(label: 'Checksum', value: asset.checksum),
|
||||||
|
_PropertyItem(label: 'Type', value: asset.type.toString()),
|
||||||
|
_PropertyItem(label: 'Created At', value: asset.createdAt.toString()),
|
||||||
|
_PropertyItem(label: 'Updated At', value: asset.updatedAt.toString()),
|
||||||
|
_PropertyItem(label: 'Width', value: asset.width?.toString()),
|
||||||
|
_PropertyItem(label: 'Height', value: asset.height?.toString()),
|
||||||
|
_PropertyItem(
|
||||||
|
label: 'Duration',
|
||||||
|
value: asset.durationInSeconds != null ? '${asset.durationInSeconds} seconds' : null,
|
||||||
|
),
|
||||||
|
_PropertyItem(label: 'Is Favorite', value: asset.isFavorite.toString()),
|
||||||
|
_PropertyItem(label: 'Live Photo Video ID', value: asset.livePhotoVideoId),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _addLocalAssetProperties(LocalAsset asset) async {
|
||||||
|
properties.insertAll(0, [
|
||||||
|
_PropertyItem(label: 'Local ID', value: asset.id),
|
||||||
|
_PropertyItem(label: 'Remote ID', value: asset.remoteId),
|
||||||
|
]);
|
||||||
|
|
||||||
|
properties.insert(4, _PropertyItem(label: 'Orientation', value: asset.orientation.toString()));
|
||||||
|
final albums = await ref.read(assetServiceProvider).getSourceAlbums(asset.id);
|
||||||
|
properties.add(_PropertyItem(label: 'Album', value: albums.map((a) => a.name).join(', ')));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _addRemoteAssetProperties(RemoteAsset asset) async {
|
||||||
|
properties.insertAll(0, [
|
||||||
|
_PropertyItem(label: 'Remote ID', value: asset.id),
|
||||||
|
_PropertyItem(label: 'Local ID', value: asset.localId),
|
||||||
|
_PropertyItem(label: 'Owner ID', value: asset.ownerId),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final additionalProps = <_PropertyItem>[
|
||||||
|
_PropertyItem(label: 'Thumb Hash', value: asset.thumbHash),
|
||||||
|
_PropertyItem(label: 'Visibility', value: asset.visibility.toString()),
|
||||||
|
_PropertyItem(label: 'Stack ID', value: asset.stackId),
|
||||||
|
];
|
||||||
|
|
||||||
|
properties.insertAll(4, additionalProps);
|
||||||
|
|
||||||
|
final exif = await ref.read(assetServiceProvider).getExif(asset);
|
||||||
|
if (exif != null) {
|
||||||
|
_addExifProperties(exif);
|
||||||
|
} else {
|
||||||
|
properties.add(const _PropertyItem(label: 'EXIF', value: null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addExifProperties(ExifInfo exif) {
|
||||||
|
properties.addAll([
|
||||||
|
_PropertyItem(
|
||||||
|
label: 'File Size',
|
||||||
|
value: exif.fileSize != null ? '${(exif.fileSize! / 1024 / 1024).toStringAsFixed(2)} MB' : null,
|
||||||
|
),
|
||||||
|
_PropertyItem(label: 'Description', value: exif.description),
|
||||||
|
_PropertyItem(label: 'EXIF Width', value: exif.width?.toString()),
|
||||||
|
_PropertyItem(label: 'EXIF Height', value: exif.height?.toString()),
|
||||||
|
_PropertyItem(label: 'Date Taken', value: exif.dateTimeOriginal?.toString()),
|
||||||
|
_PropertyItem(label: 'Time Zone', value: exif.timeZone),
|
||||||
|
_PropertyItem(label: 'Camera Make', value: exif.make),
|
||||||
|
_PropertyItem(label: 'Camera Model', value: exif.model),
|
||||||
|
_PropertyItem(label: 'Lens', value: exif.lens),
|
||||||
|
_PropertyItem(label: 'F-Number', value: exif.f != null ? 'f/${exif.fNumber}' : null),
|
||||||
|
_PropertyItem(label: 'Focal Length', value: exif.mm != null ? '${exif.focalLength}mm' : null),
|
||||||
|
_PropertyItem(label: 'ISO', value: exif.iso?.toString()),
|
||||||
|
_PropertyItem(label: 'Exposure Time', value: exif.exposureTime.isNotEmpty ? exif.exposureTime : null),
|
||||||
|
_PropertyItem(
|
||||||
|
label: 'GPS Coordinates',
|
||||||
|
value: exif.hasCoordinates ? '${exif.latitude}, ${exif.longitude}' : null,
|
||||||
|
),
|
||||||
|
_PropertyItem(
|
||||||
|
label: 'Location',
|
||||||
|
value: [exif.city, exif.state, exif.country].where((e) => e != null && e.isNotEmpty).join(', '),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getAssetTypeTitle(BaseAsset asset) {
|
||||||
|
if (asset is LocalAsset) return 'Local Asset';
|
||||||
|
if (asset is RemoteAsset) return 'Remote Asset';
|
||||||
|
return 'Base Asset';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LocalAssetsSection extends ConsumerWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
const _LocalAssetsSection({required this.asset});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final assetService = ref.watch(assetServiceProvider);
|
||||||
|
|
||||||
|
return FutureBuilder<List<LocalAsset?>>(
|
||||||
|
future: assetService.getLocalAssetsByChecksum(asset.checksum!),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return const _PropertySectionCard(
|
||||||
|
title: 'Local Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Status', value: 'Loading...')],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot.hasError) {
|
||||||
|
return _PropertySectionCard(
|
||||||
|
title: 'Local Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Error', value: snapshot.error.toString())],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final localAssets = snapshot.data?.cast<LocalAsset>() ?? [];
|
||||||
|
if (asset is LocalAsset) {
|
||||||
|
localAssets.removeWhere((a) => a.id == (asset as LocalAsset).id);
|
||||||
|
|
||||||
|
if (localAssets.isEmpty) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localAssets.isEmpty) {
|
||||||
|
return const _PropertySectionCard(
|
||||||
|
title: 'Local Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Status', value: 'No local assets found with this checksum')],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (localAssets.length > 1)
|
||||||
|
_PropertySectionCard(
|
||||||
|
title: 'Local Assets Summary',
|
||||||
|
properties: [_PropertyItem(label: 'Total Count', value: localAssets.length.toString())],
|
||||||
|
),
|
||||||
|
...localAssets.map((localAsset) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 16),
|
||||||
|
child: _AssetPropertiesSection(asset: localAsset),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RemoteAssetSection extends ConsumerWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
const _RemoteAssetSection({required this.asset});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final assetService = ref.watch(assetServiceProvider);
|
||||||
|
|
||||||
|
if (asset is RemoteAsset) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FutureBuilder<RemoteAsset?>(
|
||||||
|
future: assetService.getRemoteAssetByChecksum(asset.checksum!),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return const _PropertySectionCard(
|
||||||
|
title: 'Remote Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Status', value: 'Loading...')],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot.hasError) {
|
||||||
|
return _PropertySectionCard(
|
||||||
|
title: 'Remote Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Error', value: snapshot.error.toString())],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final remoteAsset = snapshot.data;
|
||||||
|
|
||||||
|
if (remoteAsset == null) {
|
||||||
|
return const _PropertySectionCard(
|
||||||
|
title: 'Remote Assets',
|
||||||
|
properties: [_PropertyItem(label: 'Status', value: 'No remote asset found with this checksum')],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _AssetPropertiesSection(asset: remoteAsset);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PropertySectionCard extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final List<_PropertyItem> properties;
|
||||||
|
|
||||||
|
const _PropertySectionCard({required this.title, required this.properties});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 8),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
...properties,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PropertyItem extends StatelessWidget {
|
||||||
|
final String label;
|
||||||
|
final String? value;
|
||||||
|
|
||||||
|
const _PropertyItem({required this.label, this.value});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 120,
|
||||||
|
child: Text('$label:', style: const TextStyle(fontWeight: FontWeight.w500)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(value ?? 'N/A', style: TextStyle(color: Theme.of(context).colorScheme.secondary)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
|
|
||||||
|
class AdvancedInfoActionButton extends ConsumerWidget {
|
||||||
|
final ActionSource source;
|
||||||
|
|
||||||
|
const AdvancedInfoActionButton({super.key, required this.source});
|
||||||
|
|
||||||
|
void _onTap(BuildContext context, WidgetRef ref) async {
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.read(actionProvider.notifier).troubleshoot(source, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 115.0,
|
||||||
|
iconData: Icons.help_outline_rounded,
|
||||||
|
label: "troubleshoot".t(context: context),
|
||||||
|
onPressed: () => _onTap(context, ref),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/setting.model.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart';
|
||||||
@ -14,6 +15,7 @@ import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
|||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
||||||
import 'package:immich_mobile/providers/routes.provider.dart';
|
import 'package:immich_mobile/providers/routes.provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
@ -41,6 +43,7 @@ class AssetDetailBottomSheet extends ConsumerWidget {
|
|||||||
final isInLockedView = ref.watch(inLockedViewProvider);
|
final isInLockedView = ref.watch(inLockedViewProvider);
|
||||||
final currentAlbum = ref.watch(currentRemoteAlbumProvider);
|
final currentAlbum = ref.watch(currentRemoteAlbumProvider);
|
||||||
final isArchived = asset is RemoteAsset && asset.visibility == AssetVisibility.archive;
|
final isArchived = asset is RemoteAsset && asset.visibility == AssetVisibility.archive;
|
||||||
|
final advancedTroubleshooting = ref.watch(settingsProvider.notifier).get(Setting.advancedTroubleshooting);
|
||||||
|
|
||||||
final buttonContext = ActionButtonContext(
|
final buttonContext = ActionButtonContext(
|
||||||
asset: asset,
|
asset: asset,
|
||||||
@ -49,6 +52,7 @@ class AssetDetailBottomSheet extends ConsumerWidget {
|
|||||||
isTrashEnabled: isTrashEnable,
|
isTrashEnabled: isTrashEnable,
|
||||||
isInLockedView: isInLockedView,
|
isInLockedView: isInLockedView,
|
||||||
currentAlbum: currentAlbum,
|
currentAlbum: currentAlbum,
|
||||||
|
advancedTroubleshooting: advancedTroubleshooting,
|
||||||
source: ActionSource.viewer,
|
source: ActionSource.viewer,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -122,6 +126,10 @@ class _AssetDetailBottomSheet extends ConsumerWidget {
|
|||||||
return [fNumber, exposureTime, focalLength, iso].where((spec) => spec != null && spec.isNotEmpty).join(_kSeparator);
|
return [fNumber, exposureTime, focalLength, iso].where((spec) => spec != null && spec.isNotEmpty).join(_kSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _editDateTime(BuildContext context, WidgetRef ref) async {
|
||||||
|
await ref.read(actionProvider.notifier).editDateTime(ActionSource.viewer, context);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final asset = ref.watch(currentAssetNotifier);
|
final asset = ref.watch(currentAssetNotifier);
|
||||||
@ -132,10 +140,6 @@ class _AssetDetailBottomSheet extends ConsumerWidget {
|
|||||||
final exifInfo = ref.watch(currentAssetExifProvider).valueOrNull;
|
final exifInfo = ref.watch(currentAssetExifProvider).valueOrNull;
|
||||||
final cameraTitle = _getCameraInfoTitle(exifInfo);
|
final cameraTitle = _getCameraInfoTitle(exifInfo);
|
||||||
|
|
||||||
Future<void> editDateTime() async {
|
|
||||||
await ref.read(actionProvider.notifier).editDateTime(ActionSource.viewer, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SliverList.list(
|
return SliverList.list(
|
||||||
children: [
|
children: [
|
||||||
// Asset Date and Time
|
// Asset Date and Time
|
||||||
@ -143,7 +147,7 @@ class _AssetDetailBottomSheet extends ConsumerWidget {
|
|||||||
title: _getDateTime(context, asset),
|
title: _getDateTime(context, asset),
|
||||||
titleStyle: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600),
|
titleStyle: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600),
|
||||||
trailing: asset.hasRemote ? const Icon(Icons.edit, size: 18) : null,
|
trailing: asset.hasRemote ? const Icon(Icons.edit, size: 18) : null,
|
||||||
onTap: asset.hasRemote ? () async => await editDateTime() : null,
|
onTap: asset.hasRemote ? () async => await _editDateTime(context, ref) : null,
|
||||||
),
|
),
|
||||||
if (exifInfo != null) _SheetAssetDescription(exif: exifInfo),
|
if (exifInfo != null) _SheetAssetDescription(exif: exifInfo),
|
||||||
const SheetPeopleDetails(),
|
const SheetPeopleDetails(),
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
|
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_permanent_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart';
|
||||||
|
@ -4,6 +4,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/setting.model.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
||||||
@ -21,6 +23,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_
|
|||||||
import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/setting.provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
@ -51,6 +54,7 @@ class _GeneralBottomSheetState extends ConsumerState<GeneralBottomSheet> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final multiselect = ref.watch(multiSelectProvider);
|
final multiselect = ref.watch(multiSelectProvider);
|
||||||
final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash));
|
final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash));
|
||||||
|
final advancedTroubleshooting = ref.watch(settingsProvider.notifier).get(Setting.advancedTroubleshooting);
|
||||||
|
|
||||||
Future<void> addAssetsToAlbum(RemoteAlbum album) async {
|
Future<void> addAssetsToAlbum(RemoteAlbum album) async {
|
||||||
final selectedAssets = multiselect.selectedAssets;
|
final selectedAssets = multiselect.selectedAssets;
|
||||||
@ -88,6 +92,9 @@ class _GeneralBottomSheetState extends ConsumerState<GeneralBottomSheet> {
|
|||||||
maxChildSize: 0.85,
|
maxChildSize: 0.85,
|
||||||
shouldCloseOnMinExtent: false,
|
shouldCloseOnMinExtent: false,
|
||||||
actions: [
|
actions: [
|
||||||
|
if (multiselect.selectedAssets.length == 1 && advancedTroubleshooting) ...[
|
||||||
|
const AdvancedInfoActionButton(source: ActionSource.timeline),
|
||||||
|
],
|
||||||
const ShareActionButton(source: ActionSource.timeline),
|
const ShareActionButton(source: ActionSource.timeline),
|
||||||
if (multiselect.hasRemote) ...[
|
if (multiselect.hasRemote) ...[
|
||||||
const ShareLinkActionButton(source: ActionSource.timeline),
|
const ShareLinkActionButton(source: ActionSource.timeline),
|
||||||
|
@ -6,11 +6,11 @@ import 'package:background_downloader/background_downloader.dart';
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
import 'package:immich_mobile/domain/models/album/local_album.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/upload.service.dart';
|
import 'package:immich_mobile/services/upload.service.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@ -380,5 +380,5 @@ final driftCandidateBackupAlbumInfoProvider = FutureProvider.autoDispose.family<
|
|||||||
ref,
|
ref,
|
||||||
assetId,
|
assetId,
|
||||||
) {
|
) {
|
||||||
return ref.read(backupRepositoryProvider).getSourceAlbums(assetId);
|
return ref.read(localAssetRepository).getSourceAlbums(assetId, backupSelection: BackupSelection.selected);
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
@ -6,6 +7,7 @@ import 'package:immich_mobile/models/download/livephotos_medatada.model.dart';
|
|||||||
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/services/action.service.dart';
|
import 'package:immich_mobile/services/action.service.dart';
|
||||||
import 'package:immich_mobile/services/download.service.dart';
|
import 'package:immich_mobile/services/download.service.dart';
|
||||||
import 'package:immich_mobile/services/timeline.service.dart';
|
import 'package:immich_mobile/services/timeline.service.dart';
|
||||||
@ -115,6 +117,16 @@ class ActionNotifier extends Notifier<void> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ActionResult> troubleshoot(ActionSource source, BuildContext context) async {
|
||||||
|
final assets = _getAssets(source);
|
||||||
|
if (assets.length > 1) {
|
||||||
|
return ActionResult(count: assets.length, success: false, error: 'Cannot troubleshoot multiple assets');
|
||||||
|
}
|
||||||
|
context.pushRoute(AssetTroubleshootRoute(asset: assets.first));
|
||||||
|
|
||||||
|
return ActionResult(count: assets.length, success: true);
|
||||||
|
}
|
||||||
|
|
||||||
Future<ActionResult> shareLink(ActionSource source, BuildContext context) async {
|
Future<ActionResult> shareLink(ActionSource source, BuildContext context) async {
|
||||||
final ids = _getRemoteIdsForSource(source);
|
final ids = _getRemoteIdsForSource(source);
|
||||||
try {
|
try {
|
||||||
|
@ -86,6 +86,7 @@ import 'package:immich_mobile/presentation/pages/drift_album.page.dart';
|
|||||||
import 'package:immich_mobile/presentation/pages/drift_album_options.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_album_options.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_archive.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_archive.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_asset_selection_timeline.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_asset_selection_timeline.page.dart';
|
||||||
|
import 'package:immich_mobile/presentation/pages/drift_asset_troubleshoot.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_create_album.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_create_album.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_favorite.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_favorite.page.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/drift_library.page.dart';
|
import 'package:immich_mobile/presentation/pages/drift_library.page.dart';
|
||||||
@ -343,6 +344,7 @@ class AppRouter extends RootStackRouter {
|
|||||||
AutoRoute(page: DriftFilterImageRoute.page),
|
AutoRoute(page: DriftFilterImageRoute.page),
|
||||||
AutoRoute(page: DriftActivitiesRoute.page, guards: [_authGuard, _duplicateGuard]),
|
AutoRoute(page: DriftActivitiesRoute.page, guards: [_authGuard, _duplicateGuard]),
|
||||||
AutoRoute(page: DriftBackupAssetDetailRoute.page, guards: [_authGuard, _duplicateGuard]),
|
AutoRoute(page: DriftBackupAssetDetailRoute.page, guards: [_authGuard, _duplicateGuard]),
|
||||||
|
AutoRoute(page: AssetTroubleshootRoute.page, guards: [_authGuard, _duplicateGuard]),
|
||||||
// required to handle all deeplinks in deep_link.service.dart
|
// required to handle all deeplinks in deep_link.service.dart
|
||||||
// auto_route_library#1722
|
// auto_route_library#1722
|
||||||
RedirectRoute(path: '*', redirectTo: '/'),
|
RedirectRoute(path: '*', redirectTo: '/'),
|
||||||
|
@ -403,6 +403,43 @@ class ArchiveRoute extends PageRouteInfo<void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// generated route for
|
||||||
|
/// [AssetTroubleshootPage]
|
||||||
|
class AssetTroubleshootRoute extends PageRouteInfo<AssetTroubleshootRouteArgs> {
|
||||||
|
AssetTroubleshootRoute({
|
||||||
|
Key? key,
|
||||||
|
required BaseAsset asset,
|
||||||
|
List<PageRouteInfo>? children,
|
||||||
|
}) : super(
|
||||||
|
AssetTroubleshootRoute.name,
|
||||||
|
args: AssetTroubleshootRouteArgs(key: key, asset: asset),
|
||||||
|
initialChildren: children,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const String name = 'AssetTroubleshootRoute';
|
||||||
|
|
||||||
|
static PageInfo page = PageInfo(
|
||||||
|
name,
|
||||||
|
builder: (data) {
|
||||||
|
final args = data.argsAs<AssetTroubleshootRouteArgs>();
|
||||||
|
return AssetTroubleshootPage(key: args.key, asset: args.asset);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssetTroubleshootRouteArgs {
|
||||||
|
const AssetTroubleshootRouteArgs({this.key, required this.asset});
|
||||||
|
|
||||||
|
final Key? key;
|
||||||
|
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'AssetTroubleshootRouteArgs{key: $key, asset: $asset}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// generated route for
|
/// generated route for
|
||||||
/// [AssetViewerPage]
|
/// [AssetViewerPage]
|
||||||
class AssetViewerRoute extends PageRouteInfo<AssetViewerRouteArgs> {
|
class AssetViewerRoute extends PageRouteInfo<AssetViewerRouteArgs> {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/advanced_info_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
||||||
@ -15,7 +17,6 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_act
|
|||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/unarchive_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/unarchive_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
||||||
|
|
||||||
class ActionButtonContext {
|
class ActionButtonContext {
|
||||||
final BaseAsset asset;
|
final BaseAsset asset;
|
||||||
@ -24,6 +25,7 @@ class ActionButtonContext {
|
|||||||
final bool isTrashEnabled;
|
final bool isTrashEnabled;
|
||||||
final bool isInLockedView;
|
final bool isInLockedView;
|
||||||
final RemoteAlbum? currentAlbum;
|
final RemoteAlbum? currentAlbum;
|
||||||
|
final bool advancedTroubleshooting;
|
||||||
final ActionSource source;
|
final ActionSource source;
|
||||||
|
|
||||||
const ActionButtonContext({
|
const ActionButtonContext({
|
||||||
@ -33,11 +35,13 @@ class ActionButtonContext {
|
|||||||
required this.isTrashEnabled,
|
required this.isTrashEnabled,
|
||||||
required this.isInLockedView,
|
required this.isInLockedView,
|
||||||
required this.currentAlbum,
|
required this.currentAlbum,
|
||||||
|
required this.advancedTroubleshooting,
|
||||||
required this.source,
|
required this.source,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ActionButtonType {
|
enum ActionButtonType {
|
||||||
|
advancedInfo,
|
||||||
share,
|
share,
|
||||||
shareLink,
|
shareLink,
|
||||||
archive,
|
archive,
|
||||||
@ -55,6 +59,7 @@ enum ActionButtonType {
|
|||||||
|
|
||||||
bool shouldShow(ActionButtonContext context) {
|
bool shouldShow(ActionButtonContext context) {
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
|
ActionButtonType.advancedInfo => context.advancedTroubleshooting,
|
||||||
ActionButtonType.share => true,
|
ActionButtonType.share => true,
|
||||||
ActionButtonType.shareLink =>
|
ActionButtonType.shareLink =>
|
||||||
!context.isInLockedView && //
|
!context.isInLockedView && //
|
||||||
@ -115,6 +120,7 @@ enum ActionButtonType {
|
|||||||
|
|
||||||
Widget buildButton(ActionButtonContext context) {
|
Widget buildButton(ActionButtonContext context) {
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
|
ActionButtonType.advancedInfo => AdvancedInfoActionButton(source: context.source),
|
||||||
ActionButtonType.share => ShareActionButton(source: context.source),
|
ActionButtonType.share => ShareActionButton(source: context.source),
|
||||||
ActionButtonType.shareLink => ShareLinkActionButton(source: context.source),
|
ActionButtonType.shareLink => ShareLinkActionButton(source: context.source),
|
||||||
ActionButtonType.archive => ArchiveActionButton(source: context.source),
|
ActionButtonType.archive => ArchiveActionButton(source: context.source),
|
||||||
@ -138,6 +144,7 @@ enum ActionButtonType {
|
|||||||
|
|
||||||
class ActionButtonBuilder {
|
class ActionButtonBuilder {
|
||||||
static const List<ActionButtonType> _actionTypes = [
|
static const List<ActionButtonType> _actionTypes = [
|
||||||
|
ActionButtonType.advancedInfo,
|
||||||
ActionButtonType.share,
|
ActionButtonType.share,
|
||||||
ActionButtonType.shareLink,
|
ActionButtonType.shareLink,
|
||||||
ActionButtonType.likeActivity,
|
ActionButtonType.likeActivity,
|
||||||
|
@ -81,6 +81,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -110,6 +111,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -124,6 +126,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: true,
|
isInLockedView: true,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -141,6 +144,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -156,6 +160,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: true,
|
isInLockedView: true,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -171,6 +176,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -188,6 +194,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -203,6 +210,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -218,6 +226,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: true,
|
isInLockedView: true,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -233,6 +242,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -248,6 +258,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -265,6 +276,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -280,6 +292,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -295,6 +308,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -312,6 +326,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -327,6 +342,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -342,6 +358,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: true,
|
isInLockedView: true,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -359,6 +376,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -374,6 +392,7 @@ void main() {
|
|||||||
isTrashEnabled: false,
|
isTrashEnabled: false,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -391,6 +410,7 @@ void main() {
|
|||||||
isTrashEnabled: false,
|
isTrashEnabled: false,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -406,6 +426,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -423,6 +444,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -440,6 +462,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -457,6 +480,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -472,6 +496,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -489,6 +514,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -506,6 +532,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: album,
|
currentAlbum: album,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -520,6 +547,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -537,6 +565,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: album,
|
currentAlbum: album,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -552,6 +581,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: album,
|
currentAlbum: album,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -567,6 +597,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: album,
|
currentAlbum: album,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -581,12 +612,45 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(ActionButtonType.likeActivity.shouldShow(context), isFalse);
|
expect(ActionButtonType.likeActivity.shouldShow(context), isFalse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('advancedTroubleshooting button', () {
|
||||||
|
test('should show when in advanced troubleshooting mode', () {
|
||||||
|
final context = ActionButtonContext(
|
||||||
|
asset: mergedAsset,
|
||||||
|
isOwner: true,
|
||||||
|
isArchived: false,
|
||||||
|
isTrashEnabled: true,
|
||||||
|
isInLockedView: false,
|
||||||
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: true,
|
||||||
|
source: ActionSource.timeline,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(ActionButtonType.advancedInfo.shouldShow(context), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show when not in advanced troubleshooting mode', () {
|
||||||
|
final context = ActionButtonContext(
|
||||||
|
asset: mergedAsset,
|
||||||
|
isOwner: true,
|
||||||
|
isArchived: false,
|
||||||
|
isTrashEnabled: true,
|
||||||
|
isInLockedView: false,
|
||||||
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
|
source: ActionSource.timeline,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(ActionButtonType.advancedInfo.shouldShow(context), isFalse);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('ActionButtonType.buildButton', () {
|
group('ActionButtonType.buildButton', () {
|
||||||
@ -602,6 +666,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -617,6 +682,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: album,
|
currentAlbum: album,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
final widget = buttonType.buildButton(contextWithAlbum);
|
final widget = buttonType.buildButton(contextWithAlbum);
|
||||||
@ -639,6 +705,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -658,6 +725,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: album,
|
currentAlbum: album,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -675,6 +743,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -693,6 +762,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -705,6 +775,7 @@ void main() {
|
|||||||
isTrashEnabled: true,
|
isTrashEnabled: true,
|
||||||
isInLockedView: false,
|
isInLockedView: false,
|
||||||
currentAlbum: null,
|
currentAlbum: null,
|
||||||
|
advancedTroubleshooting: false,
|
||||||
source: ActionSource.timeline,
|
source: ActionSource.timeline,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user