@momo-kits/native-kits 0.162.2-test.5-debug → 0.162.2-test.6-debug

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,7 +40,7 @@ kotlin {
40
40
  }
41
41
 
42
42
  cocoapods {
43
- version = "0.162.2-test.5-debug"
43
+ version = "0.162.2-test.6-debug"
44
44
  summary = "IOS Shared module"
45
45
  homepage = "https://momo.vn"
46
46
  ios.deploymentTarget = "15.0"
@@ -112,5 +112,5 @@ data class FontScaleConfig(
112
112
  val userScaleRate: Float? = null,
113
113
  )
114
114
 
115
- // Single source of truth: chứa cả flag OS lẫn rate user tự chỉnh.
115
+ // Single source of truth: holds both the OS flag and the user-adjusted rate.
116
116
  val LocalFontScaleConfig = staticCompositionLocalOf { FontScaleConfig() }
@@ -38,10 +38,10 @@ const val MAX_DEVICE_SCALE = 5
38
38
 
39
39
  @Composable
40
40
  fun scaleSize(size: Float, userScaleRate: Float? = null): Float {
41
- // single source of truth: useOSFontScale + userScaleRate cùng lấy từ LocalFontScaleConfig
41
+ // single source of truth: useOSFontScale + userScaleRate both read from LocalFontScaleConfig
42
42
  val fontScaleConfig = LocalFontScaleConfig.current
43
43
  val useOSFontScale = fontScaleConfig.useOSFontScale
44
- // param userScaleRate override config; không -> config.userScaleRate -> 1f (không scale)
44
+ // param userScaleRate overrides config; if absent -> config.userScaleRate -> 1f (no scaling)
45
45
  val customRate = userScaleRate ?: fontScaleConfig.userScaleRate ?: 1f
46
46
 
47
47
  val deviceWidth = getScreenDimensions().width
@@ -58,8 +58,8 @@ fun scaleSize(size: Float, userScaleRate: Float? = null): Float {
58
58
  min(deviceScale * fontSizeScaleDevice, fontSizeScaleDevice + MAX_DEVICE_SCALE)
59
59
  }
60
60
 
61
- // useOSFontScale bật -> lấy scale của OS đè lên, ignore custom rate của user.
62
- // tắt -> dùng custom rate user tự chỉnh. Cap cứng MAX_FONT_SCALE (150%) cả hai.
61
+ // useOSFontScale on -> apply the OS scale, ignore the user's custom rate.
62
+ // off -> use the user's custom rate. Both hard-capped at MAX_FONT_SCALE (150%).
63
63
  val appliedRate = if (useOSFontScale) fontScale else customRate
64
64
  if (appliedRate > 1f) {
65
65
  fontSizeScaleOS = min(appliedRate * fontSizeScaleOS, fontSizeScaleOS * MAX_FONT_SCALE)
@@ -38,11 +38,11 @@ fun NavigationContainer(
38
38
  val parentContext = ApplicationContext.current
39
39
  val mergedContext = MiniAppContext.merge(parentContext, applicationContext)
40
40
 
41
- // FontScaleConfig host ghi xuống observer storage (single source of truth khi ).
41
+ // FontScaleConfig the host writes to observer storage (single source of truth when present).
42
42
  var observerFontScaleConfig by remember { mutableStateOf<FontScaleConfig?>(null) }
43
43
  LaunchedEffect(maxApi) {
44
44
  val api = maxApi ?: return@LaunchedEffect
45
- // getDataObserver = snapshot lúc mount; observer = subscribe các lần host ghi sau đó.
45
+ // getDataObserver = snapshot at mount; observer = subscribe to later host writes.
46
46
  runCatching {
47
47
  api.getDataObserver(FONT_SCALE_OBSERVER_KEY) { data ->
48
48
  parseFontScaleConfig(data)?.let { observerFontScaleConfig = it }
@@ -162,10 +162,10 @@ val LocalMaxApi = staticCompositionLocalOf<IMaxApi?> {
162
162
  error("No MaxApi provided")
163
163
  }
164
164
 
165
- // Key observer storage host app ghi FontScaleConfig. Native lowercase key.
165
+ // Observer storage key the host app writes FontScaleConfig to. Lowercased natively.
166
166
  private const val FONT_SCALE_OBSERVER_KEY = "font_scale_config"
167
167
 
168
- // Host trả object {useOSFontScale, userScaleRate}; phòng marshaling bọc envelope / lệch kiểu.
168
+ // Host returns object {useOSFontScale, userScaleRate}; guard against envelope wrapping / type mismatch from marshaling.
169
169
  private fun parseFontScaleConfig(raw: Map<String, Any?>?): FontScaleConfig? {
170
170
  if (raw.isNullOrEmpty()) return null
171
171
  @Suppress("UNCHECKED_CAST")
package/gradle.properties CHANGED
@@ -18,7 +18,7 @@ kotlin.apple.xcodeCompatibility.nowarn=true
18
18
  name="ComposeKits"
19
19
  group=vn.momo.kits
20
20
  artifact.id=kits
21
- version=0.162.2-test.5
21
+ version=0.162.2-test.6
22
22
 
23
23
  repo=GitLab
24
24
  url=https://gitlab.mservice.com.vn/api/v4/projects/5400/packages/maven
@@ -46,5 +46,7 @@ public class ApplicationEnvironment: ObservableObject {
46
46
  self.applicationContext = applicationContext
47
47
  self.composeApi = composeApi
48
48
  self.config = config
49
+ // Load + observe the host font-scale config into the global store read by scaleSize/appFont.
50
+ FontScaleStore.shared.bind(composeApi)
49
51
  }
50
52
  }
@@ -0,0 +1,77 @@
1
+ //
2
+ // FontScaleStore.swift
3
+ // Momo Design System (SwiftUI)
4
+ //
5
+ // Global font-scale config read by scaleSize/appFont. SwiftUI counterpart of the
6
+ // Compose LocalFontScaleConfig and the RN ScaleSizeContext. Populated from the host's
7
+ // `font_scale_config` observer-storage key via the KitComposeApi bridge.
8
+ //
9
+
10
+ import SwiftUI
11
+
12
+ public struct FontScaleConfig {
13
+ public var useOSFontScale: Bool
14
+ public var userScaleRate: CGFloat?
15
+
16
+ public init(useOSFontScale: Bool = false, userScaleRate: CGFloat? = nil) {
17
+ self.useOSFontScale = useOSFontScale
18
+ self.userScaleRate = userScaleRate
19
+ }
20
+ }
21
+
22
+ /// Single source of truth for the font scale. `scaleSize`/`appFont` read `shared.config`.
23
+ /// Views that want live updates observe this object (e.g. MomoText).
24
+ public final class FontScaleStore: ObservableObject {
25
+ public static let shared = FontScaleStore()
26
+
27
+ @Published public private(set) var config = FontScaleConfig()
28
+
29
+ private var didBind = false
30
+ private var observerId: String?
31
+
32
+ private init() {}
33
+
34
+ public func update(_ newConfig: FontScaleConfig) {
35
+ if Thread.isMainThread {
36
+ config = newConfig
37
+ } else {
38
+ DispatchQueue.main.async { [weak self] in self?.config = newConfig }
39
+ }
40
+ }
41
+
42
+ /// Load the current config + subscribe to live changes through the host MaxApi bridge.
43
+ /// Safe no-op when no bridge is provided (config stays at default = no scaling).
44
+ public func bind(_ api: KitComposeApi?) {
45
+ guard let api = api, !didBind else { return }
46
+ didBind = true
47
+
48
+ // snapshot at mount
49
+ api.requestCallback(funcName: "getFontScaleConfig", params: nil) { [weak self] response in
50
+ self?.apply(response)
51
+ }
52
+ // live: re-read on every host write to the key
53
+ observerId = api.request(funcName: "observer", params: ["font_scale_config"]) { [weak self] response in
54
+ self?.apply(response)
55
+ }
56
+ }
57
+
58
+ private func apply(_ response: String) {
59
+ guard let parsed = FontScaleStore.parse(response) else { return }
60
+ update(parsed)
61
+ }
62
+
63
+ /// Tolerates the MaxApi envelope {"status":..,"response":{..}} as well as a bare config object.
64
+ static func parse(_ response: String) -> FontScaleConfig? {
65
+ guard
66
+ let data = response.data(using: .utf8),
67
+ let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
68
+ else { return nil }
69
+
70
+ let obj = (json["response"] as? [String: Any]) ?? (json["data"] as? [String: Any]) ?? json
71
+ guard obj["useOSFontScale"] != nil || obj["userScaleRate"] != nil else { return nil }
72
+
73
+ let useOS = (obj["useOSFontScale"] as? Bool) ?? false
74
+ let rate = (obj["userScaleRate"] as? NSNumber).map { CGFloat($0.doubleValue) }
75
+ return FontScaleConfig(useOSFontScale: useOS, userScaleRate: rate)
76
+ }
77
+ }
@@ -1,6 +1,9 @@
1
1
  import SwiftUI
2
2
 
3
3
  public func scaleSize(_ size: CGFloat, _ scaleRate: CGFloat? = nil) -> CGFloat {
4
+ // Single source of truth: useOSFontScale + userScaleRate from the host config.
5
+ // `scaleRate` param keeps its existing meaning: a hard cap override (default 1.5).
6
+ let config = FontScaleStore.shared.config
4
7
  let defaultScreenSize: CGFloat = 375
5
8
  let maxFontScale: CGFloat = scaleRate ?? 1.5
6
9
  let maxDeviceScale: CGFloat = 5
@@ -10,7 +13,7 @@ public func scaleSize(_ size: CGFloat, _ scaleRate: CGFloat? = nil) -> CGFloat {
10
13
 
11
14
  let defaultFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)
12
15
  let scaledFont = UIFontMetrics.default.scaledFont(for: defaultFont)
13
- let fontScale = scaledFont.pointSize / defaultFont.pointSize
16
+ let osFontScale = scaledFont.pointSize / defaultFont.pointSize
14
17
 
15
18
  var fontSizeDeviceScale = size
16
19
  var fontSizeOSScale = size
@@ -20,8 +23,11 @@ public func scaleSize(_ size: CGFloat, _ scaleRate: CGFloat? = nil) -> CGFloat {
20
23
  fontSizeDeviceScale = min(fontSizeDeviceScale * deviceScale, fontSizeDeviceScale + maxDeviceScale)
21
24
  }
22
25
 
23
- if fontScale > 1 {
24
- fontSizeOSScale = min(fontSizeOSScale * fontScale, fontSizeOSScale * maxFontScale)
26
+ // useOSFontScale on -> follow OS Dynamic Type; off -> use the user rate (default 1 = no scaling).
27
+ // Both capped at maxFontScale. Mirrors Compose scaleSize / RN useScaleSize.
28
+ let appliedRate = config.useOSFontScale ? osFontScale : (config.userScaleRate ?? 1)
29
+ if appliedRate > 1 {
30
+ fontSizeOSScale = min(fontSizeOSScale * appliedRate, fontSizeOSScale * maxFontScale)
25
31
  }
26
32
 
27
33
  return max(fontSizeDeviceScale, fontSizeOSScale)
@@ -118,6 +124,8 @@ public struct MomoText: View {
118
124
  private let content: String
119
125
  private let typography: TypographyStyle
120
126
  private let color: Color
127
+ // Observe the global store so the text re-renders live when the host changes the config.
128
+ @ObservedObject private var fontScale = FontScaleStore.shared
121
129
 
122
130
  public init(
123
131
  _ content: String,
@@ -130,6 +138,7 @@ public struct MomoText: View {
130
138
  }
131
139
 
132
140
  public var body: some View {
141
+ _ = fontScale.config
133
142
  let text = SwiftUI.Text(content)
134
143
  .font(.system(size: scaleSize(typography.fontSize), weight: typography.fontWeight))
135
144
  .foregroundColor(color)
@@ -2,16 +2,21 @@ import SwiftUI
2
2
 
3
3
  public extension Font {
4
4
  static func appFont(size: CGFloat) -> Font {
5
+ // Single source of truth: useOSFontScale + userScaleRate from the host config.
6
+ // NOTE: the static Font.xxx constants below are evaluated once at type load, so they
7
+ // capture the config at first access. Live updates apply to scaleSize()/MomoText and
8
+ // any fresh appFont(size:) call, not to the cached static constants.
9
+ let config = FontScaleStore.shared.config
5
10
  let defaultScreenSize: CGFloat = 375
6
11
  let maxFontScale: CGFloat = 1.5
7
12
  let maxDeviceScale: CGFloat = 5
8
-
13
+
9
14
  let deviceWidth = UIScreen.main.bounds.width
10
15
  let deviceScale = deviceWidth / defaultScreenSize
11
-
16
+
12
17
  let defaultFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)
13
18
  let scaledFont = UIFontMetrics.default.scaledFont(for: defaultFont)
14
- let fontScale = scaledFont.pointSize / defaultFont.pointSize
19
+ let osFontScale = scaledFont.pointSize / defaultFont.pointSize
15
20
 
16
21
  var fontSize = size
17
22
 
@@ -19,8 +24,9 @@ public extension Font {
19
24
  fontSize = min(fontSize * deviceScale, fontSize + maxDeviceScale)
20
25
  }
21
26
 
22
- if fontScale > 1 {
23
- fontSize = min(fontSize * fontScale, fontSize * maxFontScale)
27
+ let appliedRate = config.useOSFontScale ? osFontScale : (config.userScaleRate ?? 1)
28
+ if appliedRate > 1 {
29
+ fontSize = min(fontSize * appliedRate, fontSize * maxFontScale)
24
30
  }
25
31
 
26
32
  return Font.system(size: fontSize)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.162.2-test.5-debug",
3
+ "version": "0.162.2-test.6-debug",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},