Tree view threads experiment (#1480)
* Add tree-view experiment to threads * Fix typo * Remove extra minimalshellmode call * Fix to parent line rendering * Fix extra border * Some ui cleanupzio/stable
parent
d2c253a284
commit
1af8e83d53
|
@ -58,6 +58,7 @@ export class PreferencesModel {
|
||||||
homeFeedMergeFeedEnabled: boolean = false
|
homeFeedMergeFeedEnabled: boolean = false
|
||||||
threadDefaultSort: string = 'oldest'
|
threadDefaultSort: string = 'oldest'
|
||||||
threadFollowedUsersFirst: boolean = true
|
threadFollowedUsersFirst: boolean = true
|
||||||
|
threadTreeViewEnabled: boolean = false
|
||||||
requireAltTextEnabled: boolean = false
|
requireAltTextEnabled: boolean = false
|
||||||
|
|
||||||
// used to linearize async modifications to state
|
// used to linearize async modifications to state
|
||||||
|
@ -91,6 +92,7 @@ export class PreferencesModel {
|
||||||
homeFeedMergeFeedEnabled: this.homeFeedMergeFeedEnabled,
|
homeFeedMergeFeedEnabled: this.homeFeedMergeFeedEnabled,
|
||||||
threadDefaultSort: this.threadDefaultSort,
|
threadDefaultSort: this.threadDefaultSort,
|
||||||
threadFollowedUsersFirst: this.threadFollowedUsersFirst,
|
threadFollowedUsersFirst: this.threadFollowedUsersFirst,
|
||||||
|
threadTreeViewEnabled: this.threadTreeViewEnabled,
|
||||||
requireAltTextEnabled: this.requireAltTextEnabled,
|
requireAltTextEnabled: this.requireAltTextEnabled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,13 +204,20 @@ export class PreferencesModel {
|
||||||
) {
|
) {
|
||||||
this.threadDefaultSort = v.threadDefaultSort
|
this.threadDefaultSort = v.threadDefaultSort
|
||||||
}
|
}
|
||||||
// check if tread followed-users-first is enabled in preferences, then hydrate
|
// check if thread followed-users-first is enabled in preferences, then hydrate
|
||||||
if (
|
if (
|
||||||
hasProp(v, 'threadFollowedUsersFirst') &&
|
hasProp(v, 'threadFollowedUsersFirst') &&
|
||||||
typeof v.threadFollowedUsersFirst === 'boolean'
|
typeof v.threadFollowedUsersFirst === 'boolean'
|
||||||
) {
|
) {
|
||||||
this.threadFollowedUsersFirst = v.threadFollowedUsersFirst
|
this.threadFollowedUsersFirst = v.threadFollowedUsersFirst
|
||||||
}
|
}
|
||||||
|
// check if thread treeview is enabled in preferences, then hydrate
|
||||||
|
if (
|
||||||
|
hasProp(v, 'threadTreeViewEnabled') &&
|
||||||
|
typeof v.threadTreeViewEnabled === 'boolean'
|
||||||
|
) {
|
||||||
|
this.threadTreeViewEnabled = v.threadTreeViewEnabled
|
||||||
|
}
|
||||||
// check if requiring alt text is enabled in preferences, then hydrate
|
// check if requiring alt text is enabled in preferences, then hydrate
|
||||||
if (
|
if (
|
||||||
hasProp(v, 'requireAltTextEnabled') &&
|
hasProp(v, 'requireAltTextEnabled') &&
|
||||||
|
@ -524,6 +533,10 @@ export class PreferencesModel {
|
||||||
this.threadFollowedUsersFirst = !this.threadFollowedUsersFirst
|
this.threadFollowedUsersFirst = !this.threadFollowedUsersFirst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleThreadTreeViewEnabled() {
|
||||||
|
this.threadTreeViewEnabled = !this.threadTreeViewEnabled
|
||||||
|
}
|
||||||
|
|
||||||
toggleRequireAltTextEnabled() {
|
toggleRequireAltTextEnabled() {
|
||||||
this.requireAltTextEnabled = !this.requireAltTextEnabled
|
this.requireAltTextEnabled = !this.requireAltTextEnabled
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ const LOAD_MORE = {
|
||||||
const BOTTOM_COMPONENT = {
|
const BOTTOM_COMPONENT = {
|
||||||
_reactKey: '__bottom_component__',
|
_reactKey: '__bottom_component__',
|
||||||
_isHighlightedPost: false,
|
_isHighlightedPost: false,
|
||||||
|
_showBorder: true,
|
||||||
}
|
}
|
||||||
type YieldedItem =
|
type YieldedItem =
|
||||||
| PostThreadItemModel
|
| PostThreadItemModel
|
||||||
|
@ -69,10 +70,12 @@ export const PostThread = observer(function PostThread({
|
||||||
uri,
|
uri,
|
||||||
view,
|
view,
|
||||||
onPressReply,
|
onPressReply,
|
||||||
|
treeView,
|
||||||
}: {
|
}: {
|
||||||
uri: string
|
uri: string
|
||||||
view: PostThreadModel
|
view: PostThreadModel
|
||||||
onPressReply: () => void
|
onPressReply: () => void
|
||||||
|
treeView: boolean
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {isTablet} = useWebMediaQueries()
|
const {isTablet} = useWebMediaQueries()
|
||||||
|
@ -99,6 +102,13 @@ export const PostThread = observer(function PostThread({
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}, [view.isLoadingFromCache, view.thread, maxVisible])
|
}, [view.isLoadingFromCache, view.thread, maxVisible])
|
||||||
|
const highlightedPostIndex = posts.findIndex(post => post._isHighlightedPost)
|
||||||
|
const showBottomBorder =
|
||||||
|
!treeView ||
|
||||||
|
// in the treeview, only show the bottom border
|
||||||
|
// if there are replies under the highlighted posts
|
||||||
|
posts.findLast(v => v instanceof PostThreadItemModel) !==
|
||||||
|
posts[highlightedPostIndex]
|
||||||
useSetTitle(
|
useSetTitle(
|
||||||
view.thread?.postRecord &&
|
view.thread?.postRecord &&
|
||||||
`${sanitizeDisplayName(
|
`${sanitizeDisplayName(
|
||||||
|
@ -135,17 +145,16 @@ export const PostThread = observer(function PostThread({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = posts.findIndex(post => post._isHighlightedPost)
|
if (highlightedPostIndex !== -1) {
|
||||||
if (index !== -1) {
|
|
||||||
ref.current?.scrollToIndex({
|
ref.current?.scrollToIndex({
|
||||||
index,
|
index: highlightedPostIndex,
|
||||||
animated: false,
|
animated: false,
|
||||||
viewPosition: 0,
|
viewPosition: 0,
|
||||||
})
|
})
|
||||||
hasScrolledIntoView.current = true
|
hasScrolledIntoView.current = true
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
posts,
|
highlightedPostIndex,
|
||||||
view.hasContent,
|
view.hasContent,
|
||||||
view.isFromCache,
|
view.isFromCache,
|
||||||
view.isLoadingFromCache,
|
view.isLoadingFromCache,
|
||||||
|
@ -184,7 +193,14 @@ export const PostThread = observer(function PostThread({
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
} else if (item === REPLY_PROMPT) {
|
} else if (item === REPLY_PROMPT) {
|
||||||
return <ComposePrompt onPressCompose={onPressReply} />
|
return (
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
treeView && [pal.border, {borderBottomWidth: 1, marginBottom: 6}]
|
||||||
|
}>
|
||||||
|
{isDesktopWeb && <ComposePrompt onPressCompose={onPressReply} />}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
} else if (item === DELETED) {
|
} else if (item === DELETED) {
|
||||||
return (
|
return (
|
||||||
<View style={[pal.border, pal.viewLight, styles.itemContainer]}>
|
<View style={[pal.border, pal.viewLight, styles.itemContainer]}>
|
||||||
|
@ -224,7 +240,18 @@ export const PostThread = observer(function PostThread({
|
||||||
// due to some complexities with how flatlist works, this is the easiest way
|
// due to some complexities with how flatlist works, this is the easiest way
|
||||||
// I could find to get a border positioned directly under the last item
|
// I could find to get a border positioned directly under the last item
|
||||||
// -prf
|
// -prf
|
||||||
return <View style={[pal.border, styles.bottomSpacer]} />
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
{height: 400},
|
||||||
|
showBottomBorder && {
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderColor: pal.colors.border,
|
||||||
|
},
|
||||||
|
treeView && {marginTop: 10},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
} else if (item === CHILD_SPINNER) {
|
} else if (item === CHILD_SPINNER) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.childSpinner}>
|
<View style={styles.childSpinner}>
|
||||||
|
@ -240,12 +267,13 @@ export const PostThread = observer(function PostThread({
|
||||||
item={item}
|
item={item}
|
||||||
onPostReply={onRefresh}
|
onPostReply={onRefresh}
|
||||||
hasPrecedingItem={prev?._showChildReplyLine}
|
hasPrecedingItem={prev?._showChildReplyLine}
|
||||||
|
treeView={treeView}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return <></>
|
return <></>
|
||||||
},
|
},
|
||||||
[onRefresh, onPressReply, pal, posts, isTablet],
|
[onRefresh, onPressReply, pal, posts, isTablet, treeView, showBottomBorder],
|
||||||
)
|
)
|
||||||
|
|
||||||
// loading
|
// loading
|
||||||
|
@ -377,7 +405,7 @@ function* flattenThread(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield post
|
yield post
|
||||||
if (isDesktopWeb && post._isHighlightedPost) {
|
if (post._isHighlightedPost) {
|
||||||
yield REPLY_PROMPT
|
yield REPLY_PROMPT
|
||||||
}
|
}
|
||||||
if (post.replies?.length) {
|
if (post.replies?.length) {
|
||||||
|
@ -411,8 +439,4 @@ const styles = StyleSheet.create({
|
||||||
paddingVertical: 10,
|
paddingVertical: 10,
|
||||||
},
|
},
|
||||||
childSpinner: {},
|
childSpinner: {},
|
||||||
bottomSpacer: {
|
|
||||||
height: 400,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,15 +35,18 @@ import {formatCount} from '../util/numeric/format'
|
||||||
import {TimeElapsed} from 'view/com/util/TimeElapsed'
|
import {TimeElapsed} from 'view/com/util/TimeElapsed'
|
||||||
import {makeProfileLink} from 'lib/routes/links'
|
import {makeProfileLink} from 'lib/routes/links'
|
||||||
import {isDesktopWeb} from 'platform/detection'
|
import {isDesktopWeb} from 'platform/detection'
|
||||||
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
|
|
||||||
export const PostThreadItem = observer(function PostThreadItem({
|
export const PostThreadItem = observer(function PostThreadItem({
|
||||||
item,
|
item,
|
||||||
onPostReply,
|
onPostReply,
|
||||||
hasPrecedingItem,
|
hasPrecedingItem,
|
||||||
|
treeView,
|
||||||
}: {
|
}: {
|
||||||
item: PostThreadItemModel
|
item: PostThreadItemModel
|
||||||
onPostReply: () => void
|
onPostReply: () => void
|
||||||
hasPrecedingItem: boolean
|
hasPrecedingItem: boolean
|
||||||
|
treeView: boolean
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
@ -389,25 +392,28 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
const isThreadedChild = treeView && item._depth > 0
|
||||||
return (
|
return (
|
||||||
<>
|
<PostOuterWrapper
|
||||||
|
item={item}
|
||||||
|
hasPrecedingItem={hasPrecedingItem}
|
||||||
|
treeView={treeView}>
|
||||||
<PostHider
|
<PostHider
|
||||||
testID={`postThreadItem-by-${item.post.author.handle}`}
|
testID={`postThreadItem-by-${item.post.author.handle}`}
|
||||||
href={itemHref}
|
href={itemHref}
|
||||||
style={[
|
style={[pal.view]}
|
||||||
styles.outer,
|
|
||||||
pal.border,
|
|
||||||
pal.view,
|
|
||||||
item._showParentReplyLine && hasPrecedingItem && styles.noTopBorder,
|
|
||||||
styles.cursor,
|
|
||||||
]}
|
|
||||||
moderation={item.moderation.content}>
|
moderation={item.moderation.content}>
|
||||||
<PostSandboxWarning />
|
<PostSandboxWarning />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
style={{flexDirection: 'row', gap: 10, paddingLeft: 8, height: 16}}>
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 10,
|
||||||
|
paddingLeft: 8,
|
||||||
|
height: isThreadedChild ? 8 : 16,
|
||||||
|
}}>
|
||||||
<View style={{width: 52}}>
|
<View style={{width: 52}}>
|
||||||
{item._showParentReplyLine && (
|
{!isThreadedChild && item._showParentReplyLine && (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
styles.replyLine,
|
styles.replyLine,
|
||||||
|
@ -431,7 +437,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
]}>
|
]}>
|
||||||
<View style={styles.layoutAvi}>
|
<View style={styles.layoutAvi}>
|
||||||
<PreviewableUserAvatar
|
<PreviewableUserAvatar
|
||||||
size={52}
|
size={isThreadedChild ? 24 : 52}
|
||||||
did={item.post.author.did}
|
did={item.post.author.did}
|
||||||
handle={item.post.author.handle}
|
handle={item.post.author.handle}
|
||||||
avatar={item.post.author.avatar}
|
avatar={item.post.author.avatar}
|
||||||
|
@ -444,7 +450,9 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
styles.replyLine,
|
styles.replyLine,
|
||||||
{
|
{
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
backgroundColor: pal.colors.replyLine,
|
backgroundColor: isThreadedChild
|
||||||
|
? pal.colors.border
|
||||||
|
: pal.colors.replyLine,
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
@ -464,7 +472,11 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
style={styles.alert}
|
style={styles.alert}
|
||||||
/>
|
/>
|
||||||
{item.richText?.text ? (
|
{item.richText?.text ? (
|
||||||
<View style={styles.postTextContainer}>
|
<View
|
||||||
|
style={[
|
||||||
|
styles.postTextContainer,
|
||||||
|
isThreadedChild && {paddingTop: 2},
|
||||||
|
]}>
|
||||||
<RichText
|
<RichText
|
||||||
type="post-text"
|
type="post-text"
|
||||||
richText={item.richText}
|
richText={item.richText}
|
||||||
|
@ -508,30 +520,84 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
{item._hasMore ? (
|
||||||
|
<Link
|
||||||
|
style={[
|
||||||
|
styles.loadMore,
|
||||||
|
{
|
||||||
|
paddingLeft: treeView ? 44 : 70,
|
||||||
|
paddingTop: 0,
|
||||||
|
paddingBottom: treeView ? 4 : 12,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
href={itemHref}
|
||||||
|
title={itemTitle}
|
||||||
|
noFeedback>
|
||||||
|
<Text type="sm-medium" style={pal.textLight}>
|
||||||
|
More
|
||||||
|
</Text>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="angle-right"
|
||||||
|
color={pal.colors.textLight}
|
||||||
|
size={14}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
) : undefined}
|
||||||
</PostHider>
|
</PostHider>
|
||||||
{item._hasMore ? (
|
</PostOuterWrapper>
|
||||||
<Link
|
|
||||||
style={[
|
|
||||||
styles.loadMore,
|
|
||||||
{borderTopColor: pal.colors.border},
|
|
||||||
pal.view,
|
|
||||||
]}
|
|
||||||
href={itemHref}
|
|
||||||
title={itemTitle}
|
|
||||||
noFeedback>
|
|
||||||
<Text style={pal.link}>Continue thread...</Text>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon="angle-right"
|
|
||||||
style={pal.link as FontAwesomeIconStyle}
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
) : undefined}
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function PostOuterWrapper({
|
||||||
|
item,
|
||||||
|
hasPrecedingItem,
|
||||||
|
treeView,
|
||||||
|
children,
|
||||||
|
}: React.PropsWithChildren<{
|
||||||
|
item: PostThreadItemModel
|
||||||
|
hasPrecedingItem: boolean
|
||||||
|
treeView: boolean
|
||||||
|
}>) {
|
||||||
|
const {isMobile} = useWebMediaQueries()
|
||||||
|
const pal = usePalette('default')
|
||||||
|
if (treeView && item._depth > 0) {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
pal.view,
|
||||||
|
styles.cursor,
|
||||||
|
{flexDirection: 'row', paddingLeft: 10},
|
||||||
|
]}>
|
||||||
|
{Array.from(Array(item._depth - 1)).map((_, n: number) => (
|
||||||
|
<View
|
||||||
|
key={`${item.uri}-padding-${n}`}
|
||||||
|
style={{
|
||||||
|
borderLeftWidth: 2,
|
||||||
|
borderLeftColor: pal.colors.border,
|
||||||
|
marginLeft: 19,
|
||||||
|
paddingLeft: isMobile ? 0 : 4,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<View style={{flex: 1}}>{children}</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.outer,
|
||||||
|
pal.view,
|
||||||
|
pal.border,
|
||||||
|
item._showParentReplyLine && hasPrecedingItem && styles.noTopBorder,
|
||||||
|
styles.cursor,
|
||||||
|
]}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function ExpandedPostDetails({
|
function ExpandedPostDetails({
|
||||||
post,
|
post,
|
||||||
needsTranslation,
|
needsTranslation,
|
||||||
|
@ -600,7 +666,7 @@ const styles = StyleSheet.create({
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
paddingBottom: 8,
|
paddingBottom: 4,
|
||||||
paddingRight: 10,
|
paddingRight: 10,
|
||||||
},
|
},
|
||||||
postTextLargeContainer: {
|
postTextLargeContainer: {
|
||||||
|
@ -629,11 +695,10 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
loadMore: {
|
loadMore: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
alignItems: 'center',
|
||||||
borderTopWidth: 1,
|
justifyContent: 'flex-start',
|
||||||
paddingLeft: 80,
|
gap: 4,
|
||||||
paddingRight: 20,
|
paddingHorizontal: 20,
|
||||||
paddingVertical: 12,
|
|
||||||
},
|
},
|
||||||
replyLine: {
|
replyLine: {
|
||||||
width: 2,
|
width: 2,
|
||||||
|
|
|
@ -45,6 +45,7 @@ import {faEye} from '@fortawesome/free-solid-svg-icons/faEye'
|
||||||
import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash'
|
import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash'
|
||||||
import {faFaceSmile} from '@fortawesome/free-regular-svg-icons/faFaceSmile'
|
import {faFaceSmile} from '@fortawesome/free-regular-svg-icons/faFaceSmile'
|
||||||
import {faFire} from '@fortawesome/free-solid-svg-icons/faFire'
|
import {faFire} from '@fortawesome/free-solid-svg-icons/faFire'
|
||||||
|
import {faFlask} from '@fortawesome/free-solid-svg-icons'
|
||||||
import {faFloppyDisk} from '@fortawesome/free-regular-svg-icons/faFloppyDisk'
|
import {faFloppyDisk} from '@fortawesome/free-regular-svg-icons/faFloppyDisk'
|
||||||
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
||||||
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
|
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
|
||||||
|
@ -144,6 +145,7 @@ export function setup() {
|
||||||
farEyeSlash,
|
farEyeSlash,
|
||||||
faFaceSmile,
|
faFaceSmile,
|
||||||
faFire,
|
faFire,
|
||||||
|
faFlask,
|
||||||
faFloppyDisk,
|
faFloppyDisk,
|
||||||
faGear,
|
faGear,
|
||||||
faGlobe,
|
faGlobe,
|
||||||
|
|
|
@ -74,6 +74,7 @@ export const PostThreadScreen = withAuthRequired(({route}: Props) => {
|
||||||
uri={uri}
|
uri={uri}
|
||||||
view={view}
|
view={view}
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
|
treeView={store.preferences.threadTreeViewEnabled}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {Slider} from '@miblanchard/react-native-slider'
|
import {Slider} from '@miblanchard/react-native-slider'
|
||||||
import {Text} from '../com/util/text/Text'
|
import {Text} from '../com/util/text/Text'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
|
@ -158,11 +159,12 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({
|
||||||
|
|
||||||
<View style={[pal.viewLight, styles.card]}>
|
<View style={[pal.viewLight, styles.card]}>
|
||||||
<Text type="title-sm" style={[pal.text, s.pb5]}>
|
<Text type="title-sm" style={[pal.text, s.pb5]}>
|
||||||
Show Posts from My Feeds (Experimental)
|
<FontAwesomeIcon icon="flask" color={pal.colors.text} /> Show
|
||||||
|
Posts from My Feeds
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[pal.text, s.pb10]}>
|
<Text style={[pal.text, s.pb10]}>
|
||||||
Set this setting to "Yes" to show samples of your saved feeds in
|
Set this setting to "Yes" to show samples of your saved feeds in
|
||||||
your following feed.
|
your following feed. This is an experimental feature.
|
||||||
</Text>
|
</Text>
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
type="default-light"
|
type="default-light"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {Text} from '../com/util/text/Text'
|
import {Text} from '../com/util/text/Text'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
|
@ -78,6 +79,23 @@ export const PreferencesThreads = observer(function PreferencesThreadsImpl({
|
||||||
onPress={store.preferences.toggleThreadFollowedUsersFirst}
|
onPress={store.preferences.toggleThreadFollowedUsersFirst}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
<View style={[pal.viewLight, styles.card]}>
|
||||||
|
<Text type="title-sm" style={[pal.text, s.pb5]}>
|
||||||
|
<FontAwesomeIcon icon="flask" color={pal.colors.text} /> Threaded
|
||||||
|
Mode
|
||||||
|
</Text>
|
||||||
|
<Text style={[pal.text, s.pb10]}>
|
||||||
|
Set this setting to "Yes" to show replies in a threaded view. This
|
||||||
|
is an experimental feature.
|
||||||
|
</Text>
|
||||||
|
<ToggleButton
|
||||||
|
type="default-light"
|
||||||
|
label={store.preferences.threadTreeViewEnabled ? 'Yes' : 'No'}
|
||||||
|
isSelected={store.preferences.threadTreeViewEnabled}
|
||||||
|
onPress={store.preferences.toggleThreadTreeViewEnabled}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue