@momo-kits/native-kits 0.110.1-beta.1 → 0.110.1-beta.5
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.
- package/compose/build.gradle.kts +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Components.kt +23 -7
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +53 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +8 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +5 -1
- package/ios/Checkbox/Checkbox.swift +15 -35
- package/ios/Icon/Icon.swift +53 -0
- package/ios/Input/Input.swift +9 -51
- package/ios/Typography/Typography.swift +47 -4
- package/package.json +1 -1
package/compose/build.gradle.kts
CHANGED
|
@@ -3,6 +3,7 @@ plugins {
|
|
|
3
3
|
alias(libs.plugins.jetbrains.kotlin.multiplatform)
|
|
4
4
|
alias(libs.plugins.compose)
|
|
5
5
|
alias(libs.plugins.kotlin.compose.compiler)
|
|
6
|
+
kotlin("plugin.serialization")
|
|
6
7
|
id("maven-publish")
|
|
7
8
|
}
|
|
8
9
|
|
|
@@ -39,6 +40,7 @@ kotlin {
|
|
|
39
40
|
implementation(libs.coil.multiplatform.compose)
|
|
40
41
|
implementation(libs.coil.multiplatform.core)
|
|
41
42
|
implementation(libs.coil.multiplatform.network.ktor)
|
|
43
|
+
implementation(libs.jetbrains.serialization.json)
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
val androidMain by getting {
|
|
@@ -73,11 +73,19 @@ fun HeaderBackground(
|
|
|
73
73
|
targetValue = (1 - (scrollState / 200f)).coerceIn(0f, 1f),
|
|
74
74
|
)
|
|
75
75
|
|
|
76
|
+
val backgroundColor = if (scrollState == 0) {
|
|
77
|
+
Color.Transparent
|
|
78
|
+
} else {
|
|
79
|
+
AppTheme.current.colors.background.surface
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
76
83
|
when (headerType) {
|
|
77
84
|
HeaderType.DEFAULT -> {
|
|
78
85
|
val height = statusBarHeight + 52.dp
|
|
79
86
|
Box(
|
|
80
87
|
modifier = Modifier.fillMaxWidth().height(height)
|
|
88
|
+
.background(backgroundColor)
|
|
81
89
|
.bottomBorder(
|
|
82
90
|
strokeWidth = 1.dp,
|
|
83
91
|
color = AppTheme.current.colors.border.default
|
|
@@ -101,6 +109,7 @@ fun HeaderBackground(
|
|
|
101
109
|
)
|
|
102
110
|
if (AppTheme.current.assets.headerBackground != null) {
|
|
103
111
|
Image(
|
|
112
|
+
loading = false,
|
|
104
113
|
source = AppTheme.current.assets.headerBackground!!,
|
|
105
114
|
modifier = Modifier.fillMaxWidth().height(height),
|
|
106
115
|
options = Options(
|
|
@@ -113,6 +122,7 @@ fun HeaderBackground(
|
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
HeaderType.EXTENDED -> {
|
|
125
|
+
|
|
116
126
|
Box(
|
|
117
127
|
modifier = Modifier.fillMaxWidth().height(154.dp)
|
|
118
128
|
.alpha(opacityAni)
|
|
@@ -128,13 +138,19 @@ fun HeaderBackground(
|
|
|
128
138
|
)
|
|
129
139
|
) {
|
|
130
140
|
if (AppTheme.current.assets.headerBackground != null) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
Box(
|
|
142
|
+
modifier = Modifier.fillMaxWidth()
|
|
143
|
+
.background(backgroundColor)
|
|
144
|
+
) {
|
|
145
|
+
Image(
|
|
146
|
+
loading = false,
|
|
147
|
+
source = AppTheme.current.assets.headerBackground!!,
|
|
148
|
+
modifier = Modifier.fillMaxWidth().height(154.dp),
|
|
149
|
+
options = Options(
|
|
150
|
+
contentScale = ContentScale.FillWidth
|
|
151
|
+
)
|
|
136
152
|
)
|
|
137
|
-
|
|
153
|
+
}
|
|
138
154
|
}
|
|
139
155
|
}
|
|
140
156
|
}
|
|
@@ -246,7 +262,7 @@ fun Header(
|
|
|
246
262
|
}
|
|
247
263
|
if (inputSearchProps != null) {
|
|
248
264
|
InputSearch(inputSearchProps = inputSearchProps.copy(backgroundColor = backgroundSearch))
|
|
249
|
-
} else{
|
|
265
|
+
} else {
|
|
250
266
|
Box(
|
|
251
267
|
Modifier.weight(1f).graphicsLayer {
|
|
252
268
|
alpha = if (animatedHeader !== null) opacity ?: 1f else 1f
|
|
@@ -1,64 +1,77 @@
|
|
|
1
1
|
package vn.momo.kits.application
|
|
2
2
|
|
|
3
|
-
import androidx.compose.foundation.layout.WindowInsets
|
|
4
|
-
import androidx.compose.foundation.layout.asPaddingValues
|
|
5
|
-
import androidx.compose.foundation.layout.systemBars
|
|
6
3
|
import androidx.compose.runtime.Composable
|
|
7
4
|
import androidx.compose.runtime.CompositionLocalProvider
|
|
5
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
6
|
+
import androidx.compose.runtime.getValue
|
|
7
|
+
import androidx.compose.runtime.mutableStateOf
|
|
8
|
+
import androidx.compose.runtime.remember
|
|
9
|
+
import androidx.compose.runtime.rememberCoroutineScope
|
|
10
|
+
import androidx.compose.runtime.setValue
|
|
8
11
|
import androidx.compose.runtime.staticCompositionLocalOf
|
|
12
|
+
import androidx.compose.ui.unit.Dp
|
|
13
|
+
import kotlinx.coroutines.launch
|
|
14
|
+
import kotlinx.serialization.json.Json
|
|
15
|
+
import kotlinx.serialization.json.jsonObject
|
|
16
|
+
import kotlinx.serialization.json.jsonPrimitive
|
|
9
17
|
import vn.momo.kits.const.AppStatusBar
|
|
10
18
|
import vn.momo.kits.const.AppTheme
|
|
11
19
|
import vn.momo.kits.const.Theme
|
|
20
|
+
import vn.momo.kits.const.ThemeAssets
|
|
12
21
|
import vn.momo.kits.const.defaultTheme
|
|
13
22
|
import vn.momo.kits.platform.disableOverscroll
|
|
14
23
|
import vn.momo.kits.platform.getStatusBarHeight
|
|
15
24
|
|
|
16
|
-
val
|
|
17
|
-
error("no navigator provided!")
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
class Navigator {
|
|
21
|
-
fun push(content: @Composable () -> Unit) {
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
fun present(content: @Composable () -> Unit) {
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
fun reset(content: @Composable () -> Unit) {
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
fun pop() {
|
|
33
|
-
}
|
|
25
|
+
val PlatformApi = staticCompositionLocalOf<Any?> { null }
|
|
34
26
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
fun
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
fun showModal(
|
|
42
|
-
onClose: () -> Unit = {},
|
|
43
|
-
canBackgroundClose: Boolean = true,
|
|
44
|
-
content: @Composable () -> Unit,
|
|
45
|
-
) {
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
fun showBottomSheet(content: @Composable () -> Unit) {
|
|
49
|
-
}
|
|
27
|
+
interface ComposeApi {
|
|
28
|
+
fun request(funcName: String, params: String?): String
|
|
29
|
+
fun request(funcName: String, params: String?, onResponse: ((String) -> Unit)?): String
|
|
30
|
+
fun requestCallback(funcName: String, params: String?, onResponse: ((String) -> Unit)?)
|
|
31
|
+
fun removeCallback(id: String)
|
|
50
32
|
}
|
|
51
33
|
|
|
52
34
|
@Composable
|
|
53
35
|
fun ApplicationContainer(
|
|
54
36
|
theme: Theme = defaultTheme,
|
|
55
|
-
|
|
37
|
+
composeApi: ComposeApi? = null,
|
|
38
|
+
statusBarHeight: Dp? = AppStatusBar.current ?: getStatusBarHeight(),
|
|
39
|
+
content: @Composable () -> Unit
|
|
56
40
|
) {
|
|
41
|
+
var appTheme by remember { mutableStateOf(theme) }
|
|
42
|
+
val coroutineScope = rememberCoroutineScope()
|
|
43
|
+
|
|
44
|
+
LaunchedEffect(Unit) {
|
|
45
|
+
try {
|
|
46
|
+
composeApi?.request("getConfig", "DESIGN_SYSTEM") {
|
|
47
|
+
val json = Json { ignoreUnknownKeys = true }
|
|
48
|
+
val response = json.parseToJsonElement(it).jsonObject["response"]
|
|
49
|
+
val headerBar = response
|
|
50
|
+
?.jsonObject
|
|
51
|
+
?.get("headerBar")
|
|
52
|
+
?.jsonPrimitive
|
|
53
|
+
?.content
|
|
54
|
+
if (headerBar != null && appTheme.assets.headerBackground == null) {
|
|
55
|
+
coroutineScope.launch {
|
|
56
|
+
appTheme = appTheme.copy(
|
|
57
|
+
assets = ThemeAssets(
|
|
58
|
+
headerBackground = headerBar
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (e: Exception) {
|
|
66
|
+
print("@@ == NavigationContainer fetch config error $e")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
disableOverscroll()
|
|
58
71
|
CompositionLocalProvider(
|
|
59
|
-
AppTheme provides
|
|
60
|
-
|
|
61
|
-
AppStatusBar provides
|
|
72
|
+
AppTheme provides appTheme,
|
|
73
|
+
PlatformApi provides composeApi,
|
|
74
|
+
AppStatusBar provides statusBarHeight,
|
|
62
75
|
) {
|
|
63
76
|
content()
|
|
64
77
|
}
|
|
@@ -87,7 +87,9 @@ fun Screen(
|
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
val headerAnimated =
|
|
90
|
-
@Composable {
|
|
90
|
+
@Composable {
|
|
91
|
+
animatedHeader?.composable?.invoke(scrollState.value)
|
|
92
|
+
}
|
|
91
93
|
|
|
92
94
|
Box(
|
|
93
95
|
Modifier.fillMaxSize()
|
|
@@ -95,7 +97,10 @@ fun Screen(
|
|
|
95
97
|
) {
|
|
96
98
|
|
|
97
99
|
if (animatedHeader === null) {
|
|
98
|
-
HeaderBackground(
|
|
100
|
+
HeaderBackground(
|
|
101
|
+
headerType = headerType,
|
|
102
|
+
scrollState = scrollState.value,
|
|
103
|
+
)
|
|
99
104
|
} else {
|
|
100
105
|
Box(
|
|
101
106
|
Modifier.zIndex(2f)
|
|
@@ -104,7 +109,7 @@ fun Screen(
|
|
|
104
109
|
) {
|
|
105
110
|
HeaderBackground(
|
|
106
111
|
headerType = headerType,
|
|
107
|
-
scrollState = scrollState.value
|
|
112
|
+
scrollState = scrollState.value,
|
|
108
113
|
)
|
|
109
114
|
}
|
|
110
115
|
}
|
|
@@ -98,6 +98,7 @@ data class InputSearchProps(
|
|
|
98
98
|
val keyboardActions: KeyboardActions = KeyboardActions.Default,
|
|
99
99
|
val modifier: Modifier = Modifier,
|
|
100
100
|
val iconModifier: Modifier = Modifier,
|
|
101
|
+
val onClearPress: () -> Unit = {}
|
|
101
102
|
)
|
|
102
103
|
|
|
103
104
|
@Composable
|
|
@@ -195,7 +196,10 @@ fun InputSearch(
|
|
|
195
196
|
size = 16.dp,
|
|
196
197
|
color = AppTheme.current.colors.text.hint,
|
|
197
198
|
modifier = Modifier.clickable(
|
|
198
|
-
onClick = {
|
|
199
|
+
onClick = {
|
|
200
|
+
inputSearchProps.text.value = ""
|
|
201
|
+
inputSearchProps.onClearPress.invoke()
|
|
202
|
+
},
|
|
199
203
|
interactionSource = remember { MutableInteractionSource() },
|
|
200
204
|
indication = null
|
|
201
205
|
)
|
|
@@ -4,27 +4,26 @@ import SwiftUI
|
|
|
4
4
|
public struct Checkbox: View{
|
|
5
5
|
@Binding var checked: Bool
|
|
6
6
|
var disabled: Bool
|
|
7
|
-
|
|
8
|
-
var onCheckedChange: ((Bool) -> Void)?
|
|
7
|
+
var onChange: ((Bool)->Void)?
|
|
9
8
|
var indeterminate: Bool
|
|
10
9
|
var title: String
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
public init(_ checked: Binding<Bool>,disabled: Bool = false,
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
public init(_ checked: Binding<Bool>,disabled: Bool = false, onChange: ( (Bool) -> Void)?,
|
|
14
13
|
indeterminate: Bool = false,
|
|
15
14
|
title: String = ""){
|
|
16
15
|
self._checked = checked
|
|
17
16
|
self.disabled = disabled
|
|
18
|
-
self.
|
|
17
|
+
self.onChange = onChange
|
|
19
18
|
self.indeterminate = indeterminate
|
|
20
19
|
self.title = title
|
|
21
20
|
}
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
func onCheck(){
|
|
24
23
|
checked.toggle()
|
|
25
|
-
|
|
24
|
+
onChange?(checked)
|
|
26
25
|
}
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
public var body: some View {
|
|
29
28
|
HStack(spacing: Spacing.S) {
|
|
30
29
|
// Checkbox
|
|
@@ -36,20 +35,20 @@ public struct Checkbox: View{
|
|
|
36
35
|
RoundedRectangle(cornerRadius: Radius.XS)
|
|
37
36
|
.stroke(borderColor, lineWidth: Spacing.XXS)
|
|
38
37
|
)
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
if checked {
|
|
41
40
|
Image(systemName: indeterminate ? "minus" : "checkmark")
|
|
42
41
|
.resizable()
|
|
43
|
-
.foregroundColor(Colors.
|
|
42
|
+
.foregroundColor(Colors.black01)
|
|
44
43
|
.frame(width: 12, height: 12)
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
.onTapGesture {
|
|
48
47
|
if !disabled {
|
|
49
|
-
|
|
48
|
+
onChange?(checked)
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
// Title
|
|
54
53
|
if !title.isEmpty {
|
|
55
54
|
Text(title)
|
|
@@ -57,7 +56,7 @@ public struct Checkbox: View{
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
|
-
|
|
59
|
+
|
|
61
60
|
private var borderColor: Color {
|
|
62
61
|
if disabled {
|
|
63
62
|
return Colors.black03
|
|
@@ -67,7 +66,7 @@ public struct Checkbox: View{
|
|
|
67
66
|
return Colors.text
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
private var backgroundColor: Color {
|
|
72
71
|
if disabled && checked {
|
|
73
72
|
return Colors.pink08
|
|
@@ -77,25 +76,6 @@ public struct Checkbox: View{
|
|
|
77
76
|
return Colors.black01
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
|
-
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
// public var body: some View{
|
|
84
|
-
// return SwiftUI.Button(action: onCheck) {
|
|
85
|
-
// HStack {
|
|
86
|
-
// if (checked) {
|
|
87
|
-
// Image(systemName: "checkmark.square.fill")
|
|
88
|
-
// .resizable()
|
|
89
|
-
// .foregroundColor(disabled ? Colors.black07 : Colors.primary)
|
|
90
|
-
// .frame(width: 24, height: 24)
|
|
91
|
-
// }
|
|
92
|
-
// }.frame(width: 24, height: 24)
|
|
93
|
-
// .overlay(RoundedRectangle(cornerRadius: 4).stroke(Colors.black20,lineWidth: checked ? 0 : 1))
|
|
94
|
-
// .background(Colors.black01)
|
|
95
|
-
//
|
|
96
|
-
// }
|
|
97
|
-
// .opacity(disabled ? 0.4 : 1)
|
|
98
|
-
// .disabled(disabled)
|
|
99
|
-
// }
|
|
100
|
-
|
|
80
|
+
|
|
101
81
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
struct IconSource: Codable {
|
|
4
|
+
let uri: String
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
func loadIconSources() -> [String: IconSource] {
|
|
8
|
+
guard let url = Bundle.main.url(forResource: "icon", withExtension: "json") else {
|
|
9
|
+
print("Error: icon.json not found")
|
|
10
|
+
return [:]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
do {
|
|
14
|
+
let data = try Data(contentsOf: url)
|
|
15
|
+
let decoded = try JSONDecoder().decode([String: IconSource].self, from: data)
|
|
16
|
+
return decoded
|
|
17
|
+
} catch {
|
|
18
|
+
print("Error decoding icon.json: \(error)")
|
|
19
|
+
return [:]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Load the JSON data into a global variable
|
|
24
|
+
let iconSources: [String: IconSource] = loadIconSources()
|
|
25
|
+
|
|
26
|
+
// Icon ViewModel
|
|
27
|
+
public struct Icon: View {
|
|
28
|
+
var source: String
|
|
29
|
+
var size: CGFloat
|
|
30
|
+
var color: Color?
|
|
31
|
+
var accessibilityLabel: String?
|
|
32
|
+
|
|
33
|
+
public init(
|
|
34
|
+
source: String,
|
|
35
|
+
size: CGFloat = 24,
|
|
36
|
+
color: Color? = nil,
|
|
37
|
+
accessibilityLabel: String? = nil
|
|
38
|
+
) {
|
|
39
|
+
self.source = source
|
|
40
|
+
self.size = size
|
|
41
|
+
self.color = color
|
|
42
|
+
self.accessibilityLabel = accessibilityLabel
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public var body: some View {
|
|
46
|
+
if let uri = iconSources[source]?.uri {
|
|
47
|
+
ImageView(uri)
|
|
48
|
+
.frame(width: size, height: size)
|
|
49
|
+
.foregroundColor(color)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
package/ios/Input/Input.swift
CHANGED
|
@@ -72,12 +72,12 @@ public struct Input: View {
|
|
|
72
72
|
var onChange: ((String) -> Void)?
|
|
73
73
|
var onBlur: (() -> Void)?
|
|
74
74
|
var floatingIconURL: String?
|
|
75
|
-
var floatingIconColor: Color
|
|
75
|
+
var floatingIconColor: Color?
|
|
76
76
|
var size: InputSize
|
|
77
77
|
var fontWeight: InputFontWeight
|
|
78
78
|
var disabled: Bool
|
|
79
79
|
var leadingIcon: String?
|
|
80
|
-
var leadingIconColor: Color
|
|
80
|
+
var leadingIconColor: Color?
|
|
81
81
|
var loading: Bool
|
|
82
82
|
var required: Bool
|
|
83
83
|
var hintText: String?
|
|
@@ -86,7 +86,7 @@ public struct Input: View {
|
|
|
86
86
|
self.value.removeAll()
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
public init(_ value: Binding<String>, placeholder: String = "", floatingValue: String = "", multilines: Bool = false, errorMessage: String = "", isSecure: Bool = false, keyboardType: UIKeyboardType = .default, floatingIcon: AnyView? = nil, rightIcon: AnyView? = nil, onChange: ((String)->Void)? = nil, onBlur: (()->Void)? = nil, floatingIconURL: String? = nil, floatingIconColor: Color = Colors.pink03, size: InputSize = .small, fontWeight: InputFontWeight = .regular, disabled: Bool = false, leadingIcon: String? = nil, leadingIconColor: Color = Colors.pink03, loading: Bool = false, required: Bool = false, hintText: String? = nil){
|
|
89
|
+
public init(_ value: Binding<String>, placeholder: String = "", floatingValue: String = "", multilines: Bool = false, errorMessage: String = "", isSecure: Bool = false, keyboardType: UIKeyboardType = .default, floatingIcon: AnyView? = nil, rightIcon: AnyView? = nil, onChange: ((String)->Void)? = nil, onBlur: (()->Void)? = nil, floatingIconURL: String? = nil, floatingIconColor: Color? = Colors.pink03, size: InputSize = .small, fontWeight: InputFontWeight = .regular, disabled: Bool = false, leadingIcon: String? = nil, leadingIconColor: Color? = Colors.pink03, loading: Bool = false, required: Bool = false, hintText: String? = nil){
|
|
90
90
|
self.placeholder = placeholder
|
|
91
91
|
self.floatingValue = floatingValue
|
|
92
92
|
self.errorMessage = errorMessage
|
|
@@ -117,9 +117,7 @@ public struct Input: View {
|
|
|
117
117
|
ZStack(alignment: .topLeading) {
|
|
118
118
|
HStack(alignment: .center) {
|
|
119
119
|
if let leadingIcon = leadingIcon {
|
|
120
|
-
|
|
121
|
-
.frame(width: 20, height: 20)
|
|
122
|
-
.foregroundColor(leadingIconColor)
|
|
120
|
+
Icon(source: leadingIcon, size: 16, color: leadingIconColor)
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
if !isSecure {
|
|
@@ -156,17 +154,18 @@ public struct Input: View {
|
|
|
156
154
|
if value.isEmpty {
|
|
157
155
|
Text(placeholder + (required ? " *" : ""))
|
|
158
156
|
.foregroundColor(Colors.black09)
|
|
159
|
-
.padding(.horizontal, 12)
|
|
157
|
+
.padding(.horizontal, leadingIcon == nil ? 12 : 32)
|
|
160
158
|
.padding(.top, 12)
|
|
161
159
|
.allowsHitTesting(false)
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
if !floatingValue.isEmpty {
|
|
165
163
|
FloatingComponent(floatingValue, floatingIcon: floatingIconURL.map { url in
|
|
166
|
-
AnyView(
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
AnyView(
|
|
165
|
+
Icon(source: url, size: 16, color: floatingIconColor)
|
|
166
|
+
)
|
|
169
167
|
})
|
|
168
|
+
|
|
170
169
|
}
|
|
171
170
|
}
|
|
172
171
|
|
|
@@ -183,27 +182,6 @@ public struct Input: View {
|
|
|
183
182
|
}
|
|
184
183
|
}
|
|
185
184
|
|
|
186
|
-
struct ImageLoader: View {
|
|
187
|
-
@ObservedObject private var loader: ImageLoaderObject
|
|
188
|
-
|
|
189
|
-
init(url: URL) {
|
|
190
|
-
loader = ImageLoaderObject(url: url)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
var body: some View {
|
|
194
|
-
Group {
|
|
195
|
-
if let image = loader.image {
|
|
196
|
-
Image(uiImage: image)
|
|
197
|
-
.resizable()
|
|
198
|
-
.aspectRatio(contentMode: .fit)
|
|
199
|
-
} else {
|
|
200
|
-
// Use UIActivityIndicatorView for earlier iOS versions
|
|
201
|
-
ActivityIndicator(isAnimating: .constant(true), style: .medium)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
185
|
|
|
208
186
|
struct ActivityIndicator: UIViewRepresentable {
|
|
209
187
|
@Binding var isAnimating: Bool
|
|
@@ -218,26 +196,6 @@ struct ActivityIndicator: UIViewRepresentable {
|
|
|
218
196
|
}
|
|
219
197
|
}
|
|
220
198
|
|
|
221
|
-
class ImageLoaderObject: ObservableObject {
|
|
222
|
-
@Published var image: UIImage?
|
|
223
|
-
private let url: URL
|
|
224
|
-
|
|
225
|
-
init(url: URL) {
|
|
226
|
-
self.url = url
|
|
227
|
-
loadImage()
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
private func loadImage() {
|
|
231
|
-
URLSession.shared.dataTask(with: url) { data, _, _ in
|
|
232
|
-
if let data = data, let loadedImage = UIImage(data: data) {
|
|
233
|
-
DispatchQueue.main.async {
|
|
234
|
-
self.image = loadedImage
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}.resume()
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
199
|
public enum InputSize {
|
|
242
200
|
case small
|
|
243
201
|
case large
|
|
@@ -4,18 +4,61 @@ public extension Font {
|
|
|
4
4
|
static func appFont(size: CGFloat) -> Font {
|
|
5
5
|
return Font.custom("SFProText", size: size)
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
// New supported typography styles
|
|
9
|
+
static let headline_default_bold = appFont(size: 24).weight(.bold)
|
|
10
|
+
static let header_m_bold = appFont(size: 18).weight(.bold)
|
|
11
|
+
static let header_default_bold = appFont(size: 16).weight(.bold)
|
|
12
|
+
static let header_s_semibold = appFont(size: 14).weight(.semibold)
|
|
13
|
+
static let header_xs_semibold = appFont(size: 12).weight(.semibold)
|
|
14
|
+
static let body_default_regular = appFont(size: 14).weight(.regular)
|
|
15
|
+
static let description_default_regular = appFont(size: 12).weight(.regular)
|
|
16
|
+
static let description_xs_regular = appFont(size: 10).weight(.regular)
|
|
17
|
+
static let label_default_medium = appFont(size: 14).weight(.medium)
|
|
18
|
+
static let label_s_medium = appFont(size: 12).weight(.medium)
|
|
19
|
+
static let label_xs_medium = appFont(size: 10).weight(.medium)
|
|
20
|
+
static let action_default_bold = appFont(size: 16).weight(.bold)
|
|
21
|
+
static let action_s_bold = appFont(size: 14).weight(.bold)
|
|
22
|
+
static let action_xs_bold = appFont(size: 12).weight(.bold)
|
|
23
|
+
static let action_xxs_bold = appFont(size: 10).weight(.bold)
|
|
24
|
+
|
|
25
|
+
// Legacy styles
|
|
26
|
+
static let headline_default = appFont(size: 28).weight(.semibold)
|
|
27
|
+
static let headline_s = appFont(size: 24).weight(.semibold)
|
|
28
|
+
static let headline_l = appFont(size: 32).weight(.semibold)
|
|
29
|
+
static let headline_xl = appFont(size: 36).weight(.semibold)
|
|
30
|
+
static let title_default = appFont(size: 20).weight(.bold)
|
|
31
|
+
static let title_xs = appFont(size: 16).weight(.bold)
|
|
32
|
+
static let title_s = appFont(size: 18).weight(.bold)
|
|
33
|
+
static let header_default = appFont(size: 15).weight(.semibold)
|
|
34
|
+
static let header_xs = appFont(size: 12).weight(.semibold)
|
|
35
|
+
static let header_s = appFont(size: 14).weight(.semibold)
|
|
36
|
+
static let paragraph_default = appFont(size: 15).weight(.regular)
|
|
37
|
+
static let paragraph_bold = appFont(size: 15).weight(.bold)
|
|
38
|
+
static let description_default = appFont(size: 14).weight(.regular)
|
|
39
|
+
static let description_xs = appFont(size: 10).weight(.regular)
|
|
40
|
+
static let description_s = appFont(size: 12).weight(.regular)
|
|
41
|
+
static let label_default = appFont(size: 14).weight(.medium)
|
|
42
|
+
static let label_xxs = appFont(size: 8).weight(.medium)
|
|
43
|
+
static let label_xs = appFont(size: 10).weight(.medium)
|
|
44
|
+
static let label_s = appFont(size: 12).weight(.medium)
|
|
45
|
+
static let action_default = appFont(size: 16).weight(.bold)
|
|
46
|
+
static let action_xxs = appFont(size: 10).weight(.bold)
|
|
47
|
+
static let action_xs = appFont(size: 12).weight(.bold)
|
|
48
|
+
static let action_s = appFont(size: 15).weight(.bold)
|
|
49
|
+
|
|
50
|
+
// deprecated
|
|
51
|
+
static let h1 = appFont(size: 36).weight(.semibold) //headline_xl
|
|
9
52
|
static let h2 = appFont(size: 32).weight(.semibold)
|
|
10
53
|
static let h3 = appFont(size: 28).weight(.semibold)
|
|
11
54
|
static let h4 = appFont(size: 24).weight(.semibold)
|
|
12
55
|
static let title1 = appFont(size: 20).weight(.bold)
|
|
13
56
|
static let title2 = appFont(size: 18).weight(.bold)
|
|
14
57
|
static let title3 = appFont(size: 16).weight(.bold)
|
|
15
|
-
static let headerText1 = appFont(size: 15).weight(.semibold)
|
|
58
|
+
static let headerText1 = appFont(size: 15).weight(.semibold) //header_default
|
|
16
59
|
static let headerText2 = appFont(size: 14).weight(.semibold)
|
|
17
60
|
static let headerText3 = appFont(size: 12).weight(.semibold)
|
|
18
|
-
static let paragraph = appFont(size: 15).weight(.regular)
|
|
61
|
+
static let paragraph = appFont(size: 15).weight(.regular) //paragraph_default
|
|
19
62
|
static let description1 = appFont(size: 14).weight(.regular)
|
|
20
63
|
static let description2 = appFont(size: 12).weight(.regular)
|
|
21
64
|
static let description3 = appFont(size: 10).weight(.regular)
|