diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/state/models/shell.ts | 48 | ||||
-rw-r--r-- | src/view/com/composer/Autocomplete.tsx (renamed from src/view/com/modals/composer/Autocomplete.tsx) | 0 | ||||
-rw-r--r-- | src/view/com/composer/ComposePost.tsx (renamed from src/view/com/modals/ComposePost.tsx) | 24 | ||||
-rw-r--r-- | src/view/com/modals/Modal.tsx | 8 | ||||
-rw-r--r-- | src/view/com/post-thread/PostThreadItem.tsx | 11 | ||||
-rw-r--r-- | src/view/com/post/Post.tsx | 5 | ||||
-rw-r--r-- | src/view/com/posts/FeedItem.tsx | 6 | ||||
-rw-r--r-- | src/view/screens/Home.tsx | 3 | ||||
-rw-r--r-- | src/view/shell/mobile/Composer.tsx | 83 | ||||
-rw-r--r-- | src/view/shell/mobile/index.tsx | 8 |
10 files changed, 130 insertions, 66 deletions
diff --git a/src/state/models/shell.ts b/src/state/models/shell.ts index 8cb0ff9e7..33b8eef36 100644 --- a/src/state/models/shell.ts +++ b/src/state/models/shell.ts @@ -27,22 +27,6 @@ export class SharePostModel { } } -export interface ComposePostModelOpts { - replyTo?: Post.PostRef - onPost?: () => void -} -export class ComposePostModel { - name = 'compose-post' - replyTo?: Post.PostRef - onPost?: () => void - - constructor(opts?: ComposePostModelOpts) { - makeAutoObservable(this) - this.replyTo = opts?.replyTo - this.onPost = opts?.onPost - } -} - export class EditProfileModel { name = 'edit-profile' @@ -51,26 +35,22 @@ export class EditProfileModel { } } +export interface ComposerOpts { + replyTo?: Post.PostRef + onPost?: () => void +} + export class ShellModel { isModalActive = false - activeModal: - | LinkActionsModel - | SharePostModel - | ComposePostModel - | EditProfileModel - | undefined + activeModal: LinkActionsModel | SharePostModel | EditProfileModel | undefined + isComposerActive = false + composerOpts: ComposerOpts | undefined constructor() { makeAutoObservable(this) } - openModal( - modal: - | LinkActionsModel - | SharePostModel - | ComposePostModel - | EditProfileModel, - ) { + openModal(modal: LinkActionsModel | SharePostModel | EditProfileModel) { this.isModalActive = true this.activeModal = modal } @@ -79,4 +59,14 @@ export class ShellModel { this.isModalActive = false this.activeModal = undefined } + + openComposer(opts: ComposerOpts) { + this.isComposerActive = true + this.composerOpts = opts + } + + closeComposer() { + this.isComposerActive = false + this.composerOpts = undefined + } } diff --git a/src/view/com/modals/composer/Autocomplete.tsx b/src/view/com/composer/Autocomplete.tsx index 4e4bdfc8e..4e4bdfc8e 100644 --- a/src/view/com/modals/composer/Autocomplete.tsx +++ b/src/view/com/composer/Autocomplete.tsx diff --git a/src/view/com/modals/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx index 806b5d7a0..496b49a9b 100644 --- a/src/view/com/modals/ComposePost.tsx +++ b/src/view/com/composer/ComposePost.tsx @@ -1,28 +1,28 @@ import React, {useEffect, useMemo, useState} from 'react' -import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' -import {BottomSheetTextInput} from '@gorhom/bottom-sheet' +import {StyleSheet, Text, TextInput, TouchableOpacity, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import * as GetUserFollows from '../../../third-party/api/src/types/app/bsky/getUserFollows' -import * as Post from '../../../third-party/api/src/types/app/bsky/post' -import {Autocomplete} from './composer/Autocomplete' +import {Autocomplete} from './Autocomplete' import Toast from '../util/Toast' import ProgressCircle from '../util/ProgressCircle' import {useStores} from '../../../state' import * as apilib from '../../../state/lib/api' +import {ComposerOpts} from '../../../state/models/shell' import {s, colors, gradients} from '../../lib/styles' const MAX_TEXT_LENGTH = 256 const WARNING_TEXT_LENGTH = 200 const DANGER_TEXT_LENGTH = 255 -export const snapPoints = ['100%'] -export function Component({ +export function ComposePost({ replyTo, onPost, + onClose, }: { - replyTo?: Post.PostRef - onPost?: () => void + replyTo?: ComposerOpts['replyTo'] + onPost?: ComposerOpts['onPost'] + onClose: () => void }) { const store = useStores() const [error, setError] = useState('') @@ -67,7 +67,7 @@ export function Component({ } } const onPressCancel = () => { - store.shell.closeModal() + onClose() } const onPressPublish = async () => { setError('') @@ -85,7 +85,7 @@ export function Component({ return } onPost?.() - store.shell.closeModal() + onClose() Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`, { duration: Toast.durations.LONG, position: Toast.positions.TOP, @@ -148,7 +148,7 @@ export function Component({ <Text style={s.red4}>{error}</Text> </View> )} - <BottomSheetTextInput + <TextInput multiline scrollEnabled autoFocus @@ -156,7 +156,7 @@ export function Component({ placeholder={replyTo ? 'Write your reply' : "What's new?"} style={styles.textInput}> {textDecorated} - </BottomSheetTextInput> + </TextInput> <View style={[s.flexRow, s.pt10, s.pb10, s.pr5]}> <View style={s.flex1} /> <View> diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 6282b5af1..02b65a490 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -9,7 +9,6 @@ import * as models from '../../../state/models/shell' import * as LinkActionsModal from './LinkActions' import * as SharePostModal from './SharePost.native' -import * as ComposePostModal from './ComposePost' import * as EditProfile from './EditProfile' const CLOSED_SNAPPOINTS = ['10%'] @@ -51,13 +50,6 @@ export const Modal = observer(function Modal() { {...(store.shell.activeModal as models.SharePostModel)} /> ) - } else if (store.shell.activeModal?.name === 'compose-post') { - snapPoints = ComposePostModal.snapPoints - element = ( - <ComposePostModal.Component - {...(store.shell.activeModal as models.ComposePostModel)} - /> - ) } else if (store.shell.activeModal?.name === 'edit-profile') { snapPoints = EditProfile.snapPoints element = ( diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 4f0683f09..90cffc029 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -6,7 +6,6 @@ import {AtUri} from '../../../third-party/uri' import * as PostType from '../../../third-party/api/src/types/app/bsky/post' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {PostThreadViewPostModel} from '../../../state/models/post-thread-view' -import {ComposePostModel} from '../../../state/models/shell' import {Link} from '../util/Link' import {RichText} from '../util/RichText' import {PostDropdownBtn} from '../util/DropdownBtn' @@ -49,12 +48,10 @@ export const PostThreadItem = observer(function PostThreadItem({ const repostsTitle = 'Reposts of this post' const onPressReply = () => { - store.shell.openModal( - new ComposePostModel({ - replyTo: {uri: item.uri, cid: item.cid}, - onPost: onPostReply, - }), - ) + store.shell.openComposer({ + replyTo: {uri: item.uri, cid: item.cid}, + onPost: onPostReply, + }) } const onPressToggleRepost = () => { item diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index b74bbfc42..b98274c1c 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -11,7 +11,6 @@ import { } from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {PostThreadViewModel} from '../../../state/models/post-thread-view' -import {ComposePostModel} from '../../../state/models/shell' import {Link} from '../util/Link' import {UserInfoText} from '../util/UserInfoText' import {RichText} from '../util/RichText' @@ -71,9 +70,7 @@ export const Post = observer(function Post({uri}: {uri: string}) { replyHref = `/profile/${urip.hostname}/post/${urip.rkey}` } const onPressReply = () => { - store.shell.openModal( - new ComposePostModel({replyTo: {uri: item.uri, cid: item.cid}}), - ) + store.shell.openComposer({replyTo: {uri: item.uri, cid: item.cid}}) } const onPressToggleRepost = () => { item diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index cfb7d7ed7..e591113d1 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -5,7 +5,7 @@ import {AtUri} from '../../../third-party/uri' import * as PostType from '../../../third-party/api/src/types/app/bsky/post' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FeedItemModel} from '../../../state/models/feed-view' -import {ComposePostModel, SharePostModel} from '../../../state/models/shell' +import {SharePostModel} from '../../../state/models/shell' import {Link} from '../util/Link' import {PostDropdownBtn} from '../util/DropdownBtn' import {UserInfoText} from '../util/UserInfoText' @@ -40,9 +40,7 @@ export const FeedItem = observer(function FeedItem({ }, [record.reply]) const onPressReply = () => { - store.shell.openModal( - new ComposePostModel({replyTo: {uri: item.uri, cid: item.cid}}), - ) + store.shell.openComposer({replyTo: {uri: item.uri, cid: item.cid}}) } const onPressToggleRepost = () => { item diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 355a2cec1..178b01dc2 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -6,7 +6,6 @@ import {Feed} from '../com/posts/Feed' import {FAB} from '../com/util/FloatingActionButton' import {useStores} from '../../state' import {FeedModel} from '../../state/models/feed-view' -import {ComposePostModel} from '../../state/models/shell' import {ScreenParams} from '../routes' import {s} from '../lib/styles' @@ -46,7 +45,7 @@ export const Home = observer(function Home({ }, [visible, store]) const onComposePress = () => { - store.shell.openModal(new ComposePostModel({onPost: onCreatePost})) + store.shell.openComposer({onPost: onCreatePost}) } const onCreatePost = () => { defaultFeedView.loadLatest() diff --git a/src/view/shell/mobile/Composer.tsx b/src/view/shell/mobile/Composer.tsx new file mode 100644 index 000000000..62bc7304d --- /dev/null +++ b/src/view/shell/mobile/Composer.tsx @@ -0,0 +1,83 @@ +import React, {useEffect} from 'react' +import {observer} from 'mobx-react-lite' +import { + StyleSheet, + Text, + TouchableOpacity, + TouchableWithoutFeedback, + View, +} from 'react-native' +import Animated, { + useSharedValue, + useAnimatedStyle, + withTiming, + interpolate, + Easing, +} from 'react-native-reanimated' +import {IconProp} from '@fortawesome/fontawesome-svg-core' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {HomeIcon, UserGroupIcon, BellIcon} from '../../lib/icons' +import {ComposePost} from '../../com/composer/ComposePost' +import {useStores} from '../../../state' +import {ComposerOpts} from '../../../state/models/shell' +import {s, colors} from '../../lib/styles' + +export const Composer = observer( + ({ + active, + winHeight, + replyTo, + onPost, + onClose, + }: { + active: boolean + winHeight: number + replyTo?: ComposerOpts['replyTo'] + onPost?: ComposerOpts['onPost'] + onClose: () => void + }) => { + const store = useStores() + const initInterp = useSharedValue<number>(0) + + useEffect(() => { + if (active) { + initInterp.value = withTiming(1, { + duration: 300, + easing: Easing.out(Easing.exp), + }) + } else { + initInterp.value = 0 + } + }, [initInterp, active]) + const wrapperAnimStyle = useAnimatedStyle(() => ({ + top: interpolate(initInterp.value, [0, 1.0], [winHeight, 0]), + })) + + // events + // = + + // rendering + // = + + if (!active) { + return <View /> + } + + return ( + <Animated.View style={[styles.wrapper, wrapperAnimStyle]}> + <ComposePost replyTo={replyTo} onPost={onPost} onClose={onClose} /> + </Animated.View> + ) + }, +) + +const styles = StyleSheet.create({ + wrapper: { + position: 'absolute', + top: 0, + bottom: 0, + width: '100%', + backgroundColor: '#fff', + paddingTop: 20, + }, +}) diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx index 7b5dd4e91..60188f89f 100644 --- a/src/view/shell/mobile/index.tsx +++ b/src/view/shell/mobile/index.tsx @@ -30,6 +30,7 @@ import {Login} from '../../screens/Login' import {Modal} from '../../com/modals/Modal' import {MainMenu} from './MainMenu' import {TabsSelector} from './TabsSelector' +import {Composer} from './Composer' import {s, colors} from '../../lib/styles' import {GridIcon, HomeIcon, BellIcon} from '../../lib/icons' @@ -217,6 +218,13 @@ export const MobileShell: React.FC = observer(() => { active={isTabsSelectorActive} onClose={() => setTabsSelectorActive(false)} /> + <Composer + active={store.shell.isComposerActive} + onClose={() => store.shell.closeComposer()} + winHeight={winDim.height} + replyTo={store.shell.composerOpts?.replyTo} + onPost={store.shell.composerOpts?.onPost} + /> </View> ) }) |