Add web linking and proper share controls

This commit is contained in:
Paul Frazee 2022-11-21 16:07:26 -06:00
parent 39058cd36a
commit ed146a582c
15 changed files with 50 additions and 243 deletions

View file

@ -1,72 +0,0 @@
import React from 'react'
import Toast from '../util/Toast'
import Clipboard from '@react-native-clipboard/clipboard'
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {useStores} from '../../../state'
import {s, colors} from '../../lib/styles'
export const snapPoints = ['30%']
export function Component({
title,
href,
newTab,
}: {
title: string
href: string
newTab: boolean
}) {
const store = useStores()
const onPressOpenNewTab = () => {
store.shell.closeModal()
store.nav.newTab(href)
}
const onPressCopy = () => {
Clipboard.setString(href)
store.shell.closeModal()
Toast.show('Link copied', {
position: Toast.positions.TOP,
})
}
return (
<View>
<Text style={[s.textCenter, s.bold, s.mb10, s.f16]}>{title || href}</Text>
<View style={s.p10}>
{newTab ? (
<TouchableOpacity onPress={onPressOpenNewTab} style={styles.btn}>
<FontAwesomeIcon
icon="arrow-up-right-from-square"
style={styles.icon}
/>
<Text style={[s.f16, s.black]}>Open in new tab</Text>
</TouchableOpacity>
) : undefined}
<TouchableOpacity onPress={onPressCopy} style={styles.btn}>
<FontAwesomeIcon icon="link" style={styles.icon} />
<Text style={[s.f16, s.black]}>Copy to clipboard</Text>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
btn: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
borderColor: colors.gray5,
borderWidth: 1,
borderRadius: 4,
padding: 10,
marginBottom: 10,
},
icon: {
marginRight: 8,
},
})

View file

