@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.
@@ -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 = UILabel()
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 sectionIndexPreviewSize: CGFloat = 48
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.sectionIndexPreviewSize),
170
- sectionIndexPreview.heightAnchor.constraint(equalToConstant: Self.sectionIndexPreviewSize),
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, "secondaryText", "#646464"),
904
- activeColor: nativeListColor(config.theme, "accent", "#108303"),
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.backgroundColor = nativeListColor(
910
- config.theme,
911
- "inverseBackground",
912
- "#202020"
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 height = min(16, max(8, bounds.height / CGFloat(labels.count)))
1915
- let originY = indexOriginY(cellHeight: height, count: labels.count)
1916
- for (index, label) in labels.enumerated() {
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: 6,
1919
- y: originY + CGFloat(index) * height,
1920
- width: 20,
1921
- height: 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 height = min(16, max(8, bounds.height / CGFloat(titles.count)))
1961
- let originY = indexOriginY(cellHeight: height, count: titles.count)
1962
- let index = Int(floor((y - originY) / height)).clamped(to: 0...(titles.count - 1))
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
- private func indexOriginY(cellHeight: CGFloat, count: Int) -> CGFloat {
1969
- let totalHeight = cellHeight * CGFloat(count)
1970
- let centeredOriginY = (bounds.height - totalHeight) / 2
1971
- guard centeredInWindow, let window else { return centeredOriginY }
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 (localCenterY - totalHeight / 2).clamped(
1975
- to: 0...max(0, bounds.height - totalHeight)
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 = 8
2140
+ label.layer.cornerRadius = Self.labelSize / 2
1990
2141
  label.layer.masksToBounds = active
1991
- label.font = nativeListFont(ofSize: 10, weight: active ? .semibold : .medium)
2142
+ label.font = nativeListFont(ofSize: 10, weight: active ? .medium : .regular)
1992
2143
  }
1993
2144
  }
1994
2145
  }