Merge branch 'master' into master-android

This commit is contained in:
Evgeny Poberezkin
2026-06-23 15:21:42 +01:00
8 changed files with 127 additions and 29 deletions
+18 -18
View File
@@ -188,8 +188,8 @@
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw.a */; };
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx-ghc9.6.3.a */; };
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx.a */; };
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
@@ -573,8 +573,8 @@
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw.a"; sourceTree = "<group>"; };
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx-ghc9.6.3.a"; sourceTree = "<group>"; };
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx.a"; sourceTree = "<group>"; };
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
@@ -745,8 +745,8 @@
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw.a in Frameworks */,
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx-ghc9.6.3.a in Frameworks */,
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx.a in Frameworks */,
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -832,8 +832,8 @@
64C829992D54AEEE006B9E89 /* libffi.a */,
64C829982D54AEED006B9E89 /* libgmp.a */,
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.4-8XuHcEDddcyDWUwNmEyAgw.a */,
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx-ghc9.6.3.a */,
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-7.0.0.5-3gtbZllPEb75FgChAFCqhx.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -2091,7 +2091,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -2141,7 +2141,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -2183,7 +2183,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@@ -2203,7 +2203,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@@ -2228,7 +2228,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -2265,7 +2265,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -2302,7 +2302,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2353,7 +2353,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2407,7 +2407,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2441,7 +2441,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 336;
CURRENT_PROJECT_VERSION = 338;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -176,7 +176,7 @@ fun CIImageView(
.then(
if (!smallView) {
val w = if (previewBitmap.width * 0.97 <= previewBitmap.height) imageViewFullWidth() * 0.75f else DEFAULT_MAX_IMAGE_WIDTH
Modifier.width(w).aspectRatio((previewBitmap.width.toFloat() / previewBitmap.height.toFloat()).coerceAtLeast(1f / 2.33f))
Modifier.width(w).aspectRatio((previewBitmap.width.toFloat() / previewBitmap.height.toFloat()).coerceIn(1f / 2.33f, 2.33f))
} else Modifier
)
.desktopModifyBlurredState(!smallView, blurred, showMenu),
+4 -4
View File
@@ -24,13 +24,13 @@ android.nonTransitiveRClass=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11
android.version_name=7.0-beta.0
android.version_code=356
android.version_name=7.0-beta.1
android.version_code=360
android.bundle=false
desktop.version_name=7.0-beta.0
desktop.version_code=147
desktop.version_name=7.0-beta.1
desktop.version_code=149
kotlin.version=2.1.20
gradle.plugin.version=8.7.0
@@ -1,6 +1,6 @@
{
"name": "@simplex-chat/types",
"version": "0.10.0",
"version": "0.10.1",
"description": "TypeScript types for SimpleX Chat bot libraries",
"main": "dist/index.js",
"types": "dist/index.d.ts",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "simplex-chat",
"version": "7.0.0-beta.0",
"version": "7.0.0-beta.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
@@ -24,7 +24,7 @@
"docs": "typedoc"
},
"dependencies": {
"@simplex-chat/types": "^0.10.0",
"@simplex-chat/types": "^0.10.1",
"extract-zip": "^2.0.1",
"fast-deep-equal": "^3.1.3",
"node-addon-api": "^8.5.0"
@@ -4,7 +4,7 @@ const path = require('path');
const extract = require('extract-zip');
const GITHUB_REPO = 'simplex-chat/simplex-chat-libs';
const RELEASE_TAG = 'v7.0.0-beta.0';
const RELEASE_TAG = 'v7.0.0-beta.1';
const BACKEND = (process.env.SIMPLEX_BACKEND || process.env.npm_config_simplex_backend || 'sqlite').toLowerCase();
if (BACKEND !== 'sqlite' && BACKEND !== 'postgres') {
@@ -5,5 +5,5 @@ Bump both together for normal releases. For wrapper-only fixes use a PEP 440
post-release: __version__ = "6.5.2.post1", LIBS_VERSION unchanged.
"""
__version__ = "7.0.0b0" # PEP 440 — read by hatchling for wheel metadata
LIBS_VERSION = "7.0.0-beta.0" # simplex-chat-libs release tag (no 'v' prefix)
__version__ = "7.0.0b1" # PEP 440 — read by hatchling for wheel metadata
LIBS_VERSION = "7.0.0-beta.1" # simplex-chat-libs release tag (no 'v' prefix)
+98
View File
@@ -0,0 +1,98 @@
# Fix crash on opening a chat containing an extremely wide image
## Problem
Sending/receiving an image with an extreme aspect ratio (reproduced with a
**4000×1** image) makes the chat **unopenable**: every render of the chat throws
```
java.lang.IllegalArgumentException: Can't represent a width of 4660000 and height of 1165 in Constraints
at androidx.compose.foundation.layout.AspectRatioNode.measure(AspectRatio.kt:117)
...
at chat.simplex.common.views.chat.item.FramedItemViewKt$PriorityLayout$1$1.measure(FramedItemView.kt:482)
```
Because the exception fires during measurement on every frame, the chat cannot
be opened again without clearing it. Affects **Android and desktop** (the Compose
`apps/multiplatform` UI). iOS is unaffected (see below).
## Cause
The framed image preview Box sizes itself with `Modifier.aspectRatio(...)` driven
by the image's real proportions
(`apps/multiplatform/.../chat/item/CIImageView.kt`):
```kotlin
// before
Modifier.width(w).aspectRatio((previewBitmap.width.toFloat() / previewBitmap.height.toFloat()).coerceAtLeast(1f / 2.33f))
```
The ratio was clamped only on the **low** side (`coerceAtLeast(1f / 2.33f)`,
added in #6959 to stop very *tall* previews overflowing the caption). The **high**
side was left unbounded. For a 4000×1 image the ratio is `4000`.
During Compose's intrinsic-measurement pass, `AspectRatioNode` derives a fixed
`width = height × ratio`. Compose `Constraints` pack each dimension into at most
18 bits, so the maximum representable value is **262142 px**. With the observed
intrinsic height of 1165 px, `1165 × 4000 = 4,660,000` — ~18× over the limit —
and `Constraints.fixed(...)` throws. Any ratio above roughly `262142 / height`
(≈ 225 at this height) overflows; tall images never hit this because the existing
lower bound already caps their ratio.
The bitmap decoders (`Images.android.kt`, `Images.desktop.kt`) only made this
reachable: they reject pathologically *tall* images
(`outHeight > outWidth * 256`) and any dimension `> 4320`, but have **no
symmetric wide guard**, so a 4000×1 image (width 4000 ≤ 4320, not tall) decodes
and reaches the unbounded `aspectRatio`.
## Fix
Add the symmetric **upper** bound to the clamp, mirroring the existing lower
bound and the tall-image height cap already enforced in `PriorityLayout`
(`FramedItemView.kt`: `maxImageHeight = constraints.maxWidth * 2.33f`):
```kotlin
// after
Modifier.width(w).aspectRatio((previewBitmap.width.toFloat() / previewBitmap.height.toFloat()).coerceIn(1f / 2.33f, 2.33f))
```
This is the minimal one-line change. With the cap, the box width is pinned
(`≤ DEFAULT_MAX_IMAGE_WIDTH = 500.dp`) and the height-driven width becomes
`height × 2.33 ≈ 2714 px` — three orders of magnitude inside the 262142 limit —
so the measurement can never overflow at any screen density. `2.33` is the
project's single "most-extreme allowed image proportion" constant: an image is
now clamped to at most 2.33:1 in **either** direction, the same rule already
applied to tall images.
## Why 2.33 (and not a larger cap)
`2.33` is provably safe by construction because it ties the wide bound to the
same proportion the layout already guarantees for height, independent of density.
A larger cap (e.g. 50200) would preserve the natural shape of genuine panoramas
but relies on an assumption about the maximum measured height and loses the
symmetry with the tall-image rule. The trade-off accepted here is that wide
images between 2.33:1 and the crash threshold now display at 2.33:1 (the very
wide remainder shown as a thin strip with `ContentScale.FillWidth`) rather than
at their natural ratio — a cosmetic change in exchange for a guaranteed-safe,
consistent fix.
## Scope / non-goals
- Only the `!smallView` framed Box uses a media-derived `aspectRatio`; it is now
clamped. The chat-list `smallView` preview is locked to a fixed `36.sp` square,
and all other image/video/link paths size with `.width(...)` + `ContentScale`
(no `aspectRatio`), so none of them can hit this overflow.
- Two follow-ups were identified but intentionally left out to keep the diff
minimal: (1) a **symmetric wide guard** in the bitmap decoders
(`outWidth > outHeight * 256`) for defense-in-depth across all consumers, and
(2) extracting the duplicated `2.33` literal (now in `CIImageView.kt` and
`FramedItemView.kt`) into a shared `MAX_IMAGE_ASPECT_RATIO` constant.
## iOS
iOS is **not** affected by the crash. It carries the same lopsided logic —
`heightRatio` (`apps/ios/SimpleXChat/ImageUtils.swift`) caps only the tall side
(`min(size.height / size.width, 2.33)`) — but SwiftUI lays out with `CGFloat`
frames and has no `Constraints` packing limit, so a 4000×1 image yields a valid
(sub-pixel height) frame instead of throwing. No iOS change is required for the
crash; bounding the wide side there would only be a cosmetic parity tweak.