enhance: iOS dynamic type

This commit is contained in:
Tienson Qin
2025-12-04 21:27:38 +08:00
parent 0327e0f4a7
commit 7e8ed5333a
8 changed files with 132 additions and 18 deletions

View File

@@ -12,6 +12,38 @@ import UIKit
@objc(Utils)
public class Utils: CAPPlugin {
private var currentInterfaceStyle: UIUserInterfaceStyle = .unspecified
private var contentSizeObserver: NSObjectProtocol?
public override func load() {
super.load()
contentSizeObserver = NotificationCenter.default.addObserver(
forName: UIContentSizeCategory.didChangeNotification,
object: nil,
queue: .main
) { [weak self] _ in
guard let self = self else { return }
self.notifyListeners("contentSizeCategoryChanged", data: self.contentSizePayload())
}
}
deinit {
if let observer = contentSizeObserver {
NotificationCenter.default.removeObserver(observer)
}
}
private func contentSizePayload() -> [String: Any] {
let category = UIApplication.shared.preferredContentSizeCategory
let base: CGFloat = 17.0
let scaled = UIFontMetrics(forTextStyle: .body).scaledValue(for: base)
let scale = scaled / base
return [
"category": category.rawValue,
"scale": scale
]
}
@objc func isZoomed(_ call: CAPPluginCall) {
@@ -22,6 +54,10 @@ public class Utils: CAPPlugin {
call.resolve(["isZoomed": isZoomed])
}
@objc func getContentSize(_ call: CAPPluginCall) {
call.resolve(contentSizePayload())
}
@objc func getDocumentRoot(_ call: CAPPluginCall) {
let doc = FileManager.default.urls(
for: .documentDirectory,

View File

@@ -58,10 +58,13 @@
@apply inline;
.icon-emoji-wrap {
@apply relative top-[2px] pl-[1px];
position: relative;
top: 0.08em;
padding-left: 1px;
&.as-emoji {
@apply top-0 pr-[1px];
top: 0.02em;
padding-right: 1px;
}
}
@@ -69,6 +72,11 @@
@apply inline-flex items-center pr-0.5;
}
.icon-emoji-wrap em-emoji,
.icon-cp-container .ui__icon {
vertical-align: middle;
}
.block-title-wrap.as-heading {
@apply inline text-[length:inherit];
}
@@ -208,7 +216,8 @@
&.bullet-closed {
.ls-icon-color-wrap em-emoji {
@apply relative -top-[1px];
position: relative;
top: -0.08em;
}
}
}
@@ -747,23 +756,32 @@
}
.bullet-container {
display: flex;
height: 16px;
width: 16px;
display: inline-flex;
height: 1em;
width: 1em;
min-width: 1em;
flex-shrink: 0;
align-self: center;
border-radius: 50%;
justify-content: center;
align-items: center;
line-height: 1;
vertical-align: middle;
.bullet-heading {
background-color: var(--ls-block-bullet-color, #8fbc8f);
}
&.as-order-list {
@apply w-[22px] whitespace-nowrap justify-center pl-[3px];
width: 1.4em;
min-width: 1.4em;
@apply whitespace-nowrap justify-center pl-[3px];
}
.bullet {
@apply rounded-full w-[6px] h-[6px] text-[15px] opacity-80;
@apply rounded-full opacity-80;
width: 0.4em;
height: 0.4em;
> * {
@apply cursor-pointer;
@@ -792,6 +810,9 @@
}
.bullet-link-wrap {
@apply inline-flex items-center;
line-height: 1;
vertical-align: middle;
color: var(--ls-primary-text-color);
.ui__icon {

View File

@@ -36,6 +36,31 @@
(set! native-selection-action-bar (registerPlugin "NativeSelectionActionBarPlugin"))
(set! ios-utils (registerPlugin "Utils")))
(defonce ios-content-size-listener nil)
(defn- set-ios-font-scale!
[scale]
(let [^js style (.-style js/document.documentElement)
scale (or scale 1)]
(.setProperty style "--ls-mobile-font-scale" (str scale))))
(defn sync-ios-content-size!
"Fetch the current iOS Dynamic Type scale and sync it to CSS variables.
Also attaches a listener to keep it in sync when the user changes the setting."
[]
(when (native-ios?)
(let [apply-scale! (fn [payload]
(let [payload (js->clj payload :keywordize-keys true)]
(set-ios-font-scale! (:scale payload))))]
(p/let [payload (p/chain (.getContentSize ^js ios-utils)
#(js->clj % :keywordize-keys true))]
(set-ios-font-scale! (:scale payload)))
(when (nil? ios-content-size-listener)
(set! ios-content-size-listener
(.addListener ^js ios-utils "contentSizeCategoryChanged"
(fn [^js payload]
(apply-scale! payload))))))))
(defn hide-splash []
(.hide SplashScreen))

View File

@@ -39,13 +39,14 @@
`f` receives the tab id string.
Returns the Capacitor listener handle; call `(.remove handle)` to unsubscribe."
[f]
(.addListener
liquid-tabs
"tabSelected"
(fn [data]
(when (and (util/capacitor?) liquid-tabs)
(.addListener
liquid-tabs
"tabSelected"
(fn [data]
;; data is like { id: string }
(when-let [id (.-id data)]
(f id)))))
(when-let [id (.-id data)]
(f id))))))
(defn add-search-listener!
"Listen to native search query changes from the SwiftUI search tab.

View File

@@ -28,7 +28,7 @@
(rum/defc journals
[]
(ui-component/classic-app-container-wrap
[:div.pt-3
[:div.pt-6
(journal/all-journals)]))
(rum/defc home-inner < rum/static

View File

@@ -4,9 +4,11 @@
}
:root {
--ls-page-title-size: 26px;
--ls-mobile-font-scale: 1;
--ls-page-title-size: calc(24px * var(--ls-mobile-font-scale, 1));
--safe-area-inset-top: 40px;
--safe-area-inset-bottom: 16px;
--ls-mobile-font-size: 16px;
}
html.is-native-ios {
@@ -14,6 +16,29 @@ html.is-native-ios {
--safe-area-inset-bottom: 24px;
}
html.is-native-ios,
html.is-ios {
font-size: calc(var(--ls-mobile-font-size) * var(--ls-mobile-font-scale, 1));
}
html.is-native-ios body,
html.is-native-ios textarea,
html.is-native-ios input,
html.is-native-ios select,
html.is-native-ios .block-content,
html.is-ios body,
html.is-ios textarea,
html.is-ios input,
html.is-ios select,
html.is-ios .block-content {
font-size: inherit;
}
html.is-native-ios .block-content,
html.is-ios .block-content {
line-height: 1.6;
}
html.has-mobile-keyboard {
body {
@apply overflow-hidden
@@ -331,3 +356,8 @@ div[data-radix-menu-content] {
position:fixed;
top:-9999px;
}
.bullet {
width: 0.45em;
height: 0.45em;
}

View File

@@ -25,7 +25,8 @@
(defn- ios-init!
"Initialize iOS-specified event listeners"
[]
(mobile-util/check-ios-zoomed-display))
(mobile-util/check-ios-zoomed-display)
(mobile-util/sync-ios-content-size!))
(defn- android-init!
"Initialize Android-specified event listeners"

View File

@@ -10,7 +10,7 @@
["/page/:name"
{:name :page
:view (fn [route-match]
[:div.ls-mobile-page.mt-6
[:div.ls-mobile-page.pt-10
(page/page-cp (assoc route-match :mobile-page? true))])}]
["/import"
{:name :import