Add web linking and proper share controls
parent
39058cd36a
commit
ed146a582c
|
@ -13,6 +13,7 @@
|
||||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||||
5CEAE7B7A55582F96F1D5952 /* libPods-app.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB672808307A6013805A3FE /* libPods-app.a */; };
|
5CEAE7B7A55582F96F1D5952 /* libPods-app.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB672808307A6013805A3FE /* libPods-app.a */; };
|
||||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||||
|
E4BBD590292C1F5200296224 /* app.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = E4437C9E28581FA7006DA9E7 /* app.entitlements */; };
|
||||||
E4BD704B285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */; };
|
E4BD704B285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */; };
|
||||||
E4BD704C285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */; };
|
E4BD704C285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */; };
|
||||||
FEB90D21557517F9279AECA4 /* libPods-app-appTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAD3BC60FA05CF2D4F6F9BA2 /* libPods-app-appTests.a */; };
|
FEB90D21557517F9279AECA4 /* libPods-app-appTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAD3BC60FA05CF2D4F6F9BA2 /* libPods-app-appTests.a */; };
|
||||||
|
@ -248,6 +249,7 @@
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
E4BBD590292C1F5200296224 /* app.entitlements in Resources */,
|
||||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
|
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
|
||||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.developer.associated-domains</key>
|
<key>com.apple.developer.associated-domains</key>
|
||||||
<array/>
|
<array>
|
||||||
|
<string>applinks:bsky.app</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'react-native-url-polyfill/auto'
|
import 'react-native-url-polyfill/auto'
|
||||||
import React, {useState, useEffect} from 'react'
|
import React, {useState, useEffect} from 'react'
|
||||||
|
import {Linking} from 'react-native'
|
||||||
import {RootSiblingParent} from 'react-native-root-siblings'
|
import {RootSiblingParent} from 'react-native-root-siblings'
|
||||||
import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
||||||
import SplashScreen from 'react-native-splash-screen'
|
import SplashScreen from 'react-native-splash-screen'
|
||||||
|
@ -24,6 +25,14 @@ function App() {
|
||||||
.then(store => {
|
.then(store => {
|
||||||
setRootStore(store)
|
setRootStore(store)
|
||||||
SplashScreen.hide()
|
SplashScreen.hide()
|
||||||
|
Linking.getInitialURL().then((url: string | null) => {
|
||||||
|
if (url) {
|
||||||
|
store.nav.handleLink(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Linking.addEventListener('url', ({url}) => {
|
||||||
|
store.nav.handleLink(url)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,24 @@ export class NavigationModel {
|
||||||
this.tabs.find(t => t.id === ptr[0])?.setTitle(ptr[1], title)
|
this.tabs.find(t => t.id === ptr[0])?.setTitle(ptr[1], title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleLink(url: string) {
|
||||||
|
let path
|
||||||
|
if (url.startsWith('/')) {
|
||||||
|
path = url
|
||||||
|
} else if (url.startsWith('http')) {
|
||||||
|
try {
|
||||||
|
path = new URL(url).pathname
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Invalid url', url, e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('Invalid url', url)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.navigate(path)
|
||||||
|
}
|
||||||
|
|
||||||
// tab management
|
// tab management
|
||||||
// =
|
// =
|
||||||
|
|
||||||
|
|
|
@ -2,23 +2,6 @@ import {makeAutoObservable} from 'mobx'
|
||||||
import {ProfileViewModel} from './profile-view'
|
import {ProfileViewModel} from './profile-view'
|
||||||
import * as Post from '../../third-party/api/src/client/types/app/bsky/feed/post'
|
import * as Post from '../../third-party/api/src/client/types/app/bsky/feed/post'
|
||||||
|
|
||||||
export interface LinkActionsModelOpts {
|
|
||||||
newTab?: boolean
|
|
||||||
}
|
|
||||||
export class LinkActionsModel {
|
|
||||||
name = 'link-actions'
|
|
||||||
newTab: boolean
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public href: string,
|
|
||||||
public title: string,
|
|
||||||
opts?: LinkActionsModelOpts,
|
|
||||||
) {
|
|
||||||
makeAutoObservable(this)
|
|
||||||
this.newTab = typeof opts?.newTab === 'boolean' ? opts.newTab : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ConfirmModel {
|
export class ConfirmModel {
|
||||||
name = 'confirm'
|
name = 'confirm'
|
||||||
|
|
||||||
|
@ -31,14 +14,6 @@ export class ConfirmModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SharePostModel {
|
|
||||||
name = 'share-post'
|
|
||||||
|
|
||||||
constructor(public href: string) {
|
|
||||||
makeAutoObservable(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EditProfileModel {
|
export class EditProfileModel {
|
||||||
name = 'edit-profile'
|
name = 'edit-profile'
|
||||||
|
|
||||||
|
@ -85,9 +60,7 @@ export interface ComposerOpts {
|
||||||
export class ShellUiModel {
|
export class ShellUiModel {
|
||||||
isModalActive = false
|
isModalActive = false
|
||||||
activeModal:
|
activeModal:
|
||||||
| LinkActionsModel
|
|
||||||
| ConfirmModel
|
| ConfirmModel
|
||||||
| SharePostModel
|
|
||||||
| EditProfileModel
|
| EditProfileModel
|
||||||
| CreateSceneModel
|
| CreateSceneModel
|
||||||
| ServerInputModel
|
| ServerInputModel
|
||||||
|
@ -101,9 +74,7 @@ export class ShellUiModel {
|
||||||
|
|
||||||
openModal(
|
openModal(
|
||||||
modal:
|
modal:
|
||||||
| LinkActionsModel
|
|
||||||
| ConfirmModel
|
| ConfirmModel
|
||||||
| SharePostModel
|
|
||||||
| EditProfileModel
|
| EditProfileModel
|
||||||
| CreateSceneModel
|
| CreateSceneModel
|
||||||
| ServerInputModel,
|
| ServerInputModel,
|
||||||
|
|
|
@ -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,
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -7,9 +7,7 @@ import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
|
||||||
|
|
||||||
import * as models from '../../../state/models/shell-ui'
|
import * as models from '../../../state/models/shell-ui'
|
||||||
|
|
||||||
import * as LinkActionsModal from './LinkActions'
|
|
||||||
import * as ConfirmModal from './Confirm'
|
import * as ConfirmModal from './Confirm'
|
||||||
import * as SharePostModal from './SharePost.native'
|
|
||||||
import * as EditProfileModal from './EditProfile'
|
import * as EditProfileModal from './EditProfile'
|
||||||
import * as CreateSceneModal from './CreateScene'
|
import * as CreateSceneModal from './CreateScene'
|
||||||
import * as InviteToSceneModal from './InviteToScene'
|
import * as InviteToSceneModal from './InviteToScene'
|
||||||
|
@ -41,27 +39,13 @@ export const Modal = observer(function Modal() {
|
||||||
|
|
||||||
let snapPoints: (string | number)[] = CLOSED_SNAPPOINTS
|
let snapPoints: (string | number)[] = CLOSED_SNAPPOINTS
|
||||||
let element
|
let element
|
||||||
if (store.shell.activeModal?.name === 'link-actions') {
|
if (store.shell.activeModal?.name === 'confirm') {
|
||||||
snapPoints = LinkActionsModal.snapPoints
|
|
||||||
element = (
|
|
||||||
<LinkActionsModal.Component
|
|
||||||
{...(store.shell.activeModal as models.LinkActionsModel)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
} else if (store.shell.activeModal?.name === 'confirm') {
|
|
||||||
snapPoints = ConfirmModal.snapPoints
|
snapPoints = ConfirmModal.snapPoints
|
||||||
element = (
|
element = (
|
||||||
<ConfirmModal.Component
|
<ConfirmModal.Component
|
||||||
{...(store.shell.activeModal as models.ConfirmModel)}
|
{...(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') {
|
} else if (store.shell.activeModal?.name === 'edit-profile') {
|
||||||
snapPoints = EditProfileModal.snapPoints
|
snapPoints = EditProfileModal.snapPoints
|
||||||
element = (
|
element = (
|
||||||
|
|
|
@ -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,
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -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,
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
PostThreadViewPostModel,
|
PostThreadViewPostModel,
|
||||||
} from '../../../state/models/post-thread-view'
|
} from '../../../state/models/post-thread-view'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {SharePostModel} from '../../../state/models/shell-ui'
|
|
||||||
import {PostThreadItem} from './PostThreadItem'
|
import {PostThreadItem} from './PostThreadItem'
|
||||||
import {ErrorMessage} from '../util/ErrorMessage'
|
import {ErrorMessage} from '../util/ErrorMessage'
|
||||||
|
|
||||||
|
@ -17,11 +16,6 @@ export const PostThread = observer(function PostThread({
|
||||||
uri: string
|
uri: string
|
||||||
view: PostThreadViewModel
|
view: PostThreadViewModel
|
||||||
}) {
|
}) {
|
||||||
const store = useStores()
|
|
||||||
|
|
||||||
const onPressShare = (uri: string) => {
|
|
||||||
store.shell.openModal(new SharePostModel(uri))
|
|
||||||
}
|
|
||||||
const onRefresh = () => {
|
const onRefresh = () => {
|
||||||
view?.refresh().catch(err => console.error('Failed to refresh', err))
|
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 posts = view.thread ? Array.from(flattenThread(view.thread)) : []
|
||||||
const renderItem = ({item}: {item: PostThreadViewPostModel}) => (
|
const renderItem = ({item}: {item: PostThreadViewPostModel}) => (
|
||||||
<PostThreadItem
|
<PostThreadItem item={item} onPostReply={onRefresh} />
|
||||||
item={item}
|
|
||||||
onPressShare={onPressShare}
|
|
||||||
onPostReply={onRefresh}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
|
|
|
@ -21,11 +21,9 @@ const PARENT_REPLY_LINE_LENGTH = 8
|
||||||
|
|
||||||
export const PostThreadItem = observer(function PostThreadItem({
|
export const PostThreadItem = observer(function PostThreadItem({
|
||||||
item,
|
item,
|
||||||
onPressShare,
|
|
||||||
onPostReply,
|
onPostReply,
|
||||||
}: {
|
}: {
|
||||||
item: PostThreadViewPostModel
|
item: PostThreadViewPostModel
|
||||||
onPressShare: (_uri: string) => void
|
|
||||||
onPostReply: () => void
|
onPostReply: () => void
|
||||||
}) {
|
}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, {useRef} from 'react'
|
import React, {useRef} from 'react'
|
||||||
import {
|
import {
|
||||||
|
Share,
|
||||||
StyleProp,
|
StyleProp,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
|
@ -12,8 +13,9 @@ import {IconProp} from '@fortawesome/fontawesome-svg-core'
|
||||||
import RootSiblings from 'react-native-root-siblings'
|
import RootSiblings from 'react-native-root-siblings'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {colors} from '../../lib/styles'
|
import {colors} from '../../lib/styles'
|
||||||
|
import {toShareUrl} from '../../lib/strings'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {SharePostModel, ConfirmModel} from '../../../state/models/shell-ui'
|
import {ConfirmModel} from '../../../state/models/shell-ui'
|
||||||
|
|
||||||
export interface DropdownItem {
|
export interface DropdownItem {
|
||||||
icon?: IconProp
|
icon?: IconProp
|
||||||
|
@ -93,7 +95,7 @@ export function PostDropdownBtn({
|
||||||
icon: 'share',
|
icon: 'share',
|
||||||
label: 'Share...',
|
label: 'Share...',
|
||||||
onPress() {
|
onPress() {
|
||||||
store.shell.openModal(new SharePostModel(itemHref))
|
Share.share({url: toShareUrl(itemHref)})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isAuthor
|
isAuthor
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {RootStoreModel} from '../../../state'
|
import {RootStoreModel} from '../../../state'
|
||||||
import {LinkActionsModel} from '../../../state/models/shell-ui'
|
|
||||||
|
|
||||||
export const Link = observer(function Link({
|
export const Link = observer(function Link({
|
||||||
style,
|
style,
|
||||||
|
|
|
@ -140,3 +140,12 @@ export function toNiceDomain(url: string): string {
|
||||||
return url
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, {createRef, useRef, useMemo, useEffect, useState} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {
|
import {
|
||||||
ScrollView,
|
ScrollView,
|
||||||
|
Share,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
TouchableWithoutFeedback,
|
TouchableWithoutFeedback,
|
||||||
|
@ -20,8 +21,8 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import Swipeable from 'react-native-gesture-handler/Swipeable'
|
import Swipeable from 'react-native-gesture-handler/Swipeable'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
|
import {toShareUrl} from '../../lib/strings'
|
||||||
import {match} from '../../routes'
|
import {match} from '../../routes'
|
||||||
import {LinkActionsModel} from '../../../state/models/shell-ui'
|
|
||||||
|
|
||||||
const TAB_HEIGHT = 42
|
const TAB_HEIGHT = 42
|
||||||
|
|
||||||
|
@ -69,13 +70,7 @@ export const TabsSelector = observer(
|
||||||
}
|
}
|
||||||
const onPressShareTab = () => {
|
const onPressShareTab = () => {
|
||||||
onClose()
|
onClose()
|
||||||
store.shell.openModal(
|
Share.share({url: toShareUrl(store.nav.tab.current.url)})
|
||||||
new LinkActionsModel(
|
|
||||||
store.nav.tab.current.url,
|
|
||||||
store.nav.tab.current.title || 'This Page',
|
|
||||||
{newTab: false},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
const onPressChangeTab = (tabIndex: number) => {
|
const onPressChangeTab = (tabIndex: number) => {
|
||||||
store.nav.setActiveTab(tabIndex)
|
store.nav.setActiveTab(tabIndex)
|
||||||
|
|
Loading…
Reference in New Issue