fix(editor): edgeless can't slider with finger (#15091)

fix bug edgeless can't slider with finger 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added mobile immersive edgeless mode with dynamic chrome auto-hide and
tap-gesture controls.
  * Added a mobile zoom ruler UI for edgeless.
* **Bug Fixes**
* Improved iOS rendering/zoom by applying low-zoom survival behavior,
gesture-aware refresh deferral, and effective-DPR canvas scaling.
* Fixed iOS webview zoom/bounce and process-termination reload behavior.
  * Improved placeholder styling with theme-aware colors.
* **Chores**
  * Updated local ignore rules and iOS app build/version configuration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: DarkSky <darksky2048@gmail.com>
This commit is contained in:
keepClamDown
2026-06-16 21:19:31 +08:00
committed by GitHub
parent c51bdb74de
commit a77d89bb1a
43 changed files with 4749 additions and 273 deletions

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
@@ -88,8 +88,6 @@
/* Begin PBXFileSystemSynchronizedRootGroup section */
9DAE85B72E7BAC3B00DB9F1D /* Plugins */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
path = Plugins;
sourceTree = "<group>";
};
@@ -309,9 +307,13 @@
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AFFiNE/Pods-AFFiNE-frameworks.sh\"\n";
@@ -504,7 +506,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 17;
DEVELOPMENT_TEAM = 73YMMDVT2M;
INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
@@ -517,7 +519,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 0.26.3;
MARKETING_VERSION = 0.26.5;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = app.affine.pro;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -540,7 +542,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 17;
DEVELOPMENT_TEAM = 73YMMDVT2M;
INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity";
@@ -553,7 +555,7 @@
"$(inherited)",
"$(PROJECT_DIR)",
);
MARKETING_VERSION = 0.26.3;
MARKETING_VERSION = 0.26.5;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = app.affine.pro;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -1,31 +1,55 @@
import Capacitor
import Intelligents
import UIKit
import WebKit
class AFFiNEViewController: CAPBridgeViewController {
class AFFiNEViewController: CAPBridgeViewController, UIScrollViewDelegate {
var intelligentsButton: IntelligentsButton?
override func viewDidLoad() {
super.viewDidLoad()
webView?.allowsBackForwardNavigationGestures = true
webView?.allowsBackForwardNavigationGestures = false
navigationController?.navigationBar.isHidden = true
extendedLayoutIncludesOpaqueBars = false
edgesForExtendedLayout = []
// Disable WKWebView scrollView zoom/bounce to prevent conflict with edgeless canvas gestures
webView?.scrollView.minimumZoomScale = 1.0
webView?.scrollView.maximumZoomScale = 1.0
webView?.scrollView.bouncesZoom = false
webView?.scrollView.bounces = false
webView?.scrollView.pinchGestureRecognizer?.isEnabled = false
webView?.scrollView.delegate = self
// Inject viewport meta to prevent WKWebView smart zoom
let viewportScript = """
(function() {
function setViewport() {
var meta = document.querySelector('meta[name="viewport"]');
if (!meta) {
meta = document.createElement('meta');
meta.name = 'viewport';
(document.head || document.documentElement).appendChild(meta);
}
meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover';
}
if (document.head) {
setViewport();
} else {
document.addEventListener('DOMContentLoaded', setViewport);
}
})();
"""
webView?.configuration.userContentController.addUserScript(
WKUserScript(source: viewportScript, injectionTime: .atDocumentStart, forMainFrameOnly: true)
)
let intelligentsButton = installIntelligentsButton()
intelligentsButton.delegate = self
self.intelligentsButton = intelligentsButton
dismissIntelligentsButton()
}
override func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
let configuration = super.webViewConfiguration(for: instanceConfiguration)
return configuration
}
override func webView(with frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView {
super.webView(with: frame, configuration: configuration)
}
override func capacitorDidLoad() {
let plugins: [CAPPlugin] = [
AuthPlugin(),
@@ -56,7 +80,7 @@ class AFFiNEViewController: CAPBridgeViewController {
private func checkEligibilityOfIntelligent() {
guard !isCheckingIntelligentEligibility else { return }
assert(intelligentsButton != nil)
guard intelligentsButton?.isHidden ?? false else { return } // already eligible
guard intelligentsButton?.isHidden ?? false else { return }
isCheckingIntelligentEligibility = true
IntelligentContext.shared.webView = webView
IntelligentContext.shared.preparePresent { [self] result in
@@ -75,4 +99,31 @@ class AFFiNEViewController: CAPBridgeViewController {
super.viewDidDisappear(animated)
intelligentsButtonTimer?.invalidate()
}
// MARK: - UIScrollViewDelegate
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return nil
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
scrollView.zoomScale = 1.0
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset != .zero {
scrollView.contentOffset = .zero
}
}
// MARK: - Web Content Process Crash Recovery
// NOTE: Capacitor's CAPBridgeViewController owns the WKWebView
// navigationDelegate (it assigns its own WebViewDelegationHandler), so this
// override is NOT called in practice — Capacitor's handler logs
// "⚡️ WebView process terminated" and reloads instead. Kept as defensive
// fallback, matching the prior baseline behavior.
func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
webView.reload()
}
}

View File

@@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>10</string>
<string>17</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
@@ -42,7 +42,7 @@
<key>NSPhotoLibraryUsageDescription</key>
<string>AFFiNE requires access to select photos from your photo library and insert them into your documents</string>
<key>NSUserTrackingUsageDescription</key>
<string>Rest assured, enabling this permission won't access your private info on other sites. It's only used to identify your device and improve security and product experience.</string>
<string>Rest assured, enabling this permission won&apos;t access your private info on other sites. It&apos;s only used to identify your device and improve security and product experience.</string>
<key>UILaunchScreen</key>
<dict>
<key>UIImageName</key>
@@ -69,10 +69,10 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
</dict>
</plist>

View File

@@ -171,16 +171,16 @@ private extension ChatManager {
let uploadableAttachments: [CopilotAttachmentUpload] = [
editorData.fileAttachments.map { file -> CopilotAttachmentUpload in
.init(
originalName: file.name,
data: file.data ?? .init(),
mimeType: mimeType(text: file.name),
data: file.data ?? .init()
originalName: file.name
)
},
editorData.imageAttachments.map { image -> CopilotAttachmentUpload in
.init(
originalName: "image.jpg",
data: image.imageData,
mimeType: mimeType(pathExtension: "jpg"),
data: image.imageData
originalName: "image.jpg"
)
},
].flatMap(\.self)

View File

@@ -45,13 +45,13 @@ EXTERNAL SOURCES:
:path: "../../../../../node_modules/capacitor-plugin-app-tracking-transparency"
SPEC CHECKSUMS:
Capacitor: a5bf59e09f9dd82694fdcca4d107b4d215ac470f
CapacitorApp: 3ddbd30ac18c321531c3da5e707b60873d89dd60
CapacitorBrowser: 66aa8ff09cdca2a327ce464b113b470e6f667753
Capacitor: 12914e6f1b7835e161a74ebd19cb361efa37a7dd
CapacitorApp: 63b237168fc869e758481dba283315a85743ee78
CapacitorBrowser: b98aa3db018a2ce4c68242d27e596c344f3b81b3
CapacitorCordova: 31bbe4466000c6b86d9b7f1181ee286cff0205aa
CapacitorHaptics: d17da7dd984cae34111b3f097ccd3e21f9feec62
CapacitorKeyboard: 45cae3956a6f4fb1753f9a4df3e884aeaed8fe82
CapacitorPluginAppTrackingTransparency: 2a2792623a5a72795f2e8f9ab3f1147573732fd8
CapacitorHaptics: ce15be8f287fa2c61c7d2d9e958885b90cf0bebc
CapacitorKeyboard: 5660c760113bfa48962817a785879373cf5339c3
CapacitorPluginAppTrackingTransparency: 92ae9c1cfb5cf477753db9269689332a686f675a
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483
PODFILE CHECKSUM: 2c1e4be82121f2d9724ecf7e31dd14e165aeb082