basic scrollview on the native side
This commit is contained in:
@@ -20,7 +20,6 @@ public class BottomSheetModule: Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AsyncFunction("updateLayout") { (view: SheetView) in
|
AsyncFunction("updateLayout") { (view: SheetView) in
|
||||||
view.updateLayout()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Prop("containerBackgroundColor") { (view: SheetView, prop: UIColor) in
|
Prop("containerBackgroundColor") { (view: SheetView, prop: UIColor) in
|
||||||
|
|||||||
@@ -6,30 +6,97 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
class BottomSheetScrollView: UIScrollView, UIScrollViewDelegate {
|
class BottomSheetScrollView: UIScrollView, UIScrollViewDelegate {
|
||||||
|
private let sheetView: SheetView
|
||||||
private var previousHeight: CGFloat?
|
private var previousHeight: CGFloat?
|
||||||
|
private var beganDraggingY: CGFloat?
|
||||||
|
|
||||||
init() {
|
init(sheetView: SheetView) {
|
||||||
|
self.sheetView = sheetView
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
if let window = Util.getWindow() {
|
if let window = Util.getWindow() {
|
||||||
self.frame = window.bounds
|
self.frame = window.bounds
|
||||||
self.contentInset = UIEdgeInsets(top: 0,
|
let offset = window.safeAreaInsets.bottom * 3
|
||||||
left: 0,
|
self.contentInset.bottom = offset
|
||||||
bottom: window.safeAreaInsets.bottom,
|
self.verticalScrollIndicatorInsets.top = 20
|
||||||
right: 0)
|
self.verticalScrollIndicatorInsets.bottom = offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.delegate = self
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self,
|
||||||
|
selector: #selector(keyboardWillShow(notification:)),
|
||||||
|
name: UIResponder.keyboardWillShowNotification,
|
||||||
|
object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self,
|
||||||
|
selector: #selector(keyboardWillHide(notification:)),
|
||||||
|
name: UIResponder.keyboardWillHideNotification,
|
||||||
|
object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
override func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
if let height = self.subviews.first?.frame.size.height,
|
if let height = self.subviews.first?.frame.size.height,
|
||||||
self.previousHeight != height,
|
self.previousHeight != height,
|
||||||
let window = self.window {
|
let window = self.window {
|
||||||
self.contentSize = CGSize(width: window.bounds.width, height: height + window.safeAreaInsets.bottom)
|
let newDetent = self.sheetView.sheetVc.updateDetents(contentHeight: self.sheetView.clampHeight(height),
|
||||||
|
preventExpansion: self.sheetView.preventExpansion)
|
||||||
|
self.sheetView.selectedDetentIdentifier = newDetent
|
||||||
|
self.contentSize = CGSize(width: window.bounds.width, height: height)
|
||||||
|
self.previousHeight = height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func keyboardWillShow(notification: Notification) {
|
||||||
|
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
|
||||||
|
let keyboardHeight = keyboardFrame.height
|
||||||
|
let newOffset = self.contentInset.bottom + keyboardHeight
|
||||||
|
|
||||||
|
// We purposefully add keyboard height to content inset and only update
|
||||||
|
// the scroll indicator inset
|
||||||
|
self.contentInset.bottom = newOffset
|
||||||
|
self.verticalScrollIndicatorInsets.bottom = keyboardHeight
|
||||||
|
|
||||||
|
if let firstResponder = self.findFirstResponder(),
|
||||||
|
let window = self.window {
|
||||||
|
let position = firstResponder.convert(firstResponder.bounds,
|
||||||
|
to: window)
|
||||||
|
|
||||||
|
if position.minY > window.bounds.height - keyboardHeight {
|
||||||
|
self.setContentOffset(CGPoint(x: 0, y: self.contentOffset.y + keyboardHeight),
|
||||||
|
animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func keyboardWillHide(notification: Notification) {
|
||||||
|
if let window = Util.getWindow() {
|
||||||
|
let offset = window.safeAreaInsets.bottom * 3
|
||||||
|
self.contentInset.bottom = offset
|
||||||
|
self.verticalScrollIndicatorInsets.bottom = offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||||
|
self.beganDraggingY = self.contentOffset.y
|
||||||
|
}
|
||||||
|
|
||||||
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
|
if let beganDraggingY = self.beganDraggingY,
|
||||||
|
self.contentOffset.y < beganDraggingY {
|
||||||
|
if let firstResponder = self.findFirstResponder() {
|
||||||
|
firstResponder.resignFirstResponder()
|
||||||
|
}
|
||||||
|
self.beganDraggingY = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// UIView+findFirstResponder.swift
|
||||||
|
// Pods
|
||||||
|
//
|
||||||
|
// Created by Hailey on 10/9/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
extension UIView {
|
||||||
|
func findFirstResponder() -> UIView? {
|
||||||
|
if self.isFirstResponder {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
for subview in subviews {
|
||||||
|
if let responder = subview.findFirstResponder() {
|
||||||
|
return responder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,13 +3,8 @@ import UIKit
|
|||||||
|
|
||||||
class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
||||||
// Views
|
// Views
|
||||||
private var sheetVc: SheetViewController!
|
var sheetVc: SheetViewController!
|
||||||
private var innerView: UIView?
|
private var innerView: UIView?
|
||||||
private var contentHeight: CGFloat? {
|
|
||||||
get {
|
|
||||||
self.innerView?.frame.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll view
|
// Scroll view
|
||||||
private var scrollView: BottomSheetScrollView!
|
private var scrollView: BottomSheetScrollView!
|
||||||
@@ -59,6 +54,7 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isClosing = false {
|
private var isClosing = false {
|
||||||
didSet {
|
didSet {
|
||||||
if isClosing {
|
if isClosing {
|
||||||
@@ -68,7 +64,8 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private var selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier? {
|
|
||||||
|
var selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier? {
|
||||||
didSet {
|
didSet {
|
||||||
if selectedDetentIdentifier == .large {
|
if selectedDetentIdentifier == .large {
|
||||||
onSnapPointChange([
|
onSnapPointChange([
|
||||||
@@ -89,12 +86,12 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
|||||||
required init (appContext: AppContext? = nil) {
|
required init (appContext: AppContext? = nil) {
|
||||||
super.init(appContext: appContext)
|
super.init(appContext: appContext)
|
||||||
|
|
||||||
self.scrollView = BottomSheetScrollView()
|
|
||||||
|
|
||||||
self.sheetVc = SheetViewController()
|
self.sheetVc = SheetViewController()
|
||||||
if let sheet = self.sheetVc.sheetPresentationController {
|
if let sheet = self.sheetVc.sheetPresentationController {
|
||||||
sheet.delegate = self
|
sheet.delegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.scrollView = BottomSheetScrollView(sheetView: self)
|
||||||
self.sheetVc.view.addSubview(self.scrollView)
|
self.sheetVc.view.addSubview(self.scrollView)
|
||||||
|
|
||||||
self.touchHandler = RCTTouchHandler(bridge: appContext?.reactBridge)
|
self.touchHandler = RCTTouchHandler(bridge: appContext?.reactBridge)
|
||||||
@@ -132,12 +129,10 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
|||||||
guard !self.isOpen,
|
guard !self.isOpen,
|
||||||
!self.isOpening,
|
!self.isOpening,
|
||||||
!self.isClosing,
|
!self.isClosing,
|
||||||
let contentHeight = self.contentHeight,
|
|
||||||
let rvc = self.reactViewController() else {
|
let rvc = self.reactViewController() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sheetVc.setDetents(contentHeight: self.clampHeight(contentHeight), preventExpansion: self.preventExpansion)
|
|
||||||
if let sheet = sheetVc.sheetPresentationController {
|
if let sheet = sheetVc.sheetPresentationController {
|
||||||
sheet.preferredCornerRadius = self.cornerRadius
|
sheet.preferredCornerRadius = self.cornerRadius
|
||||||
self.selectedDetentIdentifier = sheet.selectedDetentIdentifier
|
self.selectedDetentIdentifier = sheet.selectedDetentIdentifier
|
||||||
@@ -151,16 +146,6 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout() {
|
|
||||||
if self.prevLayoutDetentIdentifier == self.selectedDetentIdentifier,
|
|
||||||
let contentHeight = self.contentHeight {
|
|
||||||
self.sheetVc.updateDetents(contentHeight: self.clampHeight(contentHeight),
|
|
||||||
preventExpansion: self.preventExpansion)
|
|
||||||
self.selectedDetentIdentifier = self.sheetVc.getCurrentDetentIdentifier()
|
|
||||||
}
|
|
||||||
self.prevLayoutDetentIdentifier = self.selectedDetentIdentifier
|
|
||||||
}
|
|
||||||
|
|
||||||
func dismiss() {
|
func dismiss() {
|
||||||
self.isClosing = true
|
self.isClosing = true
|
||||||
self.sheetVc.dismiss(animated: true) { [weak self] in
|
self.sheetVc.dismiss(animated: true) { [weak self] in
|
||||||
@@ -170,7 +155,7 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
|
|||||||
|
|
||||||
// MARK: - Utils
|
// MARK: - Utils
|
||||||
|
|
||||||
private func clampHeight(_ height: CGFloat) -> CGFloat {
|
func clampHeight(_ height: CGFloat) -> CGFloat {
|
||||||
if height < self.minHeight {
|
if height < self.minHeight {
|
||||||
return self.minHeight
|
return self.minHeight
|
||||||
} else if height > self.maxHeight {
|
} else if height > self.maxHeight {
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ class SheetViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDetents(contentHeight: CGFloat, preventExpansion: Bool) {
|
func setDetents(contentHeight: CGFloat, preventExpansion: Bool) -> UISheetPresentationController.Detent.Identifier? {
|
||||||
guard let sheet = self.sheetPresentationController else {
|
guard let sheet = self.sheetPresentationController else {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if contentHeight > Util.getScreenHeight() - 100 {
|
if contentHeight > Util.getScreenHeight() - 100 {
|
||||||
@@ -48,17 +48,20 @@ class SheetViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
sheet.selectedDetentIdentifier = .medium
|
sheet.selectedDetentIdentifier = .medium
|
||||||
}
|
}
|
||||||
|
return sheet.selectedDetentIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateDetents(contentHeight: CGFloat, preventExpansion: Bool) {
|
func updateDetents(contentHeight: CGFloat, preventExpansion: Bool) -> UISheetPresentationController.Detent.Identifier? {
|
||||||
|
var newDetent: UISheetPresentationController.Detent.Identifier?
|
||||||
if let sheet = self.sheetPresentationController {
|
if let sheet = self.sheetPresentationController {
|
||||||
sheet.animateChanges {
|
sheet.animateChanges {
|
||||||
self.setDetents(contentHeight: contentHeight, preventExpansion: preventExpansion)
|
newDetent = self.setDetents(contentHeight: contentHeight, preventExpansion: preventExpansion)
|
||||||
if #available(iOS 16.0, *) {
|
if #available(iOS 16.0, *) {
|
||||||
sheet.invalidateDetents()
|
sheet.invalidateDetents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return newDetent
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrentDetentIdentifier() -> UISheetPresentationController.Detent.Identifier? {
|
func getCurrentDetentIdentifier() -> UISheetPresentationController.Detent.Identifier? {
|
||||||
|
|||||||
@@ -2,10 +2,7 @@ import * as React from 'react'
|
|||||||
import {
|
import {
|
||||||
Dimensions,
|
Dimensions,
|
||||||
NativeSyntheticEvent,
|
NativeSyntheticEvent,
|
||||||
Platform,
|
|
||||||
ScrollView,
|
|
||||||
StyleProp,
|
StyleProp,
|
||||||
View,
|
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core'
|
import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core'
|
||||||
@@ -66,7 +63,6 @@ export class BottomSheetNativeComponent extends React.Component<
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {children, ...rest} = this.props
|
const {children, ...rest} = this.props
|
||||||
const cornerRadius = rest.cornerRadius ?? 0
|
|
||||||
|
|
||||||
if (!this.state.open) {
|
if (!this.state.open) {
|
||||||
return null
|
return null
|
||||||
@@ -82,19 +78,7 @@ export class BottomSheetNativeComponent extends React.Component<
|
|||||||
height: screenHeight,
|
height: screenHeight,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}>
|
}}>
|
||||||
{/*<View*/}
|
|
||||||
{/* style={[*/}
|
|
||||||
{/* {*/}
|
|
||||||
{/* flex: 1,*/}
|
|
||||||
{/* backgroundColor,*/}
|
|
||||||
{/* },*/}
|
|
||||||
{/* Platform.OS === 'android' && {*/}
|
|
||||||
{/* borderTopLeftRadius: cornerRadius,*/}
|
|
||||||
{/* borderTopRightRadius: cornerRadius,*/}
|
|
||||||
{/* },*/}
|
|
||||||
{/* ]}>*/}
|
|
||||||
<BottomSheetPortalProvider>{children}</BottomSheetPortalProvider>
|
<BottomSheetPortalProvider>{children}</BottomSheetPortalProvider>
|
||||||
{/*</View>*/}
|
|
||||||
</NativeView>
|
</NativeView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,17 @@
|
|||||||
import React, {useImperativeHandle} from 'react'
|
import React, {useImperativeHandle} from 'react'
|
||||||
import {
|
import {
|
||||||
NativeScrollEvent,
|
|
||||||
NativeSyntheticEvent,
|
|
||||||
Pressable,
|
Pressable,
|
||||||
processColor,
|
processColor,
|
||||||
ScrollView,
|
|
||||||
StyleProp,
|
StyleProp,
|
||||||
TextInput,
|
TextInput,
|
||||||
View,
|
View,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {
|
|
||||||
KeyboardAwareScrollView,
|
|
||||||
useKeyboardHandler,
|
|
||||||
} from 'react-native-keyboard-controller'
|
|
||||||
import {runOnJS} from 'react-native-reanimated'
|
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isAndroid, isIOS} from '#/platform/detection'
|
|
||||||
import {useA11y} from '#/state/a11y'
|
import {useA11y} from '#/state/a11y'
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||||
import {List, ListMethods, ListProps} from '#/view/com/util/List'
|
import {List, ListMethods, ListProps} from '#/view/com/util/List'
|
||||||
@@ -161,6 +152,7 @@ export function Outer({
|
|||||||
onSnapPointChange={onSnapPointChange}
|
onSnapPointChange={onSnapPointChange}
|
||||||
onStateChange={onStateChange}
|
onStateChange={onStateChange}
|
||||||
disableDrag={disableDrag}
|
disableDrag={disableDrag}
|
||||||
|
// @ts-expect-error @TODO
|
||||||
containerBackgroundColor={processColor(t.atoms.bg.backgroundColor)}>
|
containerBackgroundColor={processColor(t.atoms.bg.backgroundColor)}>
|
||||||
<Context.Provider value={context}>
|
<Context.Provider value={context}>
|
||||||
<View testID={testID}>{children}</View>
|
<View testID={testID}>{children}</View>
|
||||||
@@ -169,69 +161,16 @@ export function Outer({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Inner({children, style}: DialogInnerProps) {
|
export function Inner({children, style, ...props}: DialogInnerProps) {
|
||||||
const insets = useSafeAreaInsets()
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View style={[a.pt_2xl, a.px_xl, style]} {...props}>
|
||||||
style={[
|
|
||||||
a.pt_2xl,
|
|
||||||
a.px_xl,
|
|
||||||
{
|
|
||||||
paddingBottom: insets.bottom + insets.top,
|
|
||||||
},
|
|
||||||
style,
|
|
||||||
]}>
|
|
||||||
{children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrollableInner = React.forwardRef<ScrollView, DialogInnerProps>(
|
// @TODO remove this later
|
||||||
function ScrollableInner({children, style, ...props}, ref) {
|
export const ScrollableInner = Inner
|
||||||
const {nativeSnapPoint, disableDrag, setDisableDrag} = useDialogContext()
|
|
||||||
const insets = useSafeAreaInsets()
|
|
||||||
const [keyboardHeight, setKeyboardHeight] = React.useState(0)
|
|
||||||
useKeyboardHandler({
|
|
||||||
onEnd: e => {
|
|
||||||
'worklet'
|
|
||||||
runOnJS(setKeyboardHeight)(e.height)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const basePading =
|
|
||||||
(isIOS ? 30 : 50) + (isIOS ? keyboardHeight / 4 : keyboardHeight)
|
|
||||||
const fullPaddingBase = insets.bottom + insets.top + basePading
|
|
||||||
const fullPadding = isIOS ? fullPaddingBase : fullPaddingBase + 50
|
|
||||||
|
|
||||||
const paddingBottom =
|
|
||||||
nativeSnapPoint === BottomSheetSnapPoint.Full ? fullPadding : basePading
|
|
||||||
|
|
||||||
const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
||||||
const {contentOffset} = e.nativeEvent
|
|
||||||
if (contentOffset.y > 0 && !disableDrag) {
|
|
||||||
setDisableDrag(true)
|
|
||||||
} else if (contentOffset.y <= 1 && disableDrag) {
|
|
||||||
setDisableDrag(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return children
|
|
||||||
|
|
||||||
return (
|
|
||||||
<KeyboardAwareScrollView
|
|
||||||
style={[style]}
|
|
||||||
contentContainerStyle={[a.pt_2xl, a.px_xl, {paddingBottom}]}
|
|
||||||
ref={ref}
|
|
||||||
{...props}
|
|
||||||
bounces={nativeSnapPoint === BottomSheetSnapPoint.Full}
|
|
||||||
bottomOffset={30}
|
|
||||||
scrollEventThrottle={50}
|
|
||||||
onScroll={isAndroid ? onScroll : undefined}>
|
|
||||||
{children}
|
|
||||||
</KeyboardAwareScrollView>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
export const InnerFlatList = React.forwardRef<
|
export const InnerFlatList = React.forwardRef<
|
||||||
ListMethods,
|
ListMethods,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Pressable, View} from 'react-native'
|
import {Pressable, View} from 'react-native'
|
||||||
import {ScrollView} from 'react-native-gesture-handler'
|
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
@@ -38,10 +37,8 @@ function ReportDialogInner(props: ReportDialogProps) {
|
|||||||
} = useMyLabelersQuery()
|
} = useMyLabelersQuery()
|
||||||
const isLoading = useDelayedLoading(500, isLabelerLoading)
|
const isLoading = useDelayedLoading(500, isLabelerLoading)
|
||||||
|
|
||||||
const ref = React.useRef<ScrollView>(null)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog.ScrollableInner label={_(msg`Report dialog`)} ref={ref}>
|
<Dialog.ScrollableInner label={_(msg`Report dialog`)}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<View style={[a.align_center, {height: 100}]}>
|
<View style={[a.align_center, {height: 100}]}>
|
||||||
<Loader size="xl" />
|
<Loader size="xl" />
|
||||||
|
|||||||
Reference in New Issue
Block a user