feat: mobile editing (#25397)

* feat: mobile editing

fix: openapi patch

this sucks :pepehands:

chore: migrate some changes from the filtering PR

chore: color tweak

fix: hide edit button on server versions

chore: translation

* chore: code review changes

chore: code review

* sealed class

* const constant

* enum

* concurrent queries

* chore: major cleanup to use riverpod provider

* fix: aspect ratio selection

* chore: typesafe websocket event parsing

* fix: wrong disable state for save button

* chore: remove isCancelled shim

* chore: cleanup postframe callback usage

* chore: clean import

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
This commit is contained in:
Brandon Wees
2026-04-15 09:26:40 -05:00
committed by GitHub
parent 8454cb2631
commit 6dd6053222
30 changed files with 1317 additions and 646 deletions
@@ -3,16 +3,18 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/add_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/edit_image_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/share_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/add_action_button.widget.dart';
import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart';
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
import 'package:immich_mobile/providers/routes.provider.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/utils/semver.dart';
import 'package:immich_mobile/widgets/asset_viewer/video_controls.dart';
class ViewerBottomBar extends ConsumerWidget {
@@ -30,6 +32,7 @@ class ViewerBottomBar extends ConsumerWidget {
final isOwner = asset is RemoteAsset && asset.ownerId == user?.id;
final showingDetails = ref.watch(assetViewerProvider.select((s) => s.showingDetails));
final isInLockedView = ref.watch(inLockedViewProvider);
final serverInfo = ref.watch(serverInfoProvider);
final originalTheme = context.themeData;
@@ -38,7 +41,9 @@ class ViewerBottomBar extends ConsumerWidget {
if (!isInLockedView) ...[
if (asset.isLocalOnly) const UploadActionButton(source: ActionSource.viewer),
if (asset.type == AssetType.image) const EditImageActionButton(),
// edit sync was added in 2.6.0
if (asset.isEditable && serverInfo.serverVersion >= const SemVer(major: 2, minor: 6, patch: 0))
const EditImageActionButton(),
if (asset.hasRemote) AddActionButton(originalTheme: originalTheme),
if (isOwner) ...[