@onekeyfe/react-native-native-list 3.0.113 → 3.0.115
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/build.gradle +1 -0
- package/android/src/main/java/com/onekey/nativelist/NativeListRowView.kt +8 -2
- package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +378 -88
- package/ios/NativeListCell.swift +2 -0
- package/ios/RNCNativeListView.swift +186 -35
- package/lib/module/web/NativeListWebEngine.js +104 -46
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +11 -2
- package/package.json +4 -2
- package/src/web/NativeListWebEngine.ts +190 -89
package/ios/NativeListCell.swift
CHANGED
|
@@ -2386,6 +2386,7 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2386
2386
|
let price = accessoryButtons[0]
|
|
2387
2387
|
price.isUserInteractionEnabled = false
|
|
2388
2388
|
price.isHidden = false
|
|
2389
|
+
price.setAttributedTitle(nil, for: .normal)
|
|
2389
2390
|
price.setTitle(item.data.string("price"), for: .normal)
|
|
2390
2391
|
applyMarketButtonStyle(price, data: style?.dictionary("price"), defaultSize: 16, defaultLineHeight: 24, defaultWeight: .medium, color: nativeListColor(theme, "primaryText", "#202020"), defaultAlignment: .trailing)
|
|
2391
2392
|
if !item.data.dictionaries("priceSegments").isEmpty {
|
|
@@ -2395,6 +2396,7 @@ final class NativeListCell: UICollectionViewCell {
|
|
|
2395
2396
|
let change = accessoryButtons[1]
|
|
2396
2397
|
change.isUserInteractionEnabled = false
|
|
2397
2398
|
change.isHidden = false
|
|
2399
|
+
change.setAttributedTitle(nil, for: .normal)
|
|
2398
2400
|
change.setTitle(changeData.string("text"), for: .normal)
|
|
2399
2401
|
let defaultChangeColor = nativeListColor(theme, "inverseText", "#FFFFFF")
|
|
2400
2402
|
applyMarketButtonStyle(change, data: style?.dictionary("change"), defaultSize: 14, defaultLineHeight: 20, defaultWeight: .medium, color: UIColor(nativeListHex: changeData.string("textColor", default: "#FFFFFF"), fallback: defaultChangeColor), defaultAlignment: .center)
|
|
@@ -64,7 +64,7 @@ final class NativeListView: UIView {
|
|
|
64
64
|
private let footerContainer = UIView()
|
|
65
65
|
private let footerCell = NativeListCell(frame: .zero)
|
|
66
66
|
private let sectionIndexView = NativeListSectionIndexView()
|
|
67
|
-
private let sectionIndexPreview =
|
|
67
|
+
private let sectionIndexPreview = NativeListSectionIndexPreviewView()
|
|
68
68
|
private var footerHeightConstraint: NSLayoutConstraint!
|
|
69
69
|
private var dataSource: UICollectionViewDiffableDataSource<Int, String>!
|
|
70
70
|
private var config: NativeListConfig?
|
|
@@ -106,7 +106,8 @@ final class NativeListView: UIView {
|
|
|
106
106
|
|
|
107
107
|
private static let sectionIndexContentInset: CGFloat = 16
|
|
108
108
|
private static let sectionIndexRailWidth: CGFloat = 32
|
|
109
|
-
private static let
|
|
109
|
+
private static let sectionIndexPreviewWidth: CGFloat = 60
|
|
110
|
+
private static let sectionIndexPreviewHeight: CGFloat = 50
|
|
110
111
|
private static let sectionIndexPreviewEndMargin: CGFloat = 40
|
|
111
112
|
|
|
112
113
|
override init(frame: CGRect) {
|
|
@@ -166,8 +167,8 @@ final class NativeListView: UIView {
|
|
|
166
167
|
constant: -Self.sectionIndexPreviewEndMargin
|
|
167
168
|
),
|
|
168
169
|
sectionIndexPreview.centerYAnchor.constraint(equalTo: collectionView.centerYAnchor),
|
|
169
|
-
sectionIndexPreview.widthAnchor.constraint(equalToConstant: Self.
|
|
170
|
-
sectionIndexPreview.heightAnchor.constraint(equalToConstant: Self.
|
|
170
|
+
sectionIndexPreview.widthAnchor.constraint(equalToConstant: Self.sectionIndexPreviewWidth),
|
|
171
|
+
sectionIndexPreview.heightAnchor.constraint(equalToConstant: Self.sectionIndexPreviewHeight),
|
|
171
172
|
])
|
|
172
173
|
|
|
173
174
|
sectionIndexView.isHidden = true
|
|
@@ -179,11 +180,6 @@ final class NativeListView: UIView {
|
|
|
179
180
|
}
|
|
180
181
|
sectionIndexPreview.isHidden = true
|
|
181
182
|
sectionIndexPreview.alpha = 0
|
|
182
|
-
sectionIndexPreview.layer.cornerRadius = 14
|
|
183
|
-
sectionIndexPreview.layer.masksToBounds = true
|
|
184
|
-
sectionIndexPreview.textAlignment = .center
|
|
185
|
-
sectionIndexPreview.adjustsFontForContentSizeCategory = true
|
|
186
|
-
sectionIndexPreview.font = nativeListFont(ofSize: 22, weight: .semibold)
|
|
187
183
|
sectionIndexPreview.isAccessibilityElement = false
|
|
188
184
|
|
|
189
185
|
footerCell.onAction = { [weak self] item, action, target, origin in
|
|
@@ -900,18 +896,21 @@ final class NativeListView: UIView {
|
|
|
900
896
|
sectionIndexHapticsEnabled = config.sectionIndexHapticsEnabled
|
|
901
897
|
sectionIndexView.configure(
|
|
902
898
|
titles: sectionIndexEntries.map(\.title),
|
|
903
|
-
textColor: nativeListColor(config.theme, "
|
|
904
|
-
activeColor: nativeListColor(config.theme, "
|
|
899
|
+
textColor: nativeListColor(config.theme, "disabledText", "#8D8D8D"),
|
|
900
|
+
activeColor: nativeListColor(config.theme, "positive", "#218358"),
|
|
905
901
|
activeTextColor: nativeListColor(config.theme, "inverseText", "#FCFCFC"),
|
|
906
902
|
centeredInWindow: config.sectionIndexCenteredInWindow
|
|
907
903
|
)
|
|
908
904
|
sectionIndexView.isHidden = sectionIndexEntries.isEmpty
|
|
909
|
-
sectionIndexPreview.
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
905
|
+
sectionIndexPreview.configure(
|
|
906
|
+
fillColor: UIColor(
|
|
907
|
+
red: 202.0 / 255.0,
|
|
908
|
+
green: 202.0 / 255.0,
|
|
909
|
+
blue: 202.0 / 255.0,
|
|
910
|
+
alpha: 1
|
|
911
|
+
),
|
|
912
|
+
textColor: .white
|
|
913
913
|
)
|
|
914
|
-
sectionIndexPreview.textColor = nativeListColor(config.theme, "inverseText", "#FCFCFC")
|
|
915
914
|
if let previousKey,
|
|
916
915
|
let index = sectionIndexEntries.firstIndex(where: { $0.key == previousKey }) {
|
|
917
916
|
sectionIndexView.setActiveIndex(index)
|
|
@@ -930,6 +929,7 @@ final class NativeListView: UIView {
|
|
|
930
929
|
if interacting {
|
|
931
930
|
sectionIndexPreview.layer.removeAllAnimations()
|
|
932
931
|
sectionIndexPreview.text = entry.title
|
|
932
|
+
positionSectionIndexPreview(at: sectionIndexView.centerY(for: index))
|
|
933
933
|
sectionIndexPreview.isHidden = false
|
|
934
934
|
sectionIndexPreview.alpha = 1
|
|
935
935
|
if changed && sectionIndexHapticsEnabled {
|
|
@@ -958,6 +958,23 @@ final class NativeListView: UIView {
|
|
|
958
958
|
}
|
|
959
959
|
}
|
|
960
960
|
|
|
961
|
+
private func positionSectionIndexPreview(at sectionIndexY: CGFloat) {
|
|
962
|
+
layoutIfNeeded()
|
|
963
|
+
let targetY = sectionIndexView.convert(
|
|
964
|
+
CGPoint(x: sectionIndexView.bounds.midX, y: sectionIndexY),
|
|
965
|
+
to: self
|
|
966
|
+
).y
|
|
967
|
+
let safeFrame = safeAreaLayoutGuide.layoutFrame
|
|
968
|
+
let halfHeight = Self.sectionIndexPreviewHeight / 2
|
|
969
|
+
let minimumY = safeFrame.minY + halfHeight
|
|
970
|
+
let maximumY = max(minimumY, safeFrame.maxY - halfHeight)
|
|
971
|
+
let clampedY = targetY.clamped(to: minimumY...maximumY)
|
|
972
|
+
sectionIndexPreview.transform = CGAffineTransform(
|
|
973
|
+
translationX: 0,
|
|
974
|
+
y: clampedY - sectionIndexPreview.center.y
|
|
975
|
+
)
|
|
976
|
+
}
|
|
977
|
+
|
|
961
978
|
private func syncSectionIndexToVisibleRows() {
|
|
962
979
|
guard !sectionIndexScrubbing, !sectionIndexEntries.isEmpty else { return }
|
|
963
980
|
let firstVisible = collectionView.indexPathsForVisibleItems.map(\.item).min() ?? 0
|
|
@@ -1826,9 +1843,81 @@ private struct NativeListSectionIndexEntry {
|
|
|
1826
1843
|
let position: Int
|
|
1827
1844
|
}
|
|
1828
1845
|
|
|
1846
|
+
private final class NativeListSectionIndexPreviewView: UIView {
|
|
1847
|
+
private let shapeLayer = CAShapeLayer()
|
|
1848
|
+
private let label = UILabel()
|
|
1849
|
+
|
|
1850
|
+
var text: String? {
|
|
1851
|
+
get { label.text }
|
|
1852
|
+
set { label.text = newValue }
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
override init(frame: CGRect) {
|
|
1856
|
+
super.init(frame: frame)
|
|
1857
|
+
isUserInteractionEnabled = false
|
|
1858
|
+
backgroundColor = .clear
|
|
1859
|
+
layer.addSublayer(shapeLayer)
|
|
1860
|
+
label.textAlignment = .center
|
|
1861
|
+
label.adjustsFontForContentSizeCategory = true
|
|
1862
|
+
label.font = nativeListFont(ofSize: 30)
|
|
1863
|
+
label.isAccessibilityElement = false
|
|
1864
|
+
addSubview(label)
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
required init?(coder: NSCoder) {
|
|
1868
|
+
fatalError("init(coder:) has not been implemented")
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
func configure(fillColor: UIColor, textColor: UIColor) {
|
|
1872
|
+
shapeLayer.fillColor = fillColor.cgColor
|
|
1873
|
+
label.textColor = textColor
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
override func layoutSubviews() {
|
|
1877
|
+
super.layoutSubviews()
|
|
1878
|
+
let height = bounds.height
|
|
1879
|
+
let bodyWidth = min(height, max(0, bounds.width - 10))
|
|
1880
|
+
let midY = height / 2
|
|
1881
|
+
let bodyMidX = bodyWidth / 2
|
|
1882
|
+
let shoulderX = bodyWidth * 0.92
|
|
1883
|
+
let path = UIBezierPath()
|
|
1884
|
+
path.move(to: CGPoint(x: bodyMidX, y: 0))
|
|
1885
|
+
path.addCurve(
|
|
1886
|
+
to: CGPoint(x: 0, y: midY),
|
|
1887
|
+
controlPoint1: CGPoint(x: bodyWidth * 0.22, y: 0),
|
|
1888
|
+
controlPoint2: CGPoint(x: 0, y: height * 0.22)
|
|
1889
|
+
)
|
|
1890
|
+
path.addCurve(
|
|
1891
|
+
to: CGPoint(x: bodyMidX, y: height),
|
|
1892
|
+
controlPoint1: CGPoint(x: 0, y: height * 0.78),
|
|
1893
|
+
controlPoint2: CGPoint(x: bodyWidth * 0.22, y: height)
|
|
1894
|
+
)
|
|
1895
|
+
path.addCurve(
|
|
1896
|
+
to: CGPoint(x: shoulderX, y: height * 0.75),
|
|
1897
|
+
controlPoint1: CGPoint(x: bodyWidth * 0.72, y: height),
|
|
1898
|
+
controlPoint2: CGPoint(x: bodyWidth * 0.86, y: height * 0.88)
|
|
1899
|
+
)
|
|
1900
|
+
path.addLine(to: CGPoint(x: bounds.width, y: midY))
|
|
1901
|
+
path.addLine(to: CGPoint(x: shoulderX, y: height * 0.25))
|
|
1902
|
+
path.addCurve(
|
|
1903
|
+
to: CGPoint(x: bodyMidX, y: 0),
|
|
1904
|
+
controlPoint1: CGPoint(x: bodyWidth * 0.86, y: height * 0.12),
|
|
1905
|
+
controlPoint2: CGPoint(x: bodyWidth * 0.72, y: 0)
|
|
1906
|
+
)
|
|
1907
|
+
path.close()
|
|
1908
|
+
shapeLayer.frame = bounds
|
|
1909
|
+
shapeLayer.path = path.cgPath
|
|
1910
|
+
label.frame = CGRect(x: 0, y: 0, width: bodyWidth, height: height)
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1829
1914
|
// OneKey patch: arbitrate index scrubbing against ancestor dismissal gestures.
|
|
1830
1915
|
// private final class NativeListSectionIndexView: UIControl {
|
|
1831
1916
|
private final class NativeListSectionIndexView: UIControl, UIGestureRecognizerDelegate {
|
|
1917
|
+
private static let edgePadding: CGFloat = 8
|
|
1918
|
+
private static let labelSize: CGFloat = 14
|
|
1919
|
+
private static let labelSpacing: CGFloat = 16
|
|
1920
|
+
|
|
1832
1921
|
var onSelect: ((Int, Bool) -> Void)?
|
|
1833
1922
|
var onInteractionEnded: (() -> Void)?
|
|
1834
1923
|
private var titles: [String] = []
|
|
@@ -1911,16 +2000,28 @@ private final class NativeListSectionIndexView: UIControl, UIGestureRecognizerDe
|
|
|
1911
2000
|
override func layoutSubviews() {
|
|
1912
2001
|
super.layoutSubviews()
|
|
1913
2002
|
guard !labels.isEmpty else { return }
|
|
1914
|
-
let
|
|
1915
|
-
let
|
|
1916
|
-
|
|
2003
|
+
let metrics = indexMetrics(count: labels.count)
|
|
2004
|
+
let visibleIndices = visibleLabelIndices(
|
|
2005
|
+
count: labels.count,
|
|
2006
|
+
trackHeight: metrics.trackHeight
|
|
2007
|
+
)
|
|
2008
|
+
labels.forEach { $0.isHidden = true }
|
|
2009
|
+
for (visibleIndex, index) in visibleIndices.sorted().enumerated() {
|
|
2010
|
+
let label = labels[index]
|
|
2011
|
+
label.isHidden = false
|
|
2012
|
+
let centerY = visibleLabelCenterY(
|
|
2013
|
+
visibleIndex: visibleIndex,
|
|
2014
|
+
visibleCount: visibleIndices.count,
|
|
2015
|
+
metrics: metrics
|
|
2016
|
+
)
|
|
1917
2017
|
label.frame = CGRect(
|
|
1918
|
-
x:
|
|
1919
|
-
y:
|
|
1920
|
-
width:
|
|
1921
|
-
height:
|
|
2018
|
+
x: bounds.width - Self.labelSize - 3,
|
|
2019
|
+
y: centerY - Self.labelSize / 2,
|
|
2020
|
+
width: Self.labelSize,
|
|
2021
|
+
height: Self.labelSize
|
|
1922
2022
|
)
|
|
1923
2023
|
}
|
|
2024
|
+
updateLabelStyles()
|
|
1924
2025
|
}
|
|
1925
2026
|
|
|
1926
2027
|
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
|
@@ -1957,25 +2058,75 @@ private final class NativeListSectionIndexView: UIControl, UIGestureRecognizerDe
|
|
|
1957
2058
|
}
|
|
1958
2059
|
|
|
1959
2060
|
private func select(at y: CGFloat, interacting: Bool) {
|
|
1960
|
-
let
|
|
1961
|
-
|
|
1962
|
-
let
|
|
2061
|
+
let metrics = indexMetrics(count: titles.count)
|
|
2062
|
+
guard metrics.trackHeight > 0 else { return }
|
|
2063
|
+
let visibleIndices = visibleLabelIndices(
|
|
2064
|
+
count: titles.count,
|
|
2065
|
+
trackHeight: metrics.trackHeight
|
|
2066
|
+
).sorted()
|
|
2067
|
+
let visibleTrackHeight = min(
|
|
2068
|
+
metrics.trackHeight,
|
|
2069
|
+
Self.labelSpacing * CGFloat(visibleIndices.count)
|
|
2070
|
+
)
|
|
2071
|
+
let visibleOriginY = metrics.originY + (metrics.trackHeight - visibleTrackHeight) / 2
|
|
2072
|
+
let progress = ((y - visibleOriginY) / visibleTrackHeight).clamped(to: 0...1)
|
|
2073
|
+
let slot = Int(floor(progress * CGFloat(visibleIndices.count)))
|
|
2074
|
+
.clamped(to: 0...(visibleIndices.count - 1))
|
|
2075
|
+
let index = visibleIndices[slot]
|
|
1963
2076
|
if interacting && lastTouchIndex == index { return }
|
|
1964
2077
|
lastTouchIndex = interacting ? index : nil
|
|
1965
2078
|
select(index: index, interacting: interacting)
|
|
1966
2079
|
}
|
|
1967
2080
|
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2081
|
+
func centerY(for index: Int) -> CGFloat {
|
|
2082
|
+
entryCenterY(index: index, metrics: indexMetrics(count: titles.count))
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
private func indexMetrics(count: Int) -> (originY: CGFloat, trackHeight: CGFloat) {
|
|
2086
|
+
guard count > 0 else { return (bounds.midY, 0) }
|
|
2087
|
+
let availableHeight = max(0, bounds.height - Self.edgePadding * 2)
|
|
2088
|
+
let trackHeight = min(availableHeight, Self.labelSpacing * CGFloat(count))
|
|
2089
|
+
let centeredOriginY = (bounds.height - trackHeight) / 2
|
|
2090
|
+
guard centeredInWindow, let window else { return (centeredOriginY, trackHeight) }
|
|
1972
2091
|
let windowCenterY = window.safeAreaLayoutGuide.layoutFrame.midY
|
|
1973
2092
|
let localCenterY = convert(CGPoint(x: 0, y: windowCenterY), from: window).y
|
|
1974
|
-
return (
|
|
1975
|
-
|
|
2093
|
+
return (
|
|
2094
|
+
(localCenterY - trackHeight / 2).clamped(
|
|
2095
|
+
to: Self.edgePadding...max(Self.edgePadding, bounds.height - Self.edgePadding - trackHeight)
|
|
2096
|
+
),
|
|
2097
|
+
trackHeight
|
|
1976
2098
|
)
|
|
1977
2099
|
}
|
|
1978
2100
|
|
|
2101
|
+
private func entryCenterY(
|
|
2102
|
+
index: Int,
|
|
2103
|
+
metrics: (originY: CGFloat, trackHeight: CGFloat)
|
|
2104
|
+
) -> CGFloat {
|
|
2105
|
+
guard !titles.isEmpty else { return bounds.midY }
|
|
2106
|
+
return metrics.originY + metrics.trackHeight * (CGFloat(index) + 0.5) / CGFloat(titles.count)
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
private func visibleLabelCenterY(
|
|
2110
|
+
visibleIndex: Int,
|
|
2111
|
+
visibleCount: Int,
|
|
2112
|
+
metrics: (originY: CGFloat, trackHeight: CGFloat)
|
|
2113
|
+
) -> CGFloat {
|
|
2114
|
+
let visibleTrackHeight = min(metrics.trackHeight, Self.labelSpacing * CGFloat(visibleCount))
|
|
2115
|
+
let visibleOriginY = metrics.originY + (metrics.trackHeight - visibleTrackHeight) / 2
|
|
2116
|
+
return visibleOriginY
|
|
2117
|
+
+ visibleTrackHeight * (CGFloat(visibleIndex) + 0.5) / CGFloat(max(visibleCount, 1))
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
private func visibleLabelIndices(count: Int, trackHeight: CGFloat) -> Set<Int> {
|
|
2121
|
+
guard count > 0 else { return [] }
|
|
2122
|
+
let maxVisible = max(1, Int(floor(trackHeight / Self.labelSpacing)))
|
|
2123
|
+
guard count > maxVisible else { return Set(0..<count) }
|
|
2124
|
+
guard maxVisible > 1 else { return [0] }
|
|
2125
|
+
return Set((0..<maxVisible).map { slot in
|
|
2126
|
+
Int(round(CGFloat(slot * (count - 1)) / CGFloat(maxVisible - 1)))
|
|
2127
|
+
})
|
|
2128
|
+
}
|
|
2129
|
+
|
|
1979
2130
|
private func select(index: Int, interacting: Bool) {
|
|
1980
2131
|
onSelect?(index, interacting)
|
|
1981
2132
|
setActiveIndex(index)
|
|
@@ -1983,12 +2134,12 @@ private final class NativeListSectionIndexView: UIControl, UIGestureRecognizerDe
|
|
|
1983
2134
|
|
|
1984
2135
|
private func updateLabelStyles() {
|
|
1985
2136
|
for (index, label) in labels.enumerated() {
|
|
1986
|
-
let active = index == activeIndex
|
|
2137
|
+
let active = index == activeIndex && !label.isHidden
|
|
1987
2138
|
label.textColor = active ? activeTextColor : textColor
|
|
1988
2139
|
label.backgroundColor = active ? activeColor : .clear
|
|
1989
|
-
label.layer.cornerRadius =
|
|
2140
|
+
label.layer.cornerRadius = Self.labelSize / 2
|
|
1990
2141
|
label.layer.masksToBounds = active
|
|
1991
|
-
label.font = nativeListFont(ofSize: 10, weight: active ? .
|
|
2142
|
+
label.font = nativeListFont(ofSize: 10, weight: active ? .medium : .regular)
|
|
1992
2143
|
}
|
|
1993
2144
|
}
|
|
1994
2145
|
}
|