@ -7,9 +7,7 @@ import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
import * as models from '../../../state/models/shell-ui'
import * as LinkActionsModal from './LinkActions'
import * as ConfirmModal from './Confirm'
import * as SharePostModal from './SharePost.native'
import * as EditProfileModal from './EditProfile'
import * as CreateSceneModal from './CreateScene'
import * as InviteToSceneModal from './InviteToScene'
@ -41,27 +39,13 @@ export const Modal = observer(function Modal() {
let snapPoints: (string | number)[] = CLOSED_SNAPPOINTS
let element
if (store.shell.activeModal?.name === 'link-actions') {
snapPoints = LinkActionsModal.snapPoints
element = (
<LinkActionsModal.Component
{...(store.shell.activeModal as models.LinkActionsModel)}
/>
)
} else if (store.shell.activeModal?.name === 'confirm') {
if (store.shell.activeModal?.name === 'confirm') {
snapPoints = ConfirmModal.snapPoints
element = (
<ConfirmModal.Component
{...(store.shell.activeModal as models.ConfirmModel)}
/>
)
} else if (store.shell.activeModal?.name === 'share-post') {
snapPoints = SharePostModal.snapPoints
element = (
<SharePostModal.Component
{...(store.shell.activeModal as models.SharePostModel)}
/>
)
} else if (store.shell.activeModal?.name === 'edit-profile') {
snapPoints = EditProfileModal.snapPoints
element = (

View file

@ -1,43 +0,0 @@
import React from 'react'
import {Button, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import Toast from '../util/Toast'
import Clipboard from '@react-native-clipboard/clipboard'
import {s} from '../../lib/styles'
import {useStores} from '../../../state'
export const snapPoints = ['30%']
export function Component({href}: {href: string}) {
const store = useStores()
const onPressCopy = () => {
Clipboard.setString(href)
Toast.show('Link copied', {
position: Toast.positions.TOP,
})
store.shell.closeModal()
}
const onClose = () => store.shell.closeModal()
return (
<View>
<Text style={[s.textCenter, s.bold, s.mb10]}>Share this post</Text>
<Text style={[s.textCenter, s.mb10]}>{href}</Text>
<Button title="Copy to clipboard" onPress={onPressCopy} />
<View style={s.p10}>
<TouchableOpacity onPress={onClose} style={styles.closeBtn}>
<Text style={s.textCenter}>Close</Text>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
closeBtn: {
width: '100%',
borderColor: '#000',
borderWidth: 1,
borderRadius: 4,
padding: 10,
},
})

View file

@ -1,57 +0,0 @@
import React, {forwardRef, useState, useImperativeHandle} from 'react'
import {Button, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {Modal} from './WebModal'
import Toast from '../util/Toast'
import {s} from '../../lib/styles'
export const ShareModal = forwardRef(function ShareModal({}: {}, ref) {
const [isOpen, setIsOpen] = useState<boolean>(false)
const [uri, setUri] = useState<string>('')
useImperativeHandle(ref, () => ({
open(uri: string) {
console.log('sharing', uri)
setUri(uri)
setIsOpen(true)
},
}))
const onPressCopy = () => {
// TODO
Toast.show('Link copied', {
position: Toast.positions.TOP,
})
}
const onClose = () => {
setIsOpen(false)
}
return (
<>
{isOpen && (
<Modal onClose={onClose}>
<View>
<Text style={[s.textCenter, s.bold, s.mb10]}>Share this post</Text>
<Text style={[s.textCenter, s.mb10]}>{uri}</Text>
<Button title="Copy to clipboard" onPress={onPressCopy} />
<View style={s.p10}>
<TouchableOpacity onPress={onClose} style={styles.closeBtn}>
<Text style={s.textCenter}>Close</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
)}
</>
)
})
const styles = StyleSheet.create({
closeBtn: {
width: '100%',
borderColor: '#000',
borderWidth: 1,
borderRadius: 4,
padding: 10,
},
})

View file

@ -6,7 +6,6 @@ import {
PostThreadViewPostModel,
} from '../../../state/models/post-thread-view'
import {useStores} from '../../../state'
import {SharePostModel} from '../../../state/models/shell-ui'
import {PostThreadItem} from './PostThreadItem'
import {ErrorMessage} from '../util/ErrorMessage'
@ -17,11 +16,6 @@ export const PostThread = observer(function PostThread({
uri: string
view: PostThreadViewModel
}) {
const store = useStores()
const onPressShare = (uri: string) => {
store.shell.openModal(new SharePostModel(uri))
}
const onRefresh = () => {
view?.refresh().catch(err => console.error('Failed to refresh', err))
}
@ -55,11 +49,7 @@ export const PostThread = observer(function PostThread({
// =
const posts = view.thread ? Array.from(flattenThread(view.thread)) : []
const renderItem = ({item}: {item: PostThreadViewPostModel}) => (
<PostThreadItem
item={item}
onPressShare={onPressShare}
onPostReply={onRefresh}
/>
<PostThreadItem item={item} onPostReply={onRefresh} />
)
return (
<FlatList

View file

@ -21,11 +21,9 @@ const PARENT_REPLY_LINE_LENGTH = 8
export const PostThreadItem = observer(function PostThreadItem({
item,
onPressShare,
onPostReply,
}: {
item: PostThreadViewPostModel
onPressShare: (_uri: string) => void
onPostReply: () => void
}) {
const store = useStores()

View file

@ -1,5 +1,6 @@
import React, {useRef} from 'react'
import {
Share,
StyleProp,
StyleSheet,
Text,
@ -12,8 +13,9 @@ import {IconProp} from '@fortawesome/fontawesome-svg-core'
import RootSiblings from 'react-native-root-siblings'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {colors} from '../../lib/styles'
import {toShareUrl} from '../../lib/strings'
import {useStores} from '../../../state'
import {SharePostModel, ConfirmModel} from '../../../state/models/shell-ui'
import {ConfirmModel} from '../../../state/models/shell-ui'
export interface DropdownItem {
icon?: IconProp
@ -93,7 +95,7 @@ export function PostDropdownBtn({
icon: 'share',
label: 'Share...',
onPress() {
store.shell.openModal(new SharePostModel(itemHref))
Share.share({url: toShareUrl(itemHref)})
},
},
isAuthor

View file

@ -10,7 +10,6 @@ import {
} from 'react-native'
import {useStores} from '../../../state'
import {RootStoreModel} from '../../../state'
import {LinkActionsModel} from '../../../state/models/shell-ui'
export const Link = observer(function Link({
style,

View file

@ -140,3 +140,12 @@ export function toNiceDomain(url: string): string {
return url
}
}
export function toShareUrl(url: string) {
if (!url.startsWith('https')) {
const urlp = new URL('https://bsky.app')
urlp.pathname = url
url = urlp.toString()
}
return url
}

View file

@ -2,6 +2,7 @@ import React, {createRef, useRef, useMemo, useEffect, useState} from 'react'
import {observer} from 'mobx-react-lite'
import {
ScrollView,
Share,
StyleSheet,
Text,
TouchableWithoutFeedback,
@ -20,8 +21,8 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import Swipeable from 'react-native-gesture-handler/Swipeable'
import {useStores} from '../../../state'
import {s, colors} from '../../lib/styles'
import {toShareUrl} from '../../lib/strings'
import {match} from '../../routes'
import {LinkActionsModel} from '../../../state/models/shell-ui'
const TAB_HEIGHT = 42
@ -69,13 +70,7 @@ export const TabsSelector = observer(
}
const onPressShareTab = () => {
onClose()
store.shell.openModal(
new LinkActionsModel(
store.nav.tab.current.url,
store.nav.tab.current.title || 'This Page',
{newTab: false},
),
)
Share.share({url: toShareUrl(store.nav.tab.current.url)})
}
const onPressChangeTab = (tabIndex: number) => {
store.nav.setActiveTab(tabIndex)