mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	chore(mobile) Improve mobile UI (#1038)
This commit is contained in:
		@@ -12,6 +12,7 @@ import 'package:immich_mobile/shared/providers/api.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/api.service.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/openapi_extensions.dart';
 | 
			
		||||
import 'package:immich_mobile/utils/tuple.dart';
 | 
			
		||||
import 'package:logging/logging.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
final assetServiceProvider = Provider(
 | 
			
		||||
@@ -26,20 +27,26 @@ class AssetService {
 | 
			
		||||
  final ApiService _apiService;
 | 
			
		||||
  final BackupService _backupService;
 | 
			
		||||
  final BackgroundService _backgroundService;
 | 
			
		||||
  final log = Logger('AssetService');
 | 
			
		||||
 | 
			
		||||
  AssetService(this._apiService, this._backupService, this._backgroundService);
 | 
			
		||||
 | 
			
		||||
  /// Returns `null` if the server state did not change, else list of assets
 | 
			
		||||
  Future<List<Asset>?> getRemoteAssets({required bool hasCache}) async {
 | 
			
		||||
    final Box box = Hive.box(userInfoBox);
 | 
			
		||||
    final Pair<List<AssetResponseDto>, String?>? remote = await _apiService
 | 
			
		||||
        .assetApi
 | 
			
		||||
        .getAllAssetsWithETag(eTag: hasCache ? box.get(assetEtagKey) : null);
 | 
			
		||||
    if (remote == null) {
 | 
			
		||||
    try {
 | 
			
		||||
      final Box box = Hive.box(userInfoBox);
 | 
			
		||||
      final Pair<List<AssetResponseDto>, String?>? remote = await _apiService
 | 
			
		||||
          .assetApi
 | 
			
		||||
          .getAllAssetsWithETag(eTag: hasCache ? box.get(assetEtagKey) : null);
 | 
			
		||||
      if (remote == null) {
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      box.put(assetEtagKey, remote.second);
 | 
			
		||||
      return remote.first.map(Asset.remote).toList(growable: false);
 | 
			
		||||
    } catch (e, stack) {
 | 
			
		||||
      log.severe('Error while getting remote assets', e, stack);
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
    box.put(assetEtagKey, remote.second);
 | 
			
		||||
    return remote.first.map(Asset.remote).toList(growable: false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// if [urgent] is `true`, do not block by waiting on the background service
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,9 @@ class ImmichSliverAppBar extends ConsumerWidget {
 | 
			
		||||
      snap: false,
 | 
			
		||||
      backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
 | 
			
		||||
      shape: const RoundedRectangleBorder(
 | 
			
		||||
        borderRadius: BorderRadius.all(Radius.circular(5)),
 | 
			
		||||
        borderRadius: BorderRadius.all(
 | 
			
		||||
          Radius.circular(5),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      leading: Builder(
 | 
			
		||||
        builder: (BuildContext context) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
import 'package:auto_route/auto_route.dart';
 | 
			
		||||
import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
@@ -20,6 +22,7 @@ import 'package:immich_mobile/shared/providers/asset.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/services/share.service.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
 | 
			
		||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
 | 
			
		||||
import 'package:openapi/api.dart';
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +40,8 @@ class HomePage extends HookConsumerWidget {
 | 
			
		||||
    final albums = ref.watch(albumProvider);
 | 
			
		||||
    final albumService = ref.watch(albumServiceProvider);
 | 
			
		||||
 | 
			
		||||
    final tipOneOpacity = useState(0.0);
 | 
			
		||||
 | 
			
		||||
    useEffect(
 | 
			
		||||
      () {
 | 
			
		||||
        ref.read(websocketProvider.notifier).connect();
 | 
			
		||||
@@ -146,6 +151,49 @@ class HomePage extends HookConsumerWidget {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      buildLoadingIndicator() {
 | 
			
		||||
        Timer(const Duration(seconds: 2), () {
 | 
			
		||||
          tipOneOpacity.value = 1;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return Center(
 | 
			
		||||
          child: Column(
 | 
			
		||||
            mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
            children: [
 | 
			
		||||
              const ImmichLoadingIndicator(),
 | 
			
		||||
              Padding(
 | 
			
		||||
                padding: const EdgeInsets.only(top: 16.0),
 | 
			
		||||
                child: Text(
 | 
			
		||||
                  'Building the timeline',
 | 
			
		||||
                  style: TextStyle(
 | 
			
		||||
                    fontWeight: FontWeight.w600,
 | 
			
		||||
                    fontSize: 16,
 | 
			
		||||
                    color: Theme.of(context).primaryColor,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
              AnimatedOpacity(
 | 
			
		||||
                duration: const Duration(milliseconds: 500),
 | 
			
		||||
                opacity: tipOneOpacity.value,
 | 
			
		||||
                child: const SizedBox(
 | 
			
		||||
                  width: 250,
 | 
			
		||||
                  child: Padding(
 | 
			
		||||
                    padding: EdgeInsets.only(top: 8.0),
 | 
			
		||||
                    child: Text(
 | 
			
		||||
                      'If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).',
 | 
			
		||||
                      textAlign: TextAlign.justify,
 | 
			
		||||
                      style: TextStyle(
 | 
			
		||||
                        fontSize: 12,
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              )
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return SafeArea(
 | 
			
		||||
        bottom: !multiselectEnabled.state,
 | 
			
		||||
        top: true,
 | 
			
		||||
@@ -164,15 +212,17 @@ class HomePage extends HookConsumerWidget {
 | 
			
		||||
                top: selectionEnabledHook.value ? 0 : 60,
 | 
			
		||||
                bottom: 0.0,
 | 
			
		||||
              ),
 | 
			
		||||
              child: ImmichAssetGrid(
 | 
			
		||||
                renderList: renderList,
 | 
			
		||||
                assetsPerRow:
 | 
			
		||||
                    appSettingService.getSetting(AppSettingsEnum.tilesPerRow),
 | 
			
		||||
                showStorageIndicator: appSettingService
 | 
			
		||||
                    .getSetting(AppSettingsEnum.storageIndicator),
 | 
			
		||||
                listener: selectionListener,
 | 
			
		||||
                selectionActive: selectionEnabledHook.value,
 | 
			
		||||
              ),
 | 
			
		||||
              child: ref.watch(assetProvider).isEmpty
 | 
			
		||||
                  ? buildLoadingIndicator()
 | 
			
		||||
                  : ImmichAssetGrid(
 | 
			
		||||
                      renderList: renderList,
 | 
			
		||||
                      assetsPerRow: appSettingService
 | 
			
		||||
                          .getSetting(AppSettingsEnum.tilesPerRow),
 | 
			
		||||
                      showStorageIndicator: appSettingService
 | 
			
		||||
                          .getSetting(AppSettingsEnum.storageIndicator),
 | 
			
		||||
                      listener: selectionListener,
 | 
			
		||||
                      selectionActive: selectionEnabledHook.value,
 | 
			
		||||
                    ),
 | 
			
		||||
            ),
 | 
			
		||||
            if (selectionEnabledHook.value)
 | 
			
		||||
              ControlBottomAppBar(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user