Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into bnewbold/bump-api-dep
Browse files Browse the repository at this point in the history
* origin:
  Allow touch at the top of the lightbox (#1489)
  Bump ios build number
  Feeds tab fixes (#1486)
  Nicer 'post processing status' in the composer (#1472)
  Inline createPanResponder (#1483)
  Tree view threads experiment (#1480)
  Make "double tap to zoom" precise across platforms (#1482)
  Onboarding recommended follows (#1457)
  Add thread sort settings (#1475)
  • Loading branch information
estrattonbailey committed Sep 20, 2023
2 parents 6352749 + cd96f8d commit 5665968
Show file tree
Hide file tree
Showing 33 changed files with 1,157 additions and 213 deletions.
2 changes: 1 addition & 1 deletion app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = function () {
backgroundColor: '#ffffff',
},
ios: {
buildNumber: '1',
buildNumber: '2',
supportsTablet: false,
bundleIdentifier: 'xyz.blueskyweb.app',
config: {
Expand Down
14 changes: 10 additions & 4 deletions src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {router} from './routes'
import {usePalette} from 'lib/hooks/usePalette'
import {useStores} from './state'
import {getRoutingInstrumentation} from 'lib/sentry'
import {bskyTitle} from 'lib/strings/headings'
import {JSX} from 'react/jsx-runtime'
import {timeout} from 'lib/async/timeout'

import {HomeScreen} from './view/screens/Home'
import {SearchScreen} from './view/screens/Search'
Expand Down Expand Up @@ -62,11 +66,8 @@ import {AppPasswords} from 'view/screens/AppPasswords'
import {ModerationMutedAccounts} from 'view/screens/ModerationMutedAccounts'
import {ModerationBlockedAccounts} from 'view/screens/ModerationBlockedAccounts'
import {SavedFeeds} from 'view/screens/SavedFeeds'
import {getRoutingInstrumentation} from 'lib/sentry'
import {bskyTitle} from 'lib/strings/headings'
import {JSX} from 'react/jsx-runtime'
import {timeout} from 'lib/async/timeout'
import {PreferencesHomeFeed} from 'view/screens/PreferencesHomeFeed'
import {PreferencesThreads} from 'view/screens/PreferencesThreads'

const navigationRef = createNavigationContainerRef<AllNavigatorParams>()

Expand Down Expand Up @@ -219,6 +220,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
component={PreferencesHomeFeed}
options={{title: title('Home Feed Preferences')}}
/>
<Stack.Screen
name="PreferencesThreads"
component={PreferencesThreads}
options={{title: title('Threads Preferences')}}
/>
</>
)
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/routes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type CommonNavigatorParams = {
AppPasswords: undefined
SavedFeeds: undefined
PreferencesHomeFeed: undefined
PreferencesThreads: undefined
}

export type BottomTabNavigatorParams = CommonNavigatorParams & {
Expand Down
1 change: 1 addition & 0 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const router = new Router({
Log: '/sys/log',
AppPasswords: '/settings/app-passwords',
PreferencesHomeFeed: '/settings/home-feed',
PreferencesThreads: '/settings/threads',
SavedFeeds: '/settings/saved-feeds',
Support: '/support',
PrivacyPolicy: '/support/privacy',
Expand Down
37 changes: 30 additions & 7 deletions src/state/models/content/post-thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ export class PostThreadModel {
res.data.thread as AppBskyFeedDefs.ThreadViewPost,
thread.uri,
)
sortThread(thread)
sortThread(thread, this.rootStore.preferences)
this.thread = thread
}
}
Expand All @@ -263,11 +263,16 @@ function pruneReplies(post: MaybePost) {
}
}

interface SortSettings {
threadDefaultSort: string
threadFollowedUsersFirst: boolean
}

type MaybeThreadItem =
| PostThreadItemModel
| AppBskyFeedDefs.NotFoundPost
| AppBskyFeedDefs.BlockedPost
function sortThread(item: MaybeThreadItem) {
function sortThread(item: MaybeThreadItem, opts: SortSettings) {
if ('notFound' in item) {
return
}
Expand Down Expand Up @@ -296,13 +301,31 @@ function sortThread(item: MaybeThreadItem) {
if (modScore(a.moderation) !== modScore(b.moderation)) {
return modScore(a.moderation) - modScore(b.moderation)
}
if (a.post.likeCount === b.post.likeCount) {
return b.post.indexedAt.localeCompare(a.post.indexedAt) // newest
} else {
return (b.post.likeCount || 0) - (a.post.likeCount || 0) // most likes
if (opts.threadFollowedUsersFirst) {
const af = a.post.author.viewer?.following
const bf = b.post.author.viewer?.following
if (af && !bf) {
return -1
} else if (!af && bf) {
return 1
}
}
if (opts.threadDefaultSort === 'oldest') {
return a.post.indexedAt.localeCompare(b.post.indexedAt)
} else if (opts.threadDefaultSort === 'newest') {
return b.post.indexedAt.localeCompare(a.post.indexedAt)
} else if (opts.threadDefaultSort === 'most-likes') {
if (a.post.likeCount === b.post.likeCount) {
return b.post.indexedAt.localeCompare(a.post.indexedAt) // newest
} else {
return (b.post.likeCount || 0) - (a.post.likeCount || 0) // most likes
}
} else if (opts.threadDefaultSort === 'random') {
return 0.5 - Math.random() // this is vaguely criminal but we can get away with it
}
return b.post.indexedAt.localeCompare(a.post.indexedAt)
})
item.replies.forEach(reply => sortThread(reply))
item.replies.forEach(reply => sortThread(reply, opts))
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/state/models/discovery/onboarding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import {makeAutoObservable} from 'mobx'
import {RootStoreModel} from '../root-store'
import {hasProp} from 'lib/type-guards'
import {track} from 'lib/analytics/analytics'
import {SuggestedActorsModel} from './suggested-actors'

export const OnboardingScreenSteps = {
Welcome: 'Welcome',
RecommendedFeeds: 'RecommendedFeeds',
RecommendedFollows: 'RecommendedFollows',
Home: 'Home',
} as const

Expand All @@ -16,7 +18,11 @@ export class OnboardingModel {
// state
step: OnboardingStep = 'Home' // default state to skip onboarding, only enabled for new users by calling start()

// data
suggestedActors: SuggestedActorsModel

constructor(public rootStore: RootStoreModel) {
this.suggestedActors = new SuggestedActorsModel(this.rootStore)
makeAutoObservable(this, {
rootStore: false,
hydrate: false,
Expand Down Expand Up @@ -56,6 +62,11 @@ export class OnboardingModel {
this.step = 'RecommendedFeeds'
return this.step
} else if (this.step === 'RecommendedFeeds') {
this.step = 'RecommendedFollows'
// prefetch recommended follows
this.suggestedActors.loadMore(true)
return this.step
} else if (this.step === 'RecommendedFollows') {
this.finish()
return this.step
} else {
Expand Down
19 changes: 19 additions & 0 deletions src/state/models/discovery/suggested-actors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class SuggestedActorsModel {
loadMoreCursor: string | undefined = undefined
error = ''
hasMore = false
lastInsertedAtIndex = -1

// data
suggestions: SuggestedActor[] = []
Expand Down Expand Up @@ -110,6 +111,24 @@ export class SuggestedActorsModel {
}
})

async insertSuggestionsByActor(actor: string, indexToInsertAt: number) {
// fetch suggestions
const res =
await this.rootStore.agent.app.bsky.graph.getSuggestedFollowsByActor({
actor: actor,
})
const {suggestions: moreSuggestions} = res.data
this.rootStore.me.follows.hydrateProfiles(moreSuggestions)
// dedupe
const toInsert = moreSuggestions.filter(
s => !this.suggestions.find(s2 => s2.did === s.did),
)
// insert
this.suggestions.splice(indexToInsertAt + 1, 0, ...toInsert)
// update index
this.lastInsertedAtIndex = indexToInsertAt
}

// state transitions
// =

Expand Down
8 changes: 7 additions & 1 deletion src/state/models/ui/my-feeds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export type MyFeedsItem =
_reactKey: string
type: 'spinner'
}
| {
_reactKey: string
type: 'saved-feeds-loading'
numItems: number
}
| {
_reactKey: string
type: 'discover-feeds-loading'
Expand Down Expand Up @@ -91,7 +96,8 @@ export class MyFeedsUIModel {
if (this.saved.isLoading) {
items.push({
_reactKey: '__saved_feeds_loading__',
type: 'spinner',
type: 'saved-feeds-loading',
numItems: this.rootStore.preferences.savedFeeds.length || 3,
})
} else if (this.saved.hasError) {
items.push({
Expand Down
43 changes: 43 additions & 0 deletions src/state/models/ui/preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const VISIBILITY_VALUES = ['ignore', 'warn', 'hide']
const DEFAULT_LANG_CODES = (deviceLocales || [])
.concat(['en', 'ja', 'pt', 'de'])
.slice(0, 6)
const THREAD_SORT_VALUES = ['oldest', 'newest', 'most-likes', 'random']

export class LabelPreferencesModel {
nsfw: LabelPreference = 'hide'
Expand Down Expand Up @@ -55,6 +56,9 @@ export class PreferencesModel {
homeFeedRepostsEnabled: boolean = true
homeFeedQuotePostsEnabled: boolean = true
homeFeedMergeFeedEnabled: boolean = false
threadDefaultSort: string = 'oldest'
threadFollowedUsersFirst: boolean = true
threadTreeViewEnabled: boolean = false
requireAltTextEnabled: boolean = false

// used to linearize async modifications to state
Expand Down Expand Up @@ -86,6 +90,9 @@ export class PreferencesModel {
homeFeedRepostsEnabled: this.homeFeedRepostsEnabled,
homeFeedQuotePostsEnabled: this.homeFeedQuotePostsEnabled,
homeFeedMergeFeedEnabled: this.homeFeedMergeFeedEnabled,
threadDefaultSort: this.threadDefaultSort,
threadFollowedUsersFirst: this.threadFollowedUsersFirst,
threadTreeViewEnabled: this.threadTreeViewEnabled,
requireAltTextEnabled: this.requireAltTextEnabled,
}
}
Expand Down Expand Up @@ -189,6 +196,28 @@ export class PreferencesModel {
) {
this.homeFeedMergeFeedEnabled = v.homeFeedMergeFeedEnabled
}
// check if thread sort order is set in preferences, then hydrate
if (
hasProp(v, 'threadDefaultSort') &&
typeof v.threadDefaultSort === 'string' &&
THREAD_SORT_VALUES.includes(v.threadDefaultSort)
) {
this.threadDefaultSort = v.threadDefaultSort
}
// check if thread followed-users-first is enabled in preferences, then hydrate
if (
hasProp(v, 'threadFollowedUsersFirst') &&
typeof v.threadFollowedUsersFirst === 'boolean'
) {
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
if (
hasProp(v, 'requireAltTextEnabled') &&
Expand Down Expand Up @@ -494,6 +523,20 @@ export class PreferencesModel {
this.homeFeedMergeFeedEnabled = !this.homeFeedMergeFeedEnabled
}

setThreadDefaultSort(v: string) {
if (THREAD_SORT_VALUES.includes(v)) {
this.threadDefaultSort = v
}
}

toggleThreadFollowedUsersFirst() {
this.threadFollowedUsersFirst = !this.threadFollowedUsersFirst
}

toggleThreadTreeViewEnabled() {
this.threadTreeViewEnabled = !this.threadTreeViewEnabled
}

toggleRequireAltTextEnabled() {
this.requireAltTextEnabled = !this.requireAltTextEnabled
}
Expand Down
4 changes: 4 additions & 0 deletions src/view/com/auth/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useStores} from 'state/index'
import {Welcome} from './onboarding/Welcome'
import {RecommendedFeeds} from './onboarding/RecommendedFeeds'
import {RecommendedFollows} from './onboarding/RecommendedFollows'

export const Onboarding = observer(function OnboardingImpl() {
const pal = usePalette('default')
Expand All @@ -28,6 +29,9 @@ export const Onboarding = observer(function OnboardingImpl() {
{store.onboarding.step === 'RecommendedFeeds' && (
<RecommendedFeeds next={next} />
)}
{store.onboarding.step === 'RecommendedFollows' && (
<RecommendedFollows next={next} />
)}
</ErrorBoundary>
</SafeAreaView>
)
Expand Down
3 changes: 2 additions & 1 deletion src/view/com/auth/onboarding/RecommendedFeeds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({
<Text
type="2xl-medium"
style={{color: '#fff', position: 'relative', top: -1}}>
Done
Next
</Text>
<FontAwesomeIcon icon="angle-right" color="#fff" size={14} />
</View>
Expand Down Expand Up @@ -215,6 +215,7 @@ const mStyles = StyleSheet.create({
marginBottom: 16,
marginHorizontal: 16,
marginTop: 16,
alignItems: 'center',
},
buttonText: {
textAlign: 'center',
Expand Down
Loading

0 comments on commit 5665968

Please sign in to comment.