Merge branch 'simplify' into main
This commit is contained in:
commit
e858bb52de
20 changed files with 180 additions and 232 deletions
2
src/build-flags.ts
Normal file
2
src/build-flags.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export const LOGIN_INCLUDE_DEV_SERVERS = true
|
||||||
|
export const TABS_ENABLED = false
|
|
@ -5,7 +5,6 @@ import {RootStoreModel} from './models/root-store'
|
||||||
import * as libapi from './lib/api'
|
import * as libapi from './lib/api'
|
||||||
import * as storage from './lib/storage'
|
import * as storage from './lib/storage'
|
||||||
|
|
||||||
export const IS_PROD_BUILD = true
|
|
||||||
export const LOCAL_DEV_SERVICE = 'http://localhost:2583'
|
export const LOCAL_DEV_SERVICE = 'http://localhost:2583'
|
||||||
export const STAGING_SERVICE = 'https://pds.staging.bsky.dev'
|
export const STAGING_SERVICE = 'https://pds.staging.bsky.dev'
|
||||||
export const PROD_SERVICE = 'https://bsky.social'
|
export const PROD_SERVICE = 'https://bsky.social'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {makeAutoObservable} from 'mobx'
|
import {makeAutoObservable} from 'mobx'
|
||||||
import {isObj, hasProp} from '../lib/type-guards'
|
import {TABS_ENABLED} from '../../build-flags'
|
||||||
|
|
||||||
let __id = 0
|
let __id = 0
|
||||||
function genId() {
|
function genId() {
|
||||||
|
@ -244,6 +244,9 @@ export class NavigationModel {
|
||||||
// =
|
// =
|
||||||
|
|
||||||
newTab(url: string, title?: string) {
|
newTab(url: string, title?: string) {
|
||||||
|
if (!TABS_ENABLED) {
|
||||||
|
return this.navigate(url)
|
||||||
|
}
|
||||||
const tab = new NavigationTabModel()
|
const tab = new NavigationTabModel()
|
||||||
tab.navigate(url, title)
|
tab.navigate(url, title)
|
||||||
tab.isNewTab = true
|
tab.isNewTab = true
|
||||||
|
@ -252,10 +255,16 @@ export class NavigationModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveTab(tabIndex: number) {
|
setActiveTab(tabIndex: number) {
|
||||||
|
if (!TABS_ENABLED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.tabIndex = Math.max(Math.min(tabIndex, this.tabs.length - 1), 0)
|
this.tabIndex = Math.max(Math.min(tabIndex, this.tabs.length - 1), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
closeTab(tabIndex: number) {
|
closeTab(tabIndex: number) {
|
||||||
|
if (!TABS_ENABLED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.tabs = [
|
this.tabs = [
|
||||||
...this.tabs.slice(0, tabIndex),
|
...this.tabs.slice(0, tabIndex),
|
||||||
...this.tabs.slice(tabIndex + 1),
|
...this.tabs.slice(tabIndex + 1),
|
||||||
|
|
63
src/view/com/composer/Prompt.tsx
Normal file
63
src/view/com/composer/Prompt.tsx
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
|
import {colors} from '../../lib/styles'
|
||||||
|
import {useStores} from '../../../state'
|
||||||
|
import {UserAvatar} from '../util/UserAvatar'
|
||||||
|
|
||||||
|
export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
|
||||||
|
const store = useStores()
|
||||||
|
const onPressAvatar = () => {
|
||||||
|
store.nav.navigate(`/profile/${store.me.handle}`)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={styles.container} onPress={onPressCompose}>
|
||||||
|
<TouchableOpacity style={styles.avatar} onPress={onPressAvatar}>
|
||||||
|
<UserAvatar
|
||||||
|
size={50}
|
||||||
|
handle={store.me.handle || ''}
|
||||||
|
displayName={store.me.displayName}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<View style={styles.textContainer}>
|
||||||
|
<Text style={styles.text}>What's happening?</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.btn}>
|
||||||
|
<Text style={styles.btnText}>Post</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
borderRadius: 6,
|
||||||
|
margin: 2,
|
||||||
|
marginBottom: 0,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
paddingVertical: 10,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: colors.white,
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
width: 50,
|
||||||
|
},
|
||||||
|
textContainer: {
|
||||||
|
marginLeft: 10,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
color: colors.gray4,
|
||||||
|
fontSize: 17,
|
||||||
|
},
|
||||||
|
btn: {
|
||||||
|
backgroundColor: colors.gray1,
|
||||||
|
paddingVertical: 6,
|
||||||
|
paddingHorizontal: 14,
|
||||||
|
borderRadius: 30,
|
||||||
|
},
|
||||||
|
btnText: {
|
||||||
|
color: colors.gray5,
|
||||||
|
},
|
||||||
|
})
|
|
@ -5,11 +5,11 @@ import {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {
|
import {
|
||||||
IS_PROD_BUILD,
|
|
||||||
LOCAL_DEV_SERVICE,
|
LOCAL_DEV_SERVICE,
|
||||||
STAGING_SERVICE,
|
STAGING_SERVICE,
|
||||||
PROD_SERVICE,
|
PROD_SERVICE,
|
||||||
} from '../../../state/index'
|
} from '../../../state/index'
|
||||||
|
import {LOGIN_INCLUDE_DEV_SERVERS} from '../../../build-flags'
|
||||||
|
|
||||||
export const snapPoints = ['80%']
|
export const snapPoints = ['80%']
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export function Component({
|
||||||
<Text style={[s.textCenter, s.bold, s.f18]}>Choose Service</Text>
|
<Text style={[s.textCenter, s.bold, s.f18]}>Choose Service</Text>
|
||||||
<BottomSheetScrollView style={styles.inner}>
|
<BottomSheetScrollView style={styles.inner}>
|
||||||
<View style={styles.group}>
|
<View style={styles.group}>
|
||||||
{!IS_PROD_BUILD ? (
|
{LOGIN_INCLUDE_DEV_SERVERS ? (
|
||||||
<>
|
<>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.btn}
|
style={styles.btn}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {UserGroupIcon} from '../../lib/icons'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s} from '../../lib/styles'
|
import {s} from '../../lib/styles'
|
||||||
import {SCENE_EXPLAINER, TABS_EXPLAINER} from '../../lib/assets'
|
import {SCENE_EXPLAINER, TABS_EXPLAINER} from '../../lib/assets'
|
||||||
|
import {TABS_ENABLED} from '../../../build-flags'
|
||||||
|
|
||||||
const Intro = () => (
|
const Intro = () => (
|
||||||
<View style={styles.explainer}>
|
<View style={styles.explainer}>
|
||||||
|
@ -85,8 +86,8 @@ export const FeatureExplainer = () => {
|
||||||
const routes = [
|
const routes = [
|
||||||
{key: 'intro', title: 'Intro'},
|
{key: 'intro', title: 'Intro'},
|
||||||
{key: 'scenes', title: 'Scenes'},
|
{key: 'scenes', title: 'Scenes'},
|
||||||
{key: 'tabs', title: 'Tabs'},
|
TABS_ENABLED ? {key: 'tabs', title: 'Tabs'} : undefined,
|
||||||
]
|
].filter(Boolean)
|
||||||
|
|
||||||
const onPressSkip = () => store.onboard.next()
|
const onPressSkip = () => store.onboard.next()
|
||||||
const onPressNext = () => {
|
const onPressNext = () => {
|
||||||
|
|
|
@ -29,8 +29,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const [deleted, setDeleted] = useState(false)
|
const [deleted, setDeleted] = useState(false)
|
||||||
const record = item.record as unknown as PostType.Record
|
const record = item.record as unknown as PostType.Record
|
||||||
const hasEngagement =
|
const hasEngagement = item.upvoteCount || item.repostCount
|
||||||
item.upvoteCount || item.downvoteCount || item.repostCount
|
|
||||||
|
|
||||||
const itemHref = useMemo(() => {
|
const itemHref = useMemo(() => {
|
||||||
const urip = new AtUri(item.uri)
|
const urip = new AtUri(item.uri)
|
||||||
|
@ -44,11 +43,6 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
return `/profile/${item.author.handle}/post/${urip.rkey}/upvoted-by`
|
return `/profile/${item.author.handle}/post/${urip.rkey}/upvoted-by`
|
||||||
}, [item.uri, item.author.handle])
|
}, [item.uri, item.author.handle])
|
||||||
const upvotesTitle = 'Upvotes on this post'
|
const upvotesTitle = 'Upvotes on this post'
|
||||||
const downvotesHref = useMemo(() => {
|
|
||||||
const urip = new AtUri(item.uri)
|
|
||||||
return `/profile/${item.author.handle}/post/${urip.rkey}/downvoted-by`
|
|
||||||
}, [item.uri, item.author.handle])
|
|
||||||
const downvotesTitle = 'Downvotes on this post'
|
|
||||||
const repostsHref = useMemo(() => {
|
const repostsHref = useMemo(() => {
|
||||||
const urip = new AtUri(item.uri)
|
const urip = new AtUri(item.uri)
|
||||||
return `/profile/${item.author.handle}/post/${urip.rkey}/reposted-by`
|
return `/profile/${item.author.handle}/post/${urip.rkey}/reposted-by`
|
||||||
|
@ -71,11 +65,6 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
.toggleUpvote()
|
.toggleUpvote()
|
||||||
.catch(e => console.error('Failed to toggle upvote', record, e))
|
.catch(e => console.error('Failed to toggle upvote', record, e))
|
||||||
}
|
}
|
||||||
const onPressToggleDownvote = () => {
|
|
||||||
item
|
|
||||||
.toggleDownvote()
|
|
||||||
.catch(e => console.error('Failed to toggle downvote', record, e))
|
|
||||||
}
|
|
||||||
const onDeletePost = () => {
|
const onDeletePost = () => {
|
||||||
item.delete().then(
|
item.delete().then(
|
||||||
() => {
|
() => {
|
||||||
|
@ -186,21 +175,6 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
{item.downvoteCount ? (
|
|
||||||
<Link
|
|
||||||
style={styles.expandedInfoItem}
|
|
||||||
href={downvotesHref}
|
|
||||||
title={downvotesTitle}>
|
|
||||||
<Text style={[s.gray5, s.semiBold, s.f18]}>
|
|
||||||
<Text style={[s.bold, s.black, s.f18]}>
|
|
||||||
{item.downvoteCount}
|
|
||||||
</Text>{' '}
|
|
||||||
{pluralize(item.downvoteCount, 'downvote')}
|
|
||||||
</Text>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
|
@ -210,14 +184,11 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
replyCount={item.replyCount}
|
replyCount={item.replyCount}
|
||||||
repostCount={item.repostCount}
|
repostCount={item.repostCount}
|
||||||
upvoteCount={item.upvoteCount}
|
upvoteCount={item.upvoteCount}
|
||||||
downvoteCount={item.downvoteCount}
|
|
||||||
isReposted={!!item.myState.repost}
|
isReposted={!!item.myState.repost}
|
||||||
isUpvoted={!!item.myState.upvote}
|
isUpvoted={!!item.myState.upvote}
|
||||||
isDownvoted={!!item.myState.downvote}
|
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
onPressToggleRepost={onPressToggleRepost}
|
onPressToggleRepost={onPressToggleRepost}
|
||||||
onPressToggleUpvote={onPressToggleUpvote}
|
onPressToggleUpvote={onPressToggleUpvote}
|
||||||
onPressToggleDownvote={onPressToggleDownvote}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -299,14 +270,11 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
replyCount={item.replyCount}
|
replyCount={item.replyCount}
|
||||||
repostCount={item.repostCount}
|
repostCount={item.repostCount}
|
||||||
upvoteCount={item.upvoteCount}
|
upvoteCount={item.upvoteCount}
|
||||||
downvoteCount={item.downvoteCount}
|
|
||||||
isReposted={!!item.myState.repost}
|
isReposted={!!item.myState.repost}
|
||||||
isUpvoted={!!item.myState.upvote}
|
isUpvoted={!!item.myState.upvote}
|
||||||
isDownvoted={!!item.myState.downvote}
|
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
onPressToggleRepost={onPressToggleRepost}
|
onPressToggleRepost={onPressToggleRepost}
|
||||||
onPressToggleUpvote={onPressToggleUpvote}
|
onPressToggleUpvote={onPressToggleUpvote}
|
||||||
onPressToggleDownvote={onPressToggleDownvote}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -85,11 +85,6 @@ export const Post = observer(function Post({uri}: {uri: string}) {
|
||||||
.toggleUpvote()
|
.toggleUpvote()
|
||||||
.catch(e => console.error('Failed to toggle upvote', record, e))
|
.catch(e => console.error('Failed to toggle upvote', record, e))
|
||||||
}
|
}
|
||||||
const onPressToggleDownvote = () => {
|
|
||||||
item
|
|
||||||
.toggleDownvote()
|
|
||||||
.catch(e => console.error('Failed to toggle downvote', record, e))
|
|
||||||
}
|
|
||||||
const onDeletePost = () => {
|
const onDeletePost = () => {
|
||||||
item.delete().then(
|
item.delete().then(
|
||||||
() => {
|
() => {
|
||||||
|
@ -154,14 +149,11 @@ export const Post = observer(function Post({uri}: {uri: string}) {
|
||||||
replyCount={item.replyCount}
|
replyCount={item.replyCount}
|
||||||
repostCount={item.repostCount}
|
repostCount={item.repostCount}
|
||||||
upvoteCount={item.upvoteCount}
|
upvoteCount={item.upvoteCount}
|
||||||
downvoteCount={item.downvoteCount}
|
|
||||||
isReposted={!!item.myState.repost}
|
isReposted={!!item.myState.repost}
|
||||||
isUpvoted={!!item.myState.upvote}
|
isUpvoted={!!item.myState.upvote}
|
||||||
isDownvoted={!!item.myState.downvote}
|
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
onPressToggleRepost={onPressToggleRepost}
|
onPressToggleRepost={onPressToggleRepost}
|
||||||
onPressToggleUpvote={onPressToggleUpvote}
|
onPressToggleUpvote={onPressToggleUpvote}
|
||||||
onPressToggleDownvote={onPressToggleDownvote}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -6,23 +6,34 @@ import {EmptyState} from '../util/EmptyState'
|
||||||
import {ErrorMessage} from '../util/ErrorMessage'
|
import {ErrorMessage} from '../util/ErrorMessage'
|
||||||
import {FeedModel, FeedItemModel} from '../../../state/models/feed-view'
|
import {FeedModel, FeedItemModel} from '../../../state/models/feed-view'
|
||||||
import {FeedItem} from './FeedItem'
|
import {FeedItem} from './FeedItem'
|
||||||
|
import {ComposePrompt} from '../composer/Prompt'
|
||||||
|
|
||||||
|
const COMPOSE_PROMPT_ITEM = {_reactKey: '__prompt__'}
|
||||||
|
|
||||||
export const Feed = observer(function Feed({
|
export const Feed = observer(function Feed({
|
||||||
feed,
|
feed,
|
||||||
style,
|
style,
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
|
onPressCompose,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
}: {
|
}: {
|
||||||
feed: FeedModel
|
feed: FeedModel
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
||||||
|
onPressCompose?: () => void
|
||||||
onPressTryAgain?: () => void
|
onPressTryAgain?: () => void
|
||||||
}) {
|
}) {
|
||||||
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
||||||
// VirtualizedList: You have a large list that is slow to update - make sure your
|
// VirtualizedList: You have a large list that is slow to update - make sure your
|
||||||
// renderItem function renders components that follow React performance best practices
|
// renderItem function renders components that follow React performance best practices
|
||||||
// like PureComponent, shouldComponentUpdate, etc
|
// like PureComponent, shouldComponentUpdate, etc
|
||||||
const renderItem = ({item}: {item: FeedItemModel}) => <FeedItem item={item} />
|
const renderItem = ({item}: {item: FeedItemModel}) => {
|
||||||
|
if (item === COMPOSE_PROMPT_ITEM) {
|
||||||
|
return <ComposePrompt onPressCompose={onPressCompose} />
|
||||||
|
} else {
|
||||||
|
return <FeedItem item={item} />
|
||||||
|
}
|
||||||
|
}
|
||||||
const onRefresh = () => {
|
const onRefresh = () => {
|
||||||
feed.refresh().catch(err => console.error('Failed to refresh', err))
|
feed.refresh().catch(err => console.error('Failed to refresh', err))
|
||||||
}
|
}
|
||||||
|
@ -45,7 +56,7 @@ export const Feed = observer(function Feed({
|
||||||
{feed.hasContent && (
|
{feed.hasContent && (
|
||||||
<FlatList
|
<FlatList
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
data={feed.feed.slice()}
|
data={[COMPOSE_PROMPT_ITEM].concat(feed.feed.slice())}
|
||||||
keyExtractor={item => item._reactKey}
|
keyExtractor={item => item._reactKey}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
refreshing={feed.isRefreshing}
|
refreshing={feed.isRefreshing}
|
||||||
|
|
|
@ -53,11 +53,6 @@ export const FeedItem = observer(function FeedItem({
|
||||||
.toggleUpvote()
|
.toggleUpvote()
|
||||||
.catch(e => console.error('Failed to toggle upvote', record, e))
|
.catch(e => console.error('Failed to toggle upvote', record, e))
|
||||||
}
|
}
|
||||||
const onPressToggleDownvote = () => {
|
|
||||||
item
|
|
||||||
.toggleDownvote()
|
|
||||||
.catch(e => console.error('Failed to toggle downvote', record, e))
|
|
||||||
}
|
|
||||||
const onDeletePost = () => {
|
const onDeletePost = () => {
|
||||||
item.delete().then(
|
item.delete().then(
|
||||||
() => {
|
() => {
|
||||||
|
@ -150,14 +145,11 @@ export const FeedItem = observer(function FeedItem({
|
||||||
replyCount={item.replyCount}
|
replyCount={item.replyCount}
|
||||||
repostCount={item.repostCount}
|
repostCount={item.repostCount}
|
||||||
upvoteCount={item.upvoteCount}
|
upvoteCount={item.upvoteCount}
|
||||||
downvoteCount={item.downvoteCount}
|
|
||||||
isReposted={!!item.myState.repost}
|
isReposted={!!item.myState.repost}
|
||||||
isUpvoted={!!item.myState.upvote}
|
isUpvoted={!!item.myState.upvote}
|
||||||
isDownvoted={!!item.myState.downvote}
|
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
onPressToggleRepost={onPressToggleRepost}
|
onPressToggleRepost={onPressToggleRepost}
|
||||||
onPressToggleUpvote={onPressToggleUpvote}
|
onPressToggleUpvote={onPressToggleUpvote}
|
||||||
onPressToggleDownvote={onPressToggleDownvote}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
import {pluralize} from '../../lib/strings'
|
import {pluralize} from '../../lib/strings'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
import {getGradient} from '../../lib/asset-gen'
|
import {getGradient} from '../../lib/asset-gen'
|
||||||
|
import {MagnifyingGlassIcon} from '../../lib/icons'
|
||||||
import {DropdownBtn, DropdownItem} from '../util/DropdownBtn'
|
import {DropdownBtn, DropdownItem} from '../util/DropdownBtn'
|
||||||
import Toast from '../util/Toast'
|
import Toast from '../util/Toast'
|
||||||
import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
|
@ -43,10 +44,8 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
const onPressBack = () => {
|
const onPressBack = () => {
|
||||||
store.nav.tab.goBack()
|
store.nav.tab.goBack()
|
||||||
}
|
}
|
||||||
const onPressMyAvatar = () => {
|
const onPressSearch = () => {
|
||||||
if (store.me.handle) {
|
store.nav.navigate(`/search`)
|
||||||
store.nav.navigate(`/profile/${store.me.handle}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const onPressToggleFollow = () => {
|
const onPressToggleFollow = () => {
|
||||||
view?.toggleFollowing().then(
|
view?.toggleFollowing().then(
|
||||||
|
@ -117,15 +116,9 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{store.me.did ? (
|
<TouchableOpacity style={styles.searchBtn} onPress={onPressSearch}>
|
||||||
<TouchableOpacity style={styles.myAvatar} onPress={onPressMyAvatar}>
|
<MagnifyingGlassIcon size={19} style={styles.searchIcon} />
|
||||||
<UserAvatar
|
|
||||||
size={30}
|
|
||||||
handle={store.me.handle || ''}
|
|
||||||
displayName={store.me.displayName}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : undefined}
|
|
||||||
<View style={styles.avi}>
|
<View style={styles.avi}>
|
||||||
<LoadingPlaceholder
|
<LoadingPlaceholder
|
||||||
width={80}
|
width={80}
|
||||||
|
@ -194,15 +187,9 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{store.me.did ? (
|
<TouchableOpacity style={styles.searchBtn} onPress={onPressSearch}>
|
||||||
<TouchableOpacity style={styles.myAvatar} onPress={onPressMyAvatar}>
|
<MagnifyingGlassIcon size={19} style={styles.searchIcon} />
|
||||||
<UserAvatar
|
|
||||||
size={30}
|
|
||||||
handle={store.me.handle || ''}
|
|
||||||
displayName={store.me.displayName}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : undefined}
|
|
||||||
<View style={styles.avi}>
|
<View style={styles.avi}>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
size={80}
|
size={80}
|
||||||
|
@ -375,14 +362,17 @@ const styles = StyleSheet.create({
|
||||||
height: 14,
|
height: 14,
|
||||||
color: colors.black,
|
color: colors.black,
|
||||||
},
|
},
|
||||||
myAvatar: {
|
searchBtn: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 10,
|
top: 10,
|
||||||
right: 12,
|
right: 12,
|
||||||
backgroundColor: '#ffff',
|
backgroundColor: '#ffff',
|
||||||
padding: 1,
|
padding: 5,
|
||||||
borderRadius: 30,
|
borderRadius: 30,
|
||||||
},
|
},
|
||||||
|
searchIcon: {
|
||||||
|
color: colors.black,
|
||||||
|
},
|
||||||
avi: {
|
avi: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 80,
|
top: 80,
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {colors} from '../../lib/styles'
|
||||||
import {toShareUrl} from '../../lib/strings'
|
import {toShareUrl} from '../../lib/strings'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {ConfirmModel} from '../../../state/models/shell-ui'
|
import {ConfirmModel} from '../../../state/models/shell-ui'
|
||||||
|
import {TABS_ENABLED} from '../../../build-flags'
|
||||||
|
|
||||||
export interface DropdownItem {
|
export interface DropdownItem {
|
||||||
icon?: IconProp
|
icon?: IconProp
|
||||||
|
@ -84,13 +85,15 @@ export function PostDropdownBtn({
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
|
||||||
const dropdownItems: DropdownItem[] = [
|
const dropdownItems: DropdownItem[] = [
|
||||||
{
|
TABS_ENABLED
|
||||||
|
? {
|
||||||
icon: ['far', 'clone'],
|
icon: ['far', 'clone'],
|
||||||
label: 'Open in new tab',
|
label: 'Open in new tab',
|
||||||
onPress() {
|
onPress() {
|
||||||
store.nav.newTab(itemHref)
|
store.nav.newTab(itemHref)
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
: undefined,
|
||||||
{
|
{
|
||||||
icon: 'share',
|
icon: 'share',
|
||||||
label: 'Share...',
|
label: 'Share...',
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {UpIcon, DownIcon} from '../../lib/icons'
|
import {UpIcon} from '../../lib/icons'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
|
|
||||||
export function LoadingPlaceholder({
|
export function LoadingPlaceholder({
|
||||||
|
@ -93,18 +93,16 @@ export function PostLoadingPlaceholder({
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
style={s.gray3}
|
style={s.gray3}
|
||||||
icon={['far', 'comment']}
|
icon={['far', 'comment']}
|
||||||
size={14}
|
size={16}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={s.flex1}>
|
||||||
<FontAwesomeIcon style={s.gray3} icon="retweet" size={18} />
|
<FontAwesomeIcon style={s.gray3} icon="retweet" size={20} />
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={s.flex1}>
|
||||||
<UpIcon style={s.gray3} size={18} />
|
<UpIcon style={s.gray3} size={19} strokeWidth={1.7} />
|
||||||
</View>
|
|
||||||
<View style={s.flex1}>
|
|
||||||
<DownIcon style={s.gray3} size={18} />
|
|
||||||
</View>
|
</View>
|
||||||
|
<View style={s.flex1}></View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -8,27 +8,23 @@ import Animated, {
|
||||||
interpolate,
|
interpolate,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {UpIcon, UpIconSolid, DownIcon, DownIconSolid} from '../../lib/icons'
|
import {UpIcon, UpIconSolid} from '../../lib/icons'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
|
|
||||||
interface PostCtrlsOpts {
|
interface PostCtrlsOpts {
|
||||||
replyCount: number
|
replyCount: number
|
||||||
repostCount: number
|
repostCount: number
|
||||||
upvoteCount: number
|
upvoteCount: number
|
||||||
downvoteCount: number
|
|
||||||
isReposted: boolean
|
isReposted: boolean
|
||||||
isUpvoted: boolean
|
isUpvoted: boolean
|
||||||
isDownvoted: boolean
|
|
||||||
onPressReply: () => void
|
onPressReply: () => void
|
||||||
onPressToggleRepost: () => void
|
onPressToggleRepost: () => void
|
||||||
onPressToggleUpvote: () => void
|
onPressToggleUpvote: () => void
|
||||||
onPressToggleDownvote: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PostCtrls(opts: PostCtrlsOpts) {
|
export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
const interp1 = useSharedValue<number>(0)
|
const interp1 = useSharedValue<number>(0)
|
||||||
const interp2 = useSharedValue<number>(0)
|
const interp2 = useSharedValue<number>(0)
|
||||||
const interp3 = useSharedValue<number>(0)
|
|
||||||
|
|
||||||
const anim1Style = useAnimatedStyle(() => ({
|
const anim1Style = useAnimatedStyle(() => ({
|
||||||
transform: [{scale: interpolate(interp1.value, [0, 1.0], [1.0, 3.0])}],
|
transform: [{scale: interpolate(interp1.value, [0, 1.0], [1.0, 3.0])}],
|
||||||
|
@ -38,10 +34,6 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
transform: [{scale: interpolate(interp2.value, [0, 1.0], [1.0, 3.0])}],
|
transform: [{scale: interpolate(interp2.value, [0, 1.0], [1.0, 3.0])}],
|
||||||
opacity: interpolate(interp2.value, [0, 1.0], [1.0, 0.0]),
|
opacity: interpolate(interp2.value, [0, 1.0], [1.0, 0.0]),
|
||||||
}))
|
}))
|
||||||
const anim3Style = useAnimatedStyle(() => ({
|
|
||||||
transform: [{scale: interpolate(interp3.value, [0, 1.0], [1.0, 3.0])}],
|
|
||||||
opacity: interpolate(interp3.value, [0, 1.0], [1.0, 0.0]),
|
|
||||||
}))
|
|
||||||
|
|
||||||
const onPressToggleRepostWrapper = () => {
|
const onPressToggleRepostWrapper = () => {
|
||||||
if (!opts.isReposted) {
|
if (!opts.isReposted) {
|
||||||
|
@ -59,14 +51,6 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
}
|
}
|
||||||
opts.onPressToggleUpvote()
|
opts.onPressToggleUpvote()
|
||||||
}
|
}
|
||||||
const onPressToggleDownvoteWrapper = () => {
|
|
||||||
if (!opts.isDownvoted) {
|
|
||||||
interp3.value = withTiming(1, {duration: 300}, () => {
|
|
||||||
interp3.value = withDelay(100, withTiming(0, {duration: 20}))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
opts.onPressToggleDownvote()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.ctrls}>
|
<View style={styles.ctrls}>
|
||||||
|
@ -75,9 +59,9 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
style={styles.ctrlIcon}
|
style={styles.ctrlIcon}
|
||||||
icon={['far', 'comment']}
|
icon={['far', 'comment']}
|
||||||
size={14}
|
size={16}
|
||||||
/>
|
/>
|
||||||
<Text style={[s.gray5, s.ml5, s.f13]}>{opts.replyCount}</Text>
|
<Text style={[s.gray5, s.ml5, s.f17]}>{opts.replyCount}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={s.flex1}>
|
||||||
|
@ -90,14 +74,14 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
opts.isReposted ? styles.ctrlIconReposted : styles.ctrlIcon
|
opts.isReposted ? styles.ctrlIconReposted : styles.ctrlIcon
|
||||||
}
|
}
|
||||||
icon="retweet"
|
icon="retweet"
|
||||||
size={18}
|
size={20}
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
<Text
|
<Text
|
||||||
style={
|
style={
|
||||||
opts.isReposted
|
opts.isReposted
|
||||||
? [s.bold, s.green3, s.f13, s.ml5]
|
? [s.bold, s.green3, s.f17, s.ml5]
|
||||||
: [s.gray5, s.f13, s.ml5]
|
: [s.gray5, s.f17, s.ml5]
|
||||||
}>
|
}>
|
||||||
{opts.repostCount}
|
{opts.repostCount}
|
||||||
</Text>
|
</Text>
|
||||||
|
@ -109,42 +93,22 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
onPress={onPressToggleUpvoteWrapper}>
|
onPress={onPressToggleUpvoteWrapper}>
|
||||||
<Animated.View style={anim2Style}>
|
<Animated.View style={anim2Style}>
|
||||||
{opts.isUpvoted ? (
|
{opts.isUpvoted ? (
|
||||||
<UpIconSolid style={styles.ctrlIconUpvoted} size={18} />
|
<UpIconSolid style={[styles.ctrlIconUpvoted]} size={19} />
|
||||||
) : (
|
) : (
|
||||||
<UpIcon style={styles.ctrlIcon} size={18} />
|
<UpIcon style={[styles.ctrlIcon]} size={20} strokeWidth={1.5} />
|
||||||
)}
|
)}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
<Text
|
<Text
|
||||||
style={
|
style={
|
||||||
opts.isUpvoted
|
opts.isUpvoted
|
||||||
? [s.bold, s.red3, s.f13, s.ml5]
|
? [s.bold, s.red3, s.f17, s.ml5]
|
||||||
: [s.gray5, s.f13, s.ml5]
|
: [s.gray5, s.f17, s.ml5]
|
||||||
}>
|
}>
|
||||||
{opts.upvoteCount}
|
{opts.upvoteCount}
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={s.flex1}></View>
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.ctrl}
|
|
||||||
onPress={onPressToggleDownvoteWrapper}>
|
|
||||||
<Animated.View style={anim3Style}>
|
|
||||||
{opts.isDownvoted ? (
|
|
||||||
<DownIconSolid style={styles.ctrlIconDownvoted} size={18} />
|
|
||||||
) : (
|
|
||||||
<DownIcon style={styles.ctrlIcon} size={18} />
|
|
||||||
)}
|
|
||||||
</Animated.View>
|
|
||||||
<Text
|
|
||||||
style={
|
|
||||||
opts.isDownvoted
|
|
||||||
? [s.bold, s.blue3, s.f13, s.ml5]
|
|
||||||
: [s.gray5, s.f13, s.ml5]
|
|
||||||
}>
|
|
||||||
{opts.downvoteCount}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -152,12 +116,10 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
ctrls: {
|
ctrls: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
paddingRight: 20,
|
|
||||||
},
|
},
|
||||||
ctrl: {
|
ctrl: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingLeft: 4,
|
|
||||||
paddingRight: 4,
|
paddingRight: 4,
|
||||||
},
|
},
|
||||||
ctrlIcon: {
|
ctrlIcon: {
|
||||||
|
@ -169,7 +131,4 @@ const styles = StyleSheet.create({
|
||||||
ctrlIconUpvoted: {
|
ctrlIconUpvoted: {
|
||||||
color: colors.red3,
|
color: colors.red3,
|
||||||
},
|
},
|
||||||
ctrlIconDownvoted: {
|
|
||||||
color: colors.blue3,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {UserAvatar} from './UserAvatar'
|
import {UserAvatar} from './UserAvatar'
|
||||||
import {colors} from '../../lib/styles'
|
import {colors} from '../../lib/styles'
|
||||||
|
import {MagnifyingGlassIcon} from '../../lib/icons'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
|
|
||||||
export function ViewHeader({
|
export function ViewHeader({
|
||||||
|
@ -16,16 +17,14 @@ export function ViewHeader({
|
||||||
const onPressBack = () => {
|
const onPressBack = () => {
|
||||||
store.nav.tab.goBack()
|
store.nav.tab.goBack()
|
||||||
}
|
}
|
||||||
const onPressAvatar = () => {
|
const onPressSearch = () => {
|
||||||
if (store.me.handle) {
|
store.nav.navigate(`/search`)
|
||||||
store.nav.navigate(`/profile/${store.me.handle}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
{store.nav.tab.canGoBack ? (
|
{store.nav.tab.canGoBack ? (
|
||||||
<TouchableOpacity onPress={onPressBack} style={styles.backIcon}>
|
<TouchableOpacity onPress={onPressBack} style={styles.backIcon}>
|
||||||
<FontAwesomeIcon size={18} icon="angle-left" style={{marginTop: 3}} />
|
<FontAwesomeIcon size={18} icon="angle-left" style={{marginTop: 6}} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : (
|
) : (
|
||||||
<View style={styles.cornerPlaceholder} />
|
<View style={styles.cornerPlaceholder} />
|
||||||
|
@ -38,17 +37,9 @@ export function ViewHeader({
|
||||||
</Text>
|
</Text>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
{store.me.did ? (
|
<TouchableOpacity onPress={onPressSearch} style={styles.searchBtn}>
|
||||||
<TouchableOpacity onPress={onPressAvatar}>
|
<MagnifyingGlassIcon size={17} style={styles.searchBtnIcon} />
|
||||||
<UserAvatar
|
|
||||||
size={24}
|
|
||||||
handle={store.me.handle || ''}
|
|
||||||
displayName={store.me.displayName}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : (
|
|
||||||
<View style={styles.cornerPlaceholder} />
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -83,8 +74,22 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
|
|
||||||
cornerPlaceholder: {
|
cornerPlaceholder: {
|
||||||
width: 24,
|
width: 30,
|
||||||
height: 24,
|
height: 30,
|
||||||
|
},
|
||||||
|
backIcon: {width: 30, height: 30},
|
||||||
|
searchBtn: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: colors.gray1,
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
borderRadius: 15,
|
||||||
|
},
|
||||||
|
searchBtnIcon: {
|
||||||
|
color: colors.black,
|
||||||
|
position: 'relative',
|
||||||
|
top: -1,
|
||||||
},
|
},
|
||||||
backIcon: {width: 24, height: 24},
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -91,7 +91,7 @@ export function HomeIconSolid({
|
||||||
|
|
||||||
// Copyright (c) 2020 Refactoring UI Inc.
|
// Copyright (c) 2020 Refactoring UI Inc.
|
||||||
// https://github.com/tailwindlabs/heroicons/blob/master/LICENSE
|
// https://github.com/tailwindlabs/heroicons/blob/master/LICENSE
|
||||||
export function MangifyingGlassIcon({
|
export function MagnifyingGlassIcon({
|
||||||
style,
|
style,
|
||||||
size,
|
size,
|
||||||
}: {
|
}: {
|
||||||
|
@ -116,33 +116,6 @@ export function MangifyingGlassIcon({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copyright (c) 2020 Refactoring UI Inc.
|
|
||||||
// https://github.com/tailwindlabs/heroicons/blob/master/LICENSE
|
|
||||||
export function MangifyingGlassIconSolid({
|
|
||||||
style,
|
|
||||||
size,
|
|
||||||
}: {
|
|
||||||
style?: StyleProp<ViewStyle>
|
|
||||||
size?: string | number
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<Svg
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
strokeWidth={3}
|
|
||||||
stroke="currentColor"
|
|
||||||
width={size || 24}
|
|
||||||
height={size || 24}
|
|
||||||
style={style}>
|
|
||||||
<Path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
|
|
||||||
/>
|
|
||||||
</Svg>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/Remix-Design/RemixIcon/blob/master/License
|
// https://github.com/Remix-Design/RemixIcon/blob/master/License
|
||||||
export function BellIcon({
|
export function BellIcon({
|
||||||
style,
|
style,
|
||||||
|
@ -221,9 +194,11 @@ export function UserGroupIcon({
|
||||||
export function UpIcon({
|
export function UpIcon({
|
||||||
style,
|
style,
|
||||||
size,
|
size,
|
||||||
|
strokeWidth = 1.3,
|
||||||
}: {
|
}: {
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
size?: string | number
|
size?: string | number
|
||||||
|
strokeWidth: number
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Svg
|
<Svg
|
||||||
|
@ -232,8 +207,10 @@ export function UpIcon({
|
||||||
height={size || 24}
|
height={size || 24}
|
||||||
style={style}>
|
style={style}>
|
||||||
<Path
|
<Path
|
||||||
strokeWidth={1.3}
|
strokeWidth={strokeWidth}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
d="M 7 3 L 2 8 L 4.5 8 L 4.5 11.5 L 9.5 11.5 L 9.5 8 L 12 8 L 7 3 Z"
|
d="M 7 3 L 2 8 L 4.5 8 L 4.5 11.5 L 9.5 11.5 L 9.5 8 L 12 8 L 7 3 Z"
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
|
@ -257,6 +234,8 @@ export function UpIconSolid({
|
||||||
strokeWidth={1.3}
|
strokeWidth={1.3}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
d="M 7 3 L 2 8 L 4.5 8 L 4.5 11.5 L 9.5 11.5 L 9.5 8 L 12 8 L 7 3 Z"
|
d="M 7 3 L 2 8 L 4.5 8 L 4.5 11.5 L 9.5 11.5 L 9.5 8 L 12 8 L 7 3 Z"
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
|
@ -279,6 +258,8 @@ export function DownIcon({
|
||||||
<Path
|
<Path
|
||||||
strokeWidth={1.3}
|
strokeWidth={1.3}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
d="M 7 11.5 L 2 6.5 L 4.5 6.5 L 4.5 3 L 9.5 3 L 9.5 6.5 L 12 6.5 L 7 11.5 Z"
|
d="M 7 11.5 L 2 6.5 L 4.5 6.5 L 4.5 3 L 9.5 3 L 9.5 6.5 L 12 6.5 L 7 11.5 Z"
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
|
@ -302,6 +283,8 @@ export function DownIconSolid({
|
||||||
strokeWidth={1.3}
|
strokeWidth={1.3}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
d="M 7 11.5 L 2 6.5 L 4.5 6.5 L 4.5 3 L 9.5 3 L 9.5 6.5 L 12 6.5 L 7 11.5 Z"
|
d="M 7 11.5 L 2 6.5 L 4.5 6.5 L 4.5 3 L 9.5 3 L 9.5 6.5 L 12 6.5 L 7 11.5 Z"
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import useAppState from 'react-native-appstate-hook'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import {Feed} from '../com/posts/Feed'
|
import {Feed} from '../com/posts/Feed'
|
||||||
import {FAB} from '../com/util/FloatingActionButton'
|
|
||||||
import {useStores} from '../../state'
|
import {useStores} from '../../state'
|
||||||
import {FeedModel} from '../../state/models/feed-view'
|
import {FeedModel} from '../../state/models/feed-view'
|
||||||
import {ScreenParams} from '../routes'
|
import {ScreenParams} from '../routes'
|
||||||
|
@ -65,7 +64,7 @@ export const Home = observer(function Home({
|
||||||
}
|
}
|
||||||
}, [visible, store])
|
}, [visible, store])
|
||||||
|
|
||||||
const onComposePress = () => {
|
const onPressCompose = () => {
|
||||||
store.shell.openComposer({onPost: onCreatePost})
|
store.shell.openComposer({onPost: onCreatePost})
|
||||||
}
|
}
|
||||||
const onCreatePost = () => {
|
const onCreatePost = () => {
|
||||||
|
@ -87,6 +86,7 @@ export const Home = observer(function Home({
|
||||||
feed={defaultFeedView}
|
feed={defaultFeedView}
|
||||||
scrollElRef={scrollElRef}
|
scrollElRef={scrollElRef}
|
||||||
style={{flex: 1}}
|
style={{flex: 1}}
|
||||||
|
onPressCompose={onPressCompose}
|
||||||
onPressTryAgain={onPressTryAgain}
|
onPressTryAgain={onPressTryAgain}
|
||||||
/>
|
/>
|
||||||
{defaultFeedView.hasNewLatest ? (
|
{defaultFeedView.hasNewLatest ? (
|
||||||
|
@ -95,7 +95,6 @@ export const Home = observer(function Home({
|
||||||
<Text style={styles.loadLatestText}>Load new posts</Text>
|
<Text style={styles.loadLatestText}>Load new posts</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<FAB icon="pen-nib" onPress={onComposePress} />
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React, {useState, useEffect} from 'react'
|
import React, {useState, useEffect} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import {FAB} from '../com/util/FloatingActionButton'
|
|
||||||
import {Feed} from '../com/notifications/Feed'
|
import {Feed} from '../com/notifications/Feed'
|
||||||
import {useStores} from '../../state'
|
import {useStores} from '../../state'
|
||||||
import {NotificationsViewModel} from '../../state/models/notifications-view'
|
import {NotificationsViewModel} from '../../state/models/notifications-view'
|
||||||
|
@ -37,9 +36,6 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => {
|
||||||
}
|
}
|
||||||
}, [visible, store])
|
}, [visible, store])
|
||||||
|
|
||||||
const onComposePress = () => {
|
|
||||||
store.shell.openComposer({})
|
|
||||||
}
|
|
||||||
const onPressTryAgain = () => {
|
const onPressTryAgain = () => {
|
||||||
notesView?.refresh()
|
notesView?.refresh()
|
||||||
}
|
}
|
||||||
|
@ -48,7 +44,6 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => {
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<ViewHeader title="Notifications" />
|
<ViewHeader title="Notifications" />
|
||||||
{notesView && <Feed view={notesView} onPressTryAgain={onPressTryAgain} />}
|
{notesView && <Feed view={notesView} onPressTryAgain={onPressTryAgain} />}
|
||||||
<FAB icon="pen-nib" onPress={onComposePress} />
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {StyleSheet, Text, View} from 'react-native'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {ViewSelector} from '../com/util/ViewSelector'
|
import {ViewSelector} from '../com/util/ViewSelector'
|
||||||
import {FAB} from '../com/util/FloatingActionButton'
|
|
||||||
import {ScreenParams} from '../routes'
|
import {ScreenParams} from '../routes'
|
||||||
import {ProfileUiModel, Sections} from '../../state/models/profile-ui'
|
import {ProfileUiModel, Sections} from '../../state/models/profile-ui'
|
||||||
import {MembershipItem} from '../../state/models/memberships-view'
|
import {MembershipItem} from '../../state/models/memberships-view'
|
||||||
|
@ -86,9 +85,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const onComposePress = () => {
|
|
||||||
store.shell.openComposer({})
|
|
||||||
}
|
|
||||||
|
|
||||||
// rendering
|
// rendering
|
||||||
// =
|
// =
|
||||||
|
@ -241,7 +237,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
) : (
|
) : (
|
||||||
renderHeader()
|
renderHeader()
|
||||||
)}
|
)}
|
||||||
<FAB icon="pen-nib" onPress={onComposePress} />
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,6 +26,7 @@ import Animated, {
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {IconProp} from '@fortawesome/fontawesome-svg-core'
|
import {IconProp} from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import {TABS_ENABLED} from '../../../build-flags'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {NavigationModel} from '../../../state/models/navigation'
|
import {NavigationModel} from '../../../state/models/navigation'
|
||||||
import {match, MatchResult} from '../../routes'
|
import {match, MatchResult} from '../../routes'
|
||||||
|
@ -41,8 +42,6 @@ import {
|
||||||
GridIconSolid,
|
GridIconSolid,
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
HomeIconSolid,
|
HomeIconSolid,
|
||||||
MangifyingGlassIcon,
|
|
||||||
MangifyingGlassIconSolid,
|
|
||||||
BellIcon,
|
BellIcon,
|
||||||
BellIconSolid,
|
BellIconSolid,
|
||||||
} from '../../lib/icons'
|
} from '../../lib/icons'
|
||||||
|
@ -65,8 +64,6 @@ const Btn = ({
|
||||||
| 'home-solid'
|
| 'home-solid'
|
||||||
| 'bell'
|
| 'bell'
|
||||||
| 'bell-solid'
|
| 'bell-solid'
|
||||||
| 'search'
|
|
||||||
| 'search-solid'
|
|
||||||
notificationCount?: number
|
notificationCount?: number
|
||||||
tabCount?: number
|
tabCount?: number
|
||||||
onPress?: (event: GestureResponderEvent) => void
|
onPress?: (event: GestureResponderEvent) => void
|
||||||
|
@ -85,14 +82,6 @@ const Btn = ({
|
||||||
} else if (icon === 'home-solid') {
|
} else if (icon === 'home-solid') {
|
||||||
IconEl = HomeIconSolid
|
IconEl = HomeIconSolid
|
||||||
size = 24
|
size = 24
|
||||||
} else if (icon === 'search') {
|
|
||||||
IconEl = MangifyingGlassIcon
|
|
||||||
size = 24
|
|
||||||
addedStyles = {position: 'relative', top: -1} as ViewStyle
|
|
||||||
} else if (icon === 'search-solid') {
|
|
||||||
IconEl = MangifyingGlassIconSolid
|
|
||||||
size = 24
|
|
||||||
addedStyles = {position: 'relative', top: -1} as ViewStyle
|
|
||||||
} else if (icon === 'bell') {
|
} else if (icon === 'bell') {
|
||||||
IconEl = BellIcon
|
IconEl = BellIcon
|
||||||
size = 24
|
size = 24
|
||||||
|
@ -147,7 +136,6 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
store.nav.navigate('/')
|
store.nav.navigate('/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onPressSearch = () => store.nav.navigate('/search')
|
|
||||||
const onPressMenu = () => setMainMenuActive(true)
|
const onPressMenu = () => setMainMenuActive(true)
|
||||||
const onPressNotifications = () => store.nav.navigate('/notifications')
|
const onPressNotifications = () => store.nav.navigate('/notifications')
|
||||||
const onPressTabs = () => toggleTabsMenu(!isTabsSelectorActive)
|
const onPressTabs = () => toggleTabsMenu(!isTabsSelectorActive)
|
||||||
|
@ -261,7 +249,6 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAtHome = store.nav.tab.current.url === '/'
|
const isAtHome = store.nav.tab.current.url === '/'
|
||||||
const isAtSearch = store.nav.tab.current.url === '/search'
|
|
||||||
const isAtNotifications = store.nav.tab.current.url === '/notifications'
|
const isAtNotifications = store.nav.tab.current.url === '/notifications'
|
||||||
return (
|
return (
|
||||||
<View style={styles.outerContainer}>
|
<View style={styles.outerContainer}>
|
||||||
|
@ -326,16 +313,13 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
onPress={onPressHome}
|
onPress={onPressHome}
|
||||||
onLongPress={doNewTab('/')}
|
onLongPress={doNewTab('/')}
|
||||||
/>
|
/>
|
||||||
<Btn
|
{TABS_ENABLED ? (
|
||||||
icon={isAtSearch ? 'search-solid' : 'search'}
|
|
||||||
onPress={onPressSearch}
|
|
||||||
onLongPress={doNewTab('/search')}
|
|
||||||
/>
|
|
||||||
<Btn
|
<Btn
|
||||||
icon={isTabsSelectorActive ? 'clone' : ['far', 'clone']}
|
icon={isTabsSelectorActive ? 'clone' : ['far', 'clone']}
|
||||||
onPress={onPressTabs}
|
onPress={onPressTabs}
|
||||||
tabCount={store.nav.tabCount}
|
tabCount={store.nav.tabCount}
|
||||||
/>
|
/>
|
||||||
|
) : undefined}
|
||||||
<Btn
|
<Btn
|
||||||
icon={isAtNotifications ? 'bell-solid' : 'bell'}
|
icon={isAtNotifications ? 'bell-solid' : 'bell'}
|
||||||
onPress={onPressNotifications}
|
onPress={onPressNotifications}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue