Compare commits

..

1 Commits

Author SHA1 Message Date
Santo Shakil dfea8c21a6 fix(mobile): play videos from search results and folder view 2026-07-07 15:21:04 +06:00
16 changed files with 690 additions and 573 deletions
+4 -4
View File
@@ -103,14 +103,14 @@ jobs:
working-directory: ./mobile
run: printf "%s" $KEY_JKS | base64 -d > android/key.jks
- uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
- uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
with:
distribution: 'zulu'
java-version: '17'
- name: Restore Gradle Cache
id: cache-gradle-restore
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
~/.gradle/caches
@@ -181,7 +181,7 @@ jobs:
- name: Save Gradle Cache
id: cache-gradle-save
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
if: github.ref == 'refs/heads/main'
with:
path: |
@@ -237,7 +237,7 @@ jobs:
run: flutter build ios --config-only --no-codesign
- name: Setup Ruby
uses: ruby/setup-ruby@0dafeac902942906541bc140009cdbf32665b601 # v1.315.0
uses: ruby/setup-ruby@89f90524b88a01fe6e0b732220432cc6142926af # v1.313.0
with:
ruby-version: '3.3'
bundler-cache: true
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
persist-credentials: false
- name: Check for breaking API changes
uses: oasdiff/oasdiff-action/breaking@ae5ef6402ebe218ac6e872c59d0fa4557694e75c # v0.1.4
uses: oasdiff/oasdiff-action/breaking@e24529087d93f837b28b50bb66ba9016380a7fcc # v0.1.2
with:
base: https://raw.githubusercontent.com/${{ github.repository }}/main/open-api/immich-openapi-specs.json
revision: open-api/immich-openapi-specs.json
+1 -1
View File
@@ -75,7 +75,7 @@ jobs:
token: ${{ steps.token.outputs.token }}
- name: Set up QEMU
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
+1 -1
View File
@@ -149,7 +149,7 @@ jobs:
github-token: ${{ steps.generate-token.outputs.token }}
- name: Create draft release
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
draft: true
prerelease: ${{ needs.bump_version.outputs.rc }}
+2 -2
View File
@@ -716,7 +716,7 @@ jobs:
github_token: ${{ steps.token.outputs.token }}
- name: Install server dependencies
run: pnpm --filter immich install --frozen-lockfile
run: SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter immich install --frozen-lockfile
- name: Run API generation
run: mise //:open-api
working-directory: open-api
@@ -774,7 +774,7 @@ jobs:
github_token: ${{ steps.token.outputs.token }}
- name: Install server dependencies
run: pnpm install --frozen-lockfile
run: SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm install --frozen-lockfile
- name: Build plugins
run: mise //:plugins
+1 -1
View File
@@ -48,7 +48,7 @@
"pngjs": "^7.0.0",
"prettier": "^3.7.4",
"prettier-plugin-organize-imports": "^4.0.0",
"sharp": "^0.35.2",
"sharp": "^0.34.5",
"socket.io-client": "^4.7.4",
"supertest": "^7.0.0",
"typescript": "^6.0.0",
+1
View File
@@ -65,6 +65,7 @@ dir = "open-api"
run = "bash ./bin/generate-dart-sdk.sh"
[tasks.open-api]
env = { SHARP_IGNORE_GLOBAL_LIBVIPS = true }
run = [
{ task = "//:plugins" },
{ task = "//server:install" },
@@ -79,6 +79,17 @@ sealed class BaseAsset {
bool get isLocalOnly => storage == AssetState.local;
bool get isRemoteOnly => storage == AssetState.remote;
// Same asset even if localId is known on one side but not the other (heroTag isn't stable then)
bool isSameAsset(BaseAsset other) {
if (remoteId != null && other.remoteId != null) {
return remoteId == other.remoteId;
}
if (localId != null && other.localId != null) {
return localId == other.localId;
}
return checksum != null && checksum == other.checksum;
}
bool get isEditable => false;
// Overridden in subclasses
@@ -395,7 +395,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
@override
Widget build(BuildContext context) {
final currentHeroTag = ref.watch(assetViewerProvider.select((s) => s.currentAsset?.heroTag));
final currentAsset = ref.watch(assetViewerProvider.select((s) => s.currentAsset));
_showingDetails = ref.watch(assetViewerProvider.select((s) => s.showingDetails));
final stackIndex = ref.watch(assetViewerProvider.select((s) => s.stackIndex));
final isPlayingMotionVideo = ref.watch(isPlayingMotionVideoProvider);
@@ -414,7 +414,7 @@ class _AssetPageState extends ConsumerState<AssetPage> {
displayAsset = stackChildren.elementAt(stackIndex);
}
final isCurrent = currentHeroTag == displayAsset.heroTag;
final isCurrent = currentAsset != null && currentAsset.isSameAsset(displayAsset);
final viewportWidth = MediaQuery.widthOf(context);
final viewportHeight = MediaQuery.heightOf(context);
@@ -0,0 +1,46 @@
import 'package:flutter_test/flutter_test.dart';
import '../../unit/factories/local_asset_factory.dart';
import '../../unit/factories/remote_asset_factory.dart';
void main() {
group('BaseAsset.isSameAsset', () {
test('search/folder copy (localId null) matches the merged DB copy (localId set)', () {
// #29472: search and folder assets arrive with localId null, then the viewer
// watches the DB copy which fills localId. heroTag embeds localId, so it
// diverges for the same asset and isCurrent used to go false.
final searchCopy = RemoteAssetFactory.create(id: 'asset-1');
final mergedCopy = searchCopy.copyWith(localId: 'local-1');
expect(searchCopy.localId, isNull);
expect(mergedCopy.localId, 'local-1');
expect(searchCopy.heroTag, isNot(mergedCopy.heroTag));
expect(searchCopy.isSameAsset(mergedCopy), isTrue);
expect(mergedCopy.isSameAsset(searchCopy), isTrue);
});
test('different remote assets are not the same', () {
final a = RemoteAssetFactory.create(id: 'asset-1');
final b = RemoteAssetFactory.create(id: 'asset-2');
expect(a.isSameAsset(b), isFalse);
});
test('same checksum but different remote ids are not the same (duplicate files)', () {
final a = RemoteAssetFactory.create(id: 'asset-1');
final b = RemoteAssetFactory.create(id: 'asset-2').copyWith(checksum: a.checksum);
expect(a.checksum, b.checksum);
expect(a.isSameAsset(b), isFalse);
});
test('falls back to checksum when only one side has an id (local-only vs remote-only)', () {
final remoteOnly = RemoteAssetFactory.create(id: 'asset-1');
final localOnly = LocalAssetFactory.create(id: 'local-1').copyWith(checksum: remoteOnly.checksum);
expect(remoteOnly.isSameAsset(localOnly), isTrue);
expect(localOnly.isSameAsset(remoteOnly), isTrue);
});
});
}
+609 -550
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -29,7 +29,7 @@ allowBuilds:
postman-code-generators: false
overrides:
canvas: 3.2.3
sharp: ^0.35.2
sharp: ^0.34.5
packageExtensions:
nestjs-kysely:
dependencies:
+5 -6
View File
@@ -1,4 +1,4 @@
FROM ghcr.io/immich-app/base-server-dev:202607061334@sha256:c83ef9c6d7f5e7f6a276fe96647484d46b7bf6cacc1e35b823dd1d7a1aeda3b8 AS builder
FROM ghcr.io/immich-app/base-server-dev:202606161235@sha256:9f88b07acc8b7bf37a1dd3d5a19193f664443eaaab4e08e9f9341414c5e4b23f AS builder
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \
CI=1 \
COREPACK_HOME=/tmp \
@@ -20,9 +20,8 @@ RUN --mount=type=cache,id=pnpm-server,target=/buildcache/pnpm-store \
--mount=type=bind,source=.pnpmfile.cjs,target=.pnpmfile.cjs \
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
--mount=type=bind,source=pnpm-workspace.yaml,target=pnpm-workspace.yaml \
pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter immich build && \
pnpm --filter immich --prod deploy /output/server-pruned && \
SHARP_FORCE_GLOBAL_LIBVIPS=true pnpm --dir /output/server-pruned/node_modules/sharp exec npm run build
SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter immich build && \
SHARP_FORCE_GLOBAL_LIBVIPS=true pnpm --filter immich --prod --no-optional deploy /output/server-pruned
FROM builder AS web
@@ -38,7 +37,7 @@ RUN --mount=type=cache,id=pnpm-web,target=/buildcache/pnpm-store \
--mount=type=bind,source=.pnpmfile.cjs,target=.pnpmfile.cjs \
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
--mount=type=bind,source=pnpm-workspace.yaml,target=pnpm-workspace.yaml \
pnpm --filter @immich/sdk --filter immich-web install --frozen-lockfile --force && \
SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter @immich/sdk --filter immich-web install --frozen-lockfile --force && \
pnpm --filter @immich/sdk --filter immich-web build
FROM builder AS cli
@@ -81,7 +80,7 @@ RUN --mount=type=cache,id=pnpm-packages,target=/buildcache/pnpm-store \
--mount=type=cache,id=mise-tools-${TARGETPLATFORM},target=/buildcache/mise \
mise //:plugins
FROM ghcr.io/immich-app/base-server-prod:202607061334@sha256:c07ef6510ff2ccb6ead28434ade7c7a0c08aef33d7d3466b14beccdd431e86f7
FROM ghcr.io/immich-app/base-server-prod:202606161235@sha256:c6d59e3923f548d29a212b4dc51b6281a722cfa1da7972a009c0f3830f5762d6
WORKDIR /usr/src/app
ENV NODE_ENV=production \
+1 -1
View File
@@ -1,5 +1,5 @@
# dev build
FROM ghcr.io/immich-app/base-server-dev:202607061334@sha256:c83ef9c6d7f5e7f6a276fe96647484d46b7bf6cacc1e35b823dd1d7a1aeda3b8 AS dev
FROM ghcr.io/immich-app/base-server-dev:202606161235@sha256:9f88b07acc8b7bf37a1dd3d5a19193f664443eaaab4e08e9f9341414c5e4b23f AS dev
COPY --from=ghcr.io/jdx/mise:2026.6.14@sha256:b8f8c20fc3308f8b1d00ccca2bc968e4e208af1c5c1069e1ad9753baa099acff /usr/local/bin/mise /usr/local/bin/mise
+2 -2
View File
@@ -107,7 +107,7 @@
"rxjs": "^7.8.1",
"sanitize-filename": "^1.6.3",
"semver": "^7.8.1",
"sharp": "^0.35.2",
"sharp": "^0.34.5",
"sirv": "^3.0.0",
"socket.io": "^4.8.1",
"tailwindcss-preset-email": "^1.4.0",
@@ -168,6 +168,6 @@
"vitest": "^3.0.0"
},
"overrides": {
"sharp": "^0.35.2"
"sharp": "^0.34.5"
}
}
@@ -63,5 +63,6 @@
{required}
{value}
oninput={handleInput}
{disabled}></textarea>
{disabled}
></textarea>
</div>