@onekeyfe/react-native-native-list 6.7.0-alpha.378 → 6.7.0-alpha.383
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/android/src/main/java/com/onekey/nativelist/HybridNativeList.kt +14 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +240 -11
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityDetailsView.kt +7 -4
- package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +6 -3
- package/android/src/main/java/com/onekey/nativelist/NativeListButtonGroupRenderer.kt +102 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListContainerSlotAdapter.kt +12 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +87 -7
- package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +177 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +43 -14
- package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +25 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +33 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +22 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +2 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +2 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +3 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +69 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +55 -1
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +1912 -107
- package/android/src/test/java/com/margelo/nitro/nativelist/NativeListPressPolicyTest.kt +1 -0
- package/docs/ROW_TEMPLATES.md +60 -9
- package/docs/SPEC.md +450 -5
- package/docs/STYLE_SPEC.md +6 -0
- package/ios/HybridNativeList.swift +21 -2
- package/ios/NativeListAccessoryStack.swift +227 -39
- package/ios/NativeListActivityDetailsView.swift +18 -8
- package/ios/NativeListActivityRenderer.swift +8 -2
- package/ios/NativeListButtonGroupRenderer.swift +89 -0
- package/ios/NativeListDataRowRenderer.swift +155 -27
- package/ios/NativeListDesignAssets.swift +3 -0
- package/ios/NativeListIdentityRenderer.swift +166 -30
- package/ios/NativeListLeadingVisual.swift +49 -14
- package/ios/NativeListMessageRenderer.swift +34 -1
- package/ios/NativeListModels.swift +42 -2
- package/ios/NativeListRendererRegistry.swift +1 -0
- package/ios/NativeListResolvedText.swift +2 -1
- package/ios/NativeListRowHost.swift +14 -0
- package/ios/NativeListSectionHeaderRenderer.swift +88 -0
- package/ios/RNCNativeListView.swift +1013 -55
- package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/icon.svg +4 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/icon.svg +3 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/Contents.json +15 -0
- package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/icon.svg +3 -0
- package/ios/tests/NativeListActivityPresentationTests.swift +56 -0
- package/ios/tests/NativeListLifecycleTests.swift +2720 -3
- package/lib/module/NativeList.js +175 -28
- package/lib/module/NativeList.web.js +129 -30
- package/lib/module/index.js +1 -1
- package/lib/module/models.js +1 -0
- package/lib/module/selection.js +1 -1
- package/lib/module/validation.js +421 -8
- package/lib/module/web/NativeListWebEngine.js +507 -19
- package/lib/module/web/templates/ActivityRowRenderer.js +8 -7
- package/lib/module/web/templates/ButtonGroupRowRenderer.js +47 -0
- package/lib/module/web/templates/DataRowRenderer.js +40 -5
- package/lib/module/web/templates/IdentityRowRenderer.js +90 -4
- package/lib/module/web/templates/MessageRowRenderer.js +18 -2
- package/lib/module/web/templates/RowContainerStyle.js +1 -0
- package/lib/module/web/templates/RowRendererRegistry.js +3 -0
- package/lib/module/web/templates/SectionHeaderRowRenderer.js +36 -2
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
- package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
- package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
- package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
- package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
- package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
- package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
- package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
- package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
- package/lib/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
- package/lib/typescript/src/NativeList.d.ts +1 -1
- package/lib/typescript/src/NativeList.nitro.d.ts +2 -0
- package/lib/typescript/src/NativeList.types.d.ts +18 -0
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/models.d.ts +105 -9
- package/lib/typescript/src/validation.d.ts +12 -0
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +32 -0
- package/lib/typescript/src/web/templates/ButtonGroupRowRenderer.d.ts +14 -0
- package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +1 -1
- package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +9 -3
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
- package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
- package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
- package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
- package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
- package/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
- package/package.json +3 -3
- package/react-native-native-list.podspec +1 -0
- package/src/NativeList.nitro.ts +2 -0
- package/src/NativeList.tsx +313 -44
- package/src/NativeList.types.ts +22 -0
- package/src/NativeList.web.tsx +204 -48
- package/src/index.ts +2 -0
- package/src/models.ts +117 -3
- package/src/selection.ts +1 -0
- package/src/validation.ts +852 -6
- package/src/web/NativeListWebEngine.ts +803 -20
- package/src/web/templates/ActivityRowRenderer.ts +14 -6
- package/src/web/templates/ButtonGroupRowRenderer.ts +58 -0
- package/src/web/templates/DataRowRenderer.ts +93 -20
- package/src/web/templates/IdentityRowRenderer.ts +150 -5
- package/src/web/templates/MessageRowRenderer.ts +23 -7
- package/src/web/templates/RowContainerStyle.ts +2 -0
- package/src/web/templates/RowRendererRegistry.ts +11 -1
- package/src/web/templates/SectionHeaderRowRenderer.ts +47 -4
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
package com.margelo.nitro.nativelist
|
|
2
2
|
|
|
3
3
|
import android.graphics.Color
|
|
4
|
+
import android.graphics.Canvas
|
|
4
5
|
import android.graphics.Outline
|
|
6
|
+
import android.graphics.Paint
|
|
5
7
|
import android.graphics.drawable.GradientDrawable
|
|
6
8
|
import android.view.Gravity
|
|
7
9
|
import android.view.View
|
|
@@ -211,6 +213,7 @@ internal class NativeListMessageRowView(context: ThemedReactContext, fonts: Nati
|
|
|
211
213
|
NativeListRendererRowView(context, fonts) {
|
|
212
214
|
override val assetFields = listOf("leading", "thumbnail")
|
|
213
215
|
private val views = NativeListMessageRenderer.Views(context, fonts)
|
|
216
|
+
private val warningBorderPaint = Paint(Paint.ANTI_ALIAS_FLAG)
|
|
214
217
|
|
|
215
218
|
override fun bindContent(
|
|
216
219
|
item: NativeListItem,
|
|
@@ -229,5 +232,27 @@ internal class NativeListMessageRowView(context: ThemedReactContext, fonts: Nati
|
|
|
229
232
|
|
|
230
233
|
override fun recycleContent() = views.recycle()
|
|
231
234
|
|
|
235
|
+
override fun appearance() {
|
|
236
|
+
super.appearance()
|
|
237
|
+
if (boundItem?.json?.optString("presentation") == "inlineWarning") {
|
|
238
|
+
foreground = null
|
|
239
|
+
clipToOutline = false
|
|
240
|
+
(background as? GradientDrawable)?.cornerRadius = 0f
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
override fun dispatchDraw(canvas: Canvas) {
|
|
245
|
+
super.dispatchDraw(canvas)
|
|
246
|
+
val item = boundItem ?: return
|
|
247
|
+
if (item.json.optString("presentation") != "inlineWarning") return
|
|
248
|
+
val container = item.json.optJSONObject("style")?.optJSONObject("container") ?: return
|
|
249
|
+
val borderWidth = container.optDouble("borderWidth", 0.0).toFloat()
|
|
250
|
+
if (borderWidth <= 0) return
|
|
251
|
+
val pixels = (borderWidth * resources.displayMetrics.density).coerceAtLeast(1f)
|
|
252
|
+
warningBorderPaint.color = parseNativeListColor(container.optString("borderColor", "#00000000"))
|
|
253
|
+
canvas.drawRect(0f, 0f, width.toFloat(), pixels, warningBorderPaint)
|
|
254
|
+
canvas.drawRect(0f, height - pixels, width.toFloat(), height.toFloat(), warningBorderPaint)
|
|
255
|
+
}
|
|
256
|
+
|
|
232
257
|
override fun disposeContent() = views.dispose()
|
|
233
258
|
}
|
|
@@ -13,7 +13,7 @@ internal fun isNativeListRowPressEnabled(
|
|
|
13
13
|
variant: String,
|
|
14
14
|
disabled: Boolean,
|
|
15
15
|
pressDisabled: Boolean,
|
|
16
|
-
): Boolean = !disabled && !pressDisabled && (type != "system" || variant == "retry")
|
|
16
|
+
): Boolean = !disabled && !pressDisabled && type != "buttonGroup" && (type != "system" || variant == "retry")
|
|
17
17
|
|
|
18
18
|
internal fun isNativeListWholeRowInteractive(
|
|
19
19
|
type: String,
|
|
@@ -78,7 +78,7 @@ private fun updateLengthPrefixed(digest: MessageDigest, value: String) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// Template type alone partitions reuse; data keys and styles never select a renderer.
|
|
81
|
-
internal enum class NativeListRendererKey { MESSAGE, RAIL, MEDIA_TILE, ACTION, SYSTEM, ACTIVITY, DATA_ROW, METRIC_CARD, MARKET, IDENTITY, SECTION_HEADER, WALLET_GROUP }
|
|
81
|
+
internal enum class NativeListRendererKey { MESSAGE, RAIL, MEDIA_TILE, ACTION, SYSTEM, ACTIVITY, DATA_ROW, METRIC_CARD, MARKET, IDENTITY, SECTION_HEADER, WALLET_GROUP, BUTTON_GROUP }
|
|
82
82
|
|
|
83
83
|
internal data class NativeListItem(
|
|
84
84
|
val key: String,
|
|
@@ -163,6 +163,8 @@ internal data class NativeListItem(
|
|
|
163
163
|
|
|
164
164
|
internal data class NativeListConfig(
|
|
165
165
|
val generation: Int,
|
|
166
|
+
val structuralTransition: StructuralTransition?,
|
|
167
|
+
val disclosure: Disclosure?,
|
|
166
168
|
val layout: String,
|
|
167
169
|
val orientation: String,
|
|
168
170
|
val gridColumns: Int,
|
|
@@ -189,9 +191,36 @@ internal data class NativeListConfig(
|
|
|
189
191
|
val fixedFooter: NativeListItem?,
|
|
190
192
|
val items: List<NativeListItem>,
|
|
191
193
|
) {
|
|
194
|
+
internal data class StructuralTransition(
|
|
195
|
+
val id: String,
|
|
196
|
+
val durationMs: Long,
|
|
197
|
+
val anchorKey: String?,
|
|
198
|
+
)
|
|
199
|
+
internal data class Disclosure(
|
|
200
|
+
val expanded: Boolean,
|
|
201
|
+
val expandedTrailingInset: Double,
|
|
202
|
+
)
|
|
192
203
|
companion object {
|
|
193
204
|
fun parse(snapshotJson: String): NativeListConfig {
|
|
194
205
|
val root = JSONObject(snapshotJson)
|
|
206
|
+
val transition = root.optJSONObject("structuralTransition")
|
|
207
|
+
val structuralTransition = transition?.optString("id")?.takeIf(String::isNotEmpty)?.let { id ->
|
|
208
|
+
StructuralTransition(
|
|
209
|
+
id = id,
|
|
210
|
+
durationMs = transition.optDouble("durationMs", 220.0).coerceIn(0.0, 2000.0).toLong(),
|
|
211
|
+
anchorKey = transition.optString("anchorKey").takeIf(String::isNotEmpty),
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
val disclosureJson = root.optJSONObject("disclosure")
|
|
215
|
+
require(!root.has("disclosure") || disclosureJson != null) { "Invalid disclosure" }
|
|
216
|
+
val disclosure = disclosureJson?.let { value ->
|
|
217
|
+
require(value.opt("expanded") is Boolean) { "Invalid disclosure.expanded" }
|
|
218
|
+
require(!value.has("expandedTrailingInset") ||
|
|
219
|
+
value.opt("expandedTrailingInset") is Number) { "Invalid disclosure.expandedTrailingInset" }
|
|
220
|
+
val inset = value.optDouble("expandedTrailingInset", 0.0)
|
|
221
|
+
require(inset.isFinite() && inset >= 0.0) { "Invalid disclosure.expandedTrailingInset" }
|
|
222
|
+
Disclosure(value.getBoolean("expanded"), inset)
|
|
223
|
+
}
|
|
195
224
|
require(root.getInt("schemaVersion") == 1) { "Unsupported schemaVersion" }
|
|
196
225
|
val layout = root.getJSONObject("layout")
|
|
197
226
|
val selection = root.optJSONObject("selection")
|
|
@@ -214,6 +243,8 @@ internal data class NativeListConfig(
|
|
|
214
243
|
val fixedFooter = root.optJSONObject("fixedFooter")?.let(NativeListItem::parse)
|
|
215
244
|
return NativeListConfig(
|
|
216
245
|
generation = root.getInt("generation"),
|
|
246
|
+
structuralTransition = structuralTransition,
|
|
247
|
+
disclosure = disclosure,
|
|
217
248
|
layout = layout.getString("kind"),
|
|
218
249
|
orientation = layout.optString("orientation", "vertical"),
|
|
219
250
|
gridColumns = layout.optInt("gridColumns", 1).coerceIn(1, 7),
|
|
@@ -240,6 +240,9 @@ internal class OneKeyIconView(context: android.content.Context) : View(context)
|
|
|
240
240
|
private val selectorIconColors: Map<String, List<Int?>> =
|
|
241
241
|
mapOf(
|
|
242
242
|
"GlobusOutline" to listOf(null),
|
|
243
|
+
"GasSolid" to listOf(null),
|
|
244
|
+
"RefreshCcwOutline" to listOf(null),
|
|
245
|
+
"CryptoCoinOutline" to listOf(null, null),
|
|
243
246
|
"LockSolid" to listOf(null),
|
|
244
247
|
"GoogleIllus" to
|
|
245
248
|
listOf(
|
|
@@ -267,6 +270,9 @@ internal class OneKeyIconView(context: android.content.Context) : View(context)
|
|
|
267
270
|
private val selectorIconViewBoxes =
|
|
268
271
|
mapOf(
|
|
269
272
|
"GlobusOutline" to 24f,
|
|
273
|
+
"GasSolid" to 24f,
|
|
274
|
+
"RefreshCcwOutline" to 24f,
|
|
275
|
+
"CryptoCoinOutline" to 24f,
|
|
270
276
|
"LockSolid" to 24f,
|
|
271
277
|
"GoogleIllus" to 24f,
|
|
272
278
|
"AppleBrand" to 16f,
|
|
@@ -282,6 +288,9 @@ internal class OneKeyIconView(context: android.content.Context) : View(context)
|
|
|
282
288
|
private val actionIconFillTypes =
|
|
283
289
|
mapOf(
|
|
284
290
|
"GlobusOutline" to listOf(Path.FillType.EVEN_ODD),
|
|
291
|
+
"GasSolid" to listOf(Path.FillType.EVEN_ODD),
|
|
292
|
+
"RefreshCcwOutline" to listOf(Path.FillType.WINDING),
|
|
293
|
+
"CryptoCoinOutline" to listOf(Path.FillType.WINDING, Path.FillType.EVEN_ODD),
|
|
285
294
|
"LockSolid" to listOf(Path.FillType.EVEN_ODD),
|
|
286
295
|
"GoogleIllus" to
|
|
287
296
|
listOf(
|
|
@@ -324,6 +333,19 @@ internal class OneKeyIconView(context: android.content.Context) : View(context)
|
|
|
324
333
|
// Exact 24x24 paths from app-monorepo packages/components Icon sources.
|
|
325
334
|
private val iconPaths =
|
|
326
335
|
mapOf(
|
|
336
|
+
"RefreshCcwOutline" to
|
|
337
|
+
listOf(
|
|
338
|
+
"M5 12a7 7 0 0 0 7 7 7.15 7.15 0 0 0 4.955-2h-2.943v-2h6v6h-2v-2.257A9.148 9.148 0 0 1 12 21a9 9 0 0 1-9-9v-1h2v1Zm1-6.754A9.148 9.148 0 0 1 12 3a9 9 0 0 1 9 9v1h-2v-1a7 7 0 0 0-7-7 7.15 7.15 0 0 0-4.955 2H10v2H4V3h2v2.246Z"
|
|
339
|
+
),
|
|
340
|
+
"GasSolid" to
|
|
341
|
+
listOf(
|
|
342
|
+
"M15 9h4v7h1V8.414L17.586 6 19 4.586l3 3V18h-5v-7h-2v8h1v2H2v-2h1V3h12zM6 9v2h6V9z"
|
|
343
|
+
),
|
|
344
|
+
"CryptoCoinOutline" to
|
|
345
|
+
listOf(
|
|
346
|
+
"M11 16.387a4.5 4.5 0 0 1 0-8.775V6h2v1.613a4.5 4.5 0 0 1 2.856 2.067l-1.712 1.032a2.5 2.5 0 1 0 0 2.576l1.712 1.032A4.5 4.5 0 0 1 13 16.386V18h-2z",
|
|
347
|
+
"M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10m-2 0a8 8 0 1 0-16 0 8 8 0 0 0 16 0",
|
|
348
|
+
),
|
|
327
349
|
// OneKey patch: official selector SVG path geometry.
|
|
328
350
|
"GlobusOutline" to
|
|
329
351
|
listOf(
|
|
@@ -17,6 +17,7 @@ internal object NativeListRendererRegistry {
|
|
|
17
17
|
NativeListRendererKey.ACTIVITY to ::NativeListActivityRowView,
|
|
18
18
|
NativeListRendererKey.SYSTEM to ::NativeListSystemRowView,
|
|
19
19
|
NativeListRendererKey.ACTION to ::NativeListActionRowView,
|
|
20
|
+
NativeListRendererKey.BUTTON_GROUP to ::NativeListButtonGroupRowView,
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
private val keys =
|
|
@@ -33,6 +34,7 @@ internal object NativeListRendererRegistry {
|
|
|
33
34
|
"activity" to NativeListRendererKey.ACTIVITY,
|
|
34
35
|
"system" to NativeListRendererKey.SYSTEM,
|
|
35
36
|
"action" to NativeListRendererKey.ACTION,
|
|
37
|
+
"buttonGroup" to NativeListRendererKey.BUTTON_GROUP,
|
|
36
38
|
)
|
|
37
39
|
|
|
38
40
|
fun key(type: String) = keys.getValue(type)
|
|
@@ -106,6 +106,8 @@ internal abstract class NativeListRendererRowView(protected val reactContext: Th
|
|
|
106
106
|
protected open val pressedColorName = "rowPressedBackground"
|
|
107
107
|
protected open val pressedColorFallback = "#00000017"
|
|
108
108
|
private var current: NativeListItem? = null
|
|
109
|
+
protected val boundItem: NativeListItem?
|
|
110
|
+
get() = current
|
|
109
111
|
private var theme: JSONObject? = null
|
|
110
112
|
private var listLayout = "linear"
|
|
111
113
|
private var itemIndex: Int? = null
|
|
@@ -52,7 +52,7 @@ internal data class NativeListResolvedText(
|
|
|
52
52
|
view.letterSpacing = 0f
|
|
53
53
|
view.gravity = gravity
|
|
54
54
|
view.opticalOffsetY = offset
|
|
55
|
-
view.maxLines = lines
|
|
55
|
+
view.maxLines = if (lines == 0) Int.MAX_VALUE else lines
|
|
56
56
|
view.setHorizontallyScrolling(lines == 1 && explicitTruncation)
|
|
57
57
|
view.ellipsize = if (explicitTruncation && !clip) TextUtils.TruncateAt.END else null
|
|
58
58
|
view.setLineSpacing(0f, 1f)
|
|
@@ -87,7 +87,8 @@ internal data class NativeListResolvedText(
|
|
|
87
87
|
sourceScale: Boolean,
|
|
88
88
|
): NativeListResolvedText {
|
|
89
89
|
val density = context.resources.displayMetrics.density
|
|
90
|
-
val
|
|
90
|
+
val requestedLines = style?.optInt("lines", lines) ?: lines
|
|
91
|
+
val maxLines = if (requestedLines == 0) 0 else requestedLines.coerceIn(1, 3)
|
|
91
92
|
val truncation = style?.let { it.has("lines") || it.has("truncate") } == true
|
|
92
93
|
val fontSize =
|
|
93
94
|
if (style?.has("fontSize") == true) (style.optDouble("fontSize") * density).toFloat()
|
|
@@ -26,6 +26,7 @@ internal class NativeListSectionHeaderRowView(context: ThemedReactContext, fonts
|
|
|
26
26
|
private val mainColumn = LinearLayout(context)
|
|
27
27
|
private val titleLine = PackedTitleLineLayout(context)
|
|
28
28
|
private val title = DottedUnderlineTextView(context)
|
|
29
|
+
private val leadingBadge = NativeListTextView(context)
|
|
29
30
|
private val titleSpinner = ProgressBar(context, null, android.R.attr.progressBarStyleSmall).apply {
|
|
30
31
|
isIndeterminate = true
|
|
31
32
|
importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
|
|
@@ -165,6 +166,12 @@ internal class NativeListSectionHeaderRowView(context: ThemedReactContext, fonts
|
|
|
165
166
|
currentTheme = theme
|
|
166
167
|
currentLayout = layout
|
|
167
168
|
removeAllViews()
|
|
169
|
+
if (trailingViews[0].parent === titleLine) {
|
|
170
|
+
titleLine.removeView(trailingViews[0])
|
|
171
|
+
trailingColumn.addView(trailingViews[0], 0)
|
|
172
|
+
}
|
|
173
|
+
titleLine.removeView(leadingBadge)
|
|
174
|
+
leadingBadge.text = ""
|
|
168
175
|
titleLine.removeView(headerTitleIcon)
|
|
169
176
|
trailingColumn.removeView(headerValueIcon)
|
|
170
177
|
paintDefaults.forEach { (view, flags) -> view.paintFlags = flags }
|
|
@@ -188,6 +195,10 @@ internal class NativeListSectionHeaderRowView(context: ThemedReactContext, fonts
|
|
|
188
195
|
view.ellipsize = null
|
|
189
196
|
view.setHorizontallyScrolling(false)
|
|
190
197
|
view.opticalOffsetY = 0f
|
|
198
|
+
view.helpBindingGeneration += 1
|
|
199
|
+
view.guardsHelpTouches = false
|
|
200
|
+
view.primaryHelpOnly = false
|
|
201
|
+
view.showsHelpUnderline = false
|
|
191
202
|
view.gravity = Gravity.START
|
|
192
203
|
view.letterSpacing = 0f
|
|
193
204
|
view.fontFeatureSettings = "tnum"
|
|
@@ -291,6 +302,7 @@ internal class NativeListSectionHeaderRowView(context: ThemedReactContext, fonts
|
|
|
291
302
|
}
|
|
292
303
|
}
|
|
293
304
|
applyTextStyle(item)
|
|
305
|
+
bindPositionHeaderFields(item, theme)
|
|
294
306
|
titleSpinner.indeterminateTintList = ColorStateList.valueOf(title.currentTextColor)
|
|
295
307
|
style
|
|
296
308
|
.optJSONObject("container")
|
|
@@ -307,6 +319,57 @@ internal class NativeListSectionHeaderRowView(context: ThemedReactContext, fonts
|
|
|
307
319
|
applySelectorTypography(item)
|
|
308
320
|
}
|
|
309
321
|
|
|
322
|
+
private fun bindPositionHeaderFields(item: NativeListItem, theme: JSONObject?) {
|
|
323
|
+
val style = item.json.optJSONObject("style") ?: JSONObject()
|
|
324
|
+
item.json.optJSONObject("leadingBadge")?.let { badge ->
|
|
325
|
+
leadingBadge.text = badge.optString("text")
|
|
326
|
+
leadingBadge.textSize = sp(12f)
|
|
327
|
+
leadingBadge.typeface = fonts.medium(context)
|
|
328
|
+
leadingBadge.includeFontPadding = false
|
|
329
|
+
val tones = mapOf("info" to ("info" to "#0F69F6"), "success" to ("positive" to "#008F5A"), "warning" to ("caution" to "#A35E00"), "danger" to ("negative" to "#CE2C31"))
|
|
330
|
+
val tone = tones[badge.optString("tone")]
|
|
331
|
+
if (tone != null) {
|
|
332
|
+
val tint = color(theme, tone.first, tone.second)
|
|
333
|
+
leadingBadge.setTextColor(tint)
|
|
334
|
+
val fallback = (tint and 0x00FFFFFF) or (31 shl 24)
|
|
335
|
+
val fill = if (badge.optString("tone") == "success" && theme?.has("successBackground") == true)
|
|
336
|
+
safeColor(theme.optString("successBackground"), fallback) else fallback
|
|
337
|
+
leadingBadge.background = roundedFill(fill, 4f)
|
|
338
|
+
} else {
|
|
339
|
+
leadingBadge.setTextColor(color(theme, "secondaryText", "#0000009B"))
|
|
340
|
+
leadingBadge.background = roundedFill(color(theme, "strongBackground", "#0000000F"), 4f)
|
|
341
|
+
}
|
|
342
|
+
leadingBadge.setPadding(dp(8), dp(2), dp(8), dp(2))
|
|
343
|
+
TextViewCompat.setLineHeight(leadingBadge, dp(16))
|
|
344
|
+
titleLine.addView(leadingBadge, 0, LayoutParams(LayoutParams.WRAP_CONTENT, dp(20)).apply { marginEnd = dp(8) })
|
|
345
|
+
}
|
|
346
|
+
if (style.has("titleDecoration")) {
|
|
347
|
+
title.showsDottedUnderline = false
|
|
348
|
+
title.showsHelpUnderline = style.optString("titleDecoration") == "dashed"
|
|
349
|
+
title.setPadding(0, 0, 0, if (title.showsHelpUnderline) dp(3) else 0)
|
|
350
|
+
}
|
|
351
|
+
val value = trailingViews[0]
|
|
352
|
+
if (style.optString("valuePlacement") == "afterTitle") {
|
|
353
|
+
trailingColumn.removeView(value)
|
|
354
|
+
title.layoutParams = wrap()
|
|
355
|
+
titleLine.packsChildrenAtStart = false
|
|
356
|
+
titleLine.addView(value, wrap().apply { marginStart = dp(8) })
|
|
357
|
+
}
|
|
358
|
+
item.json.optJSONObject("valueHelp")?.let { help ->
|
|
359
|
+
value.guardsHelpTouches = true
|
|
360
|
+
value.setOnClickListener(null)
|
|
361
|
+
value.isClickable = false
|
|
362
|
+
value.showsHelpUnderline = help.optString("underline") == "dashed"
|
|
363
|
+
if (help.optString("presentation") == "popover") {
|
|
364
|
+
value.setOnClickListener {
|
|
365
|
+
currentItem?.takeUnless { it.json.optBoolean("disabled") }?.let {
|
|
366
|
+
emitAction(it, help.optString("actionKey"), null, value, "trailingAccessory", 0)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
310
373
|
private fun applyTextStyle(item: NativeListItem) {
|
|
311
374
|
val style = item.json.optJSONObject("style") ?: return
|
|
312
375
|
for ((slot, view) in
|
|
@@ -411,6 +474,12 @@ internal class NativeListSectionHeaderRowView(context: ThemedReactContext, fonts
|
|
|
411
474
|
override fun recycleContent() {
|
|
412
475
|
checkboxControl.reset()
|
|
413
476
|
currentItem = null
|
|
477
|
+
title.setOnClickListener(null)
|
|
478
|
+
title.isClickable = false
|
|
479
|
+
trailingViews[0].helpBindingGeneration += 1
|
|
480
|
+
trailingViews[0].setOnClickListener(null)
|
|
481
|
+
trailingViews[0].isClickable = false
|
|
482
|
+
trailingViews[0].showsHelpUnderline = false
|
|
414
483
|
titleSpinner.visibility = GONE
|
|
415
484
|
}
|
|
416
485
|
|
|
@@ -1,9 +1,62 @@
|
|
|
1
1
|
package com.margelo.nitro.nativelist
|
|
2
2
|
|
|
3
3
|
import android.graphics.Canvas
|
|
4
|
+
import android.graphics.DashPathEffect
|
|
5
|
+
import android.graphics.Paint
|
|
6
|
+
import android.graphics.RectF
|
|
7
|
+
import android.view.MotionEvent
|
|
4
8
|
import android.widget.TextView
|
|
5
9
|
|
|
6
10
|
internal open class NativeListTextView(context: android.content.Context) : TextView(context) {
|
|
11
|
+
var helpBindingGeneration = 0
|
|
12
|
+
var guardsHelpTouches = false
|
|
13
|
+
private var helpDownGeneration = -1
|
|
14
|
+
var primaryHelpOnly = false
|
|
15
|
+
var showsHelpUnderline = false
|
|
16
|
+
set(value) { field = value; invalidate() }
|
|
17
|
+
private val helpPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
|
18
|
+
style = Paint.Style.STROKE
|
|
19
|
+
strokeWidth = resources.displayMetrics.density
|
|
20
|
+
pathEffect = DashPathEffect(floatArrayOf(3 * strokeWidth, 2 * strokeWidth), 0f)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
val helpAnchorBounds: RectF?
|
|
24
|
+
get() {
|
|
25
|
+
if (!primaryHelpOnly) return null
|
|
26
|
+
val textLayout = layout ?: return null
|
|
27
|
+
if (textLayout.lineCount == 0) return null
|
|
28
|
+
return RectF(
|
|
29
|
+
totalPaddingLeft + textLayout.getLineLeft(0),
|
|
30
|
+
(totalPaddingTop + textLayout.getLineTop(0)).toFloat() + opticalOffsetY,
|
|
31
|
+
totalPaddingLeft + textLayout.getLineRight(0),
|
|
32
|
+
(totalPaddingTop + textLayout.getLineBottom(0)).toFloat() + opticalOffsetY,
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
37
|
+
if (primaryHelpOnly && event.actionMasked == MotionEvent.ACTION_DOWN &&
|
|
38
|
+
helpAnchorBounds?.contains(event.x, event.y) != true) return false
|
|
39
|
+
if (guardsHelpTouches) {
|
|
40
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) helpDownGeneration = helpBindingGeneration
|
|
41
|
+
if (event.actionMasked == MotionEvent.ACTION_UP && helpDownGeneration != helpBindingGeneration) {
|
|
42
|
+
isPressed = false
|
|
43
|
+
return true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return super.onTouchEvent(event)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private fun drawHelpUnderline(canvas: Canvas) {
|
|
50
|
+
if (!showsHelpUnderline) return
|
|
51
|
+
val textLayout = layout ?: return
|
|
52
|
+
if (textLayout.lineCount == 0) return
|
|
53
|
+
helpPaint.color = currentTextColor
|
|
54
|
+
val left = totalPaddingLeft + textLayout.getLineLeft(0)
|
|
55
|
+
val right = totalPaddingLeft + textLayout.getLineRight(0)
|
|
56
|
+
val bottom = totalPaddingTop + textLayout.getLineBottom(0) - resources.displayMetrics.density
|
|
57
|
+
canvas.drawLine(left, bottom, right, bottom, helpPaint)
|
|
58
|
+
}
|
|
59
|
+
|
|
7
60
|
var rowHorizontallyScrolling = false
|
|
8
61
|
private set
|
|
9
62
|
|
|
@@ -16,10 +69,11 @@ internal open class NativeListTextView(context: android.content.Context) : TextV
|
|
|
16
69
|
set(value) { field = value; invalidate() }
|
|
17
70
|
|
|
18
71
|
override fun onDraw(canvas: Canvas) {
|
|
19
|
-
if (opticalOffsetY == 0f) { super.onDraw(canvas); return }
|
|
72
|
+
if (opticalOffsetY == 0f) { super.onDraw(canvas); drawHelpUnderline(canvas); return }
|
|
20
73
|
val checkpoint = canvas.save()
|
|
21
74
|
canvas.translate(0f, opticalOffsetY)
|
|
22
75
|
super.onDraw(canvas)
|
|
76
|
+
drawHelpUnderline(canvas)
|
|
23
77
|
canvas.restoreToCount(checkpoint)
|
|
24
78
|
}
|
|
25
79
|
}
|