···11import {makeAutoObservable, runInAction} from 'mobx'
22-import {AtUri} from '../../third-party/uri'
22+import {AtUri} from '../../../third-party/uri'
33import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
44-import {RootStoreModel} from './root-store'
44+import {RootStoreModel} from '../root-store'
55import {cleanError} from 'lib/strings/errors'
66import {bundleAsync} from 'lib/async/bundle'
77import * as apilib from 'lib/api/index'
···10101111export type LikeItem = GetLikes.Like
12121313-export class LikesViewModel {
1313+export class LikesModel {
1414 // state
1515 isLoading = false
1616 isRefreshing = false
+6-6
src/state/models/me.ts
···11import {makeAutoObservable, runInAction} from 'mobx'
22import {RootStoreModel} from './root-store'
33-import {FeedModel} from './feed-view'
44-import {NotificationsViewModel} from './notifications-view'
33+import {PostsFeedModel} from './feeds/posts'
44+import {NotificationsFeedModel} from './feeds/notifications'
55import {MyFollowsCache} from './cache/my-follows'
66import {isObj, hasProp} from 'lib/type-guards'
77···1313 avatar: string = ''
1414 followsCount: number | undefined
1515 followersCount: number | undefined
1616- mainFeed: FeedModel
1717- notifications: NotificationsViewModel
1616+ mainFeed: PostsFeedModel
1717+ notifications: NotificationsFeedModel
1818 follows: MyFollowsCache
19192020 constructor(public rootStore: RootStoreModel) {
···2323 {rootStore: false, serialize: false, hydrate: false},
2424 {autoBind: true},
2525 )
2626- this.mainFeed = new FeedModel(this.rootStore, 'home', {
2626+ this.mainFeed = new PostsFeedModel(this.rootStore, 'home', {
2727 algorithm: 'reverse-chronological',
2828 })
2929- this.notifications = new NotificationsViewModel(this.rootStore, {})
2929+ this.notifications = new NotificationsFeedModel(this.rootStore, {})
3030 this.follows = new MyFollowsCache(this.rootStore)
3131 }
3232
···11import {makeAutoObservable} from 'mobx'
22import {AppBskyFeedPost as Post} from '@atproto/api'
33-import {AtUri} from '../../third-party/uri'
44-import {RootStoreModel} from './root-store'
33+import {AtUri} from '../../../third-party/uri'
44+import {RootStoreModel} from '../root-store'
55import {cleanError} from 'lib/strings/errors'
6677type RemoveIndex<T> = {
···11import {makeAutoObservable, runInAction} from 'mobx'
22-import {AtUri} from '../../third-party/uri'
22+import {AtUri} from '../../../third-party/uri'
33import {
44 AppBskyFeedGetRepostedBy as GetRepostedBy,
55 AppBskyActorDefs,
66} from '@atproto/api'
77-import {RootStoreModel} from './root-store'
77+import {RootStoreModel} from '../root-store'
88import {bundleAsync} from 'lib/async/bundle'
99import {cleanError} from 'lib/strings/errors'
1010import * as apilib from 'lib/api/index'
···13131414export type RepostedByItem = AppBskyActorDefs.ProfileViewBasic
15151616-export class RepostedByViewModel {
1616+export class RepostedByModel {
1717 // state
1818 isLoading = false
1919 isRefreshing = false
+5-5
src/state/models/root-store.ts
···1212import {LogModel} from './log'
1313import {SessionModel} from './session'
1414import {ShellUiModel} from './ui/shell'
1515-import {ProfilesViewModel} from './profiles-view'
1515+import {ProfilesCache} from './cache/profiles-view'
1616import {LinkMetasCache} from './cache/link-metas'
1717-import {NotificationsViewItemModel} from './notifications-view'
1717+import {NotificationsFeedItemModel} from './feeds/notifications'
1818import {MeModel} from './me'
1919import {PreferencesModel} from './ui/preferences'
2020import {resetToTab} from '../../Navigation'
···3636 shell = new ShellUiModel(this)
3737 preferences = new PreferencesModel()
3838 me = new MeModel(this)
3939- profiles = new ProfilesViewModel(this)
3939+ profiles = new ProfilesCache(this)
4040 linkMetas = new LinkMetasCache(this)
4141 imageSizes = new ImageSizesCache()
4242···205205206206 // a notification has been queued for push
207207 onPushNotification(
208208- handler: (notif: NotificationsViewItemModel) => void,
208208+ handler: (notif: NotificationsFeedItemModel) => void,
209209 ): EmitterSubscription {
210210 return DeviceEventEmitter.addListener('push-notification', handler)
211211 }
212212- emitPushNotification(notif: NotificationsViewItemModel) {
212212+ emitPushNotification(notif: NotificationsFeedItemModel) {
213213 DeviceEventEmitter.emit('push-notification', notif)
214214 }
215215
···11import {makeAutoObservable, runInAction} from 'mobx'
22import {AppBskyActorDefs} from '@atproto/api'
33import AwaitLock from 'await-lock'
44-import {RootStoreModel} from './root-store'
44+import {RootStoreModel} from '../root-store'
5566-export class UserAutocompleteViewModel {
66+export class UserAutocompleteModel {
77 // state
88 isLoading = false
99 isActive = false
···33 AppBskyGraphGetFollowers as GetFollowers,
44 AppBskyActorDefs as ActorDefs,
55} from '@atproto/api'
66-import {RootStoreModel} from './root-store'
66+import {RootStoreModel} from '../root-store'
77import {cleanError} from 'lib/strings/errors'
88import {bundleAsync} from 'lib/async/bundle'
99···11111212export type FollowerItem = ActorDefs.ProfileViewBasic
13131414-export class UserFollowersViewModel {
1414+export class UserFollowersModel {
1515 // state
1616 isLoading = false
1717 isRefreshing = false
···33 AppBskyGraphGetFollows as GetFollows,
44 AppBskyActorDefs as ActorDefs,
55} from '@atproto/api'
66-import {RootStoreModel} from './root-store'
66+import {RootStoreModel} from '../root-store'
77import {cleanError} from 'lib/strings/errors'
88import {bundleAsync} from 'lib/async/bundle'
99···11111212export type FollowItem = ActorDefs.ProfileViewBasic
13131414-export class UserFollowsViewModel {
1414+export class UserFollowsModel {
1515 // state
1616 isLoading = false
1717 isRefreshing = false
+3-3
src/view/com/composer/Composer.tsx
···1515import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
1616import {RichText} from '@atproto/api'
1717import {useAnalytics} from 'lib/analytics'
1818-import {UserAutocompleteViewModel} from 'state/models/user-autocomplete-view'
1818+import {UserAutocompleteModel} from 'state/models/discovery/user-autocomplete'
1919import {ExternalEmbed} from './ExternalEmbed'
2020import {Text} from '../util/text/Text'
2121import * as Toast from '../util/Toast'
···6969 )
7070 const [selectedPhotos, setSelectedPhotos] = React.useState<string[]>([])
71717272- const autocompleteView = React.useMemo<UserAutocompleteViewModel>(
7373- () => new UserAutocompleteViewModel(store),
7272+ const autocompleteView = React.useMemo<UserAutocompleteModel>(
7373+ () => new UserAutocompleteModel(store),
7474 [store],
7575 )
7676
+2-2
src/view/com/composer/text-input/TextInput.tsx
···1111} from '@mattermost/react-native-paste-input'
1212import {AppBskyRichtextFacet, RichText} from '@atproto/api'
1313import isEqual from 'lodash.isequal'
1414-import {UserAutocompleteViewModel} from 'state/models/user-autocomplete-view'
1414+import {UserAutocompleteModel} from 'state/models/discovery/user-autocomplete'
1515import {Autocomplete} from './mobile/Autocomplete'
1616import {Text} from 'view/com/util/text/Text'
1717import {useStores} from 'state/index'
···3636 richtext: RichText
3737 placeholder: string
3838 suggestedLinks: Set<string>
3939- autocompleteView: UserAutocompleteViewModel
3939+ autocompleteView: UserAutocompleteModel
4040 setRichText: (v: RichText) => void
4141 onPhotoPasted: (uri: string) => void
4242 onSuggestedLinksChanged: (uris: Set<string>) => void
···22import {ActivityIndicator, StyleSheet, View} from 'react-native'
33import {observer} from 'mobx-react-lite'
44import {useStores} from 'state/index'
55-import {SuggestedPostsView} from 'state/models/suggested-posts-view'
55+import {SuggestedPostsModel} from 'state/models/discovery/suggested-posts'
66import {s} from 'lib/styles'
77import {FeedItem as Post} from '../posts/FeedItem'
88import {Text} from '../util/text/Text'
···1111export const SuggestedPosts = observer(() => {
1212 const pal = usePalette('default')
1313 const store = useStores()
1414- const suggestedPostsView = React.useMemo<SuggestedPostsView>(
1515- () => new SuggestedPostsView(store),
1414+ const suggestedPostsView = React.useMemo<SuggestedPostsModel>(
1515+ () => new SuggestedPostsModel(store),
1616 [store],
1717 )
1818
+2-2
src/view/com/modals/EditProfile.tsx
···1212import {Text} from '../util/text/Text'
1313import {ErrorMessage} from '../util/error/ErrorMessage'
1414import {useStores} from 'state/index'
1515-import {ProfileViewModel} from 'state/models/profile-view'
1515+import {ProfileModel} from 'state/models/content/profile'
1616import {s, colors, gradients} from 'lib/styles'
1717import {enforceLen} from 'lib/strings/helpers'
1818import {MAX_DISPLAY_NAME, MAX_DESCRIPTION} from 'lib/constants'
···3030 profileView,
3131 onUpdate,
3232}: {
3333- profileView: ProfileViewModel
3333+ profileView: ProfileModel
3434 onUpdate?: () => void
3535}) {
3636 const store = useStores()
+2-2
src/view/com/notifications/Feed.tsx
···22import {observer} from 'mobx-react-lite'
33import {CenteredView, FlatList} from '../util/Views'
44import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
55-import {NotificationsViewModel} from 'state/models/notifications-view'
55+import {NotificationsFeedModel} from 'state/models/feeds/notifications'
66import {FeedItem} from './FeedItem'
77import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
88import {ErrorMessage} from '../util/error/ErrorMessage'
···1919 onPressTryAgain,
2020 onScroll,
2121}: {
2222- view: NotificationsViewModel
2222+ view: NotificationsFeedModel
2323 scrollElRef?: MutableRefObject<FlatList<any> | null>
2424 onPressTryAgain?: () => void
2525 onScroll?: OnScrollCb
+4-4
src/view/com/notifications/FeedItem.tsx
···1414 FontAwesomeIconStyle,
1515 Props,
1616} from '@fortawesome/react-native-fontawesome'
1717-import {NotificationsViewItemModel} from 'state/models/notifications-view'
1818-import {PostThreadViewModel} from 'state/models/post-thread-view'
1717+import {NotificationsFeedItemModel} from 'state/models/feeds/notifications'
1818+import {PostThreadModel} from 'state/models/content/post-thread'
1919import {s, colors} from 'lib/styles'
2020import {ago} from 'lib/strings/time'
2121import {pluralize} from 'lib/strings/helpers'
···4242export const FeedItem = observer(function FeedItem({
4343 item,
4444}: {
4545- item: NotificationsViewItemModel
4545+ item: NotificationsFeedItemModel
4646}) {
4747 const pal = usePalette('default')
4848 const [isAuthorsExpanded, setAuthorsExpanded] = React.useState<boolean>(false)
···338338function AdditionalPostText({
339339 additionalPost,
340340}: {
341341- additionalPost?: PostThreadViewModel
341341+ additionalPost?: PostThreadModel
342342}) {
343343 const pal = usePalette('default')
344344 if (
+2-5
src/view/com/post-thread/PostLikedBy.tsx
···22import {observer} from 'mobx-react-lite'
33import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
44import {CenteredView, FlatList} from '../util/Views'
55-import {LikesViewModel, LikeItem} from 'state/models/likes-view'
55+import {LikesModel, LikeItem} from 'state/models/lists/likes'
66import {ErrorMessage} from '../util/error/ErrorMessage'
77import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
88import {useStores} from 'state/index'
···1111export const PostLikedBy = observer(function ({uri}: {uri: string}) {
1212 const pal = usePalette('default')
1313 const store = useStores()
1414- const view = React.useMemo(
1515- () => new LikesViewModel(store, {uri}),
1616- [store, uri],
1717- )
1414+ const view = React.useMemo(() => new LikesModel(store, {uri}), [store, uri])
18151916 useEffect(() => {
2017 view.loadMore().catch(err => store.log.error('Failed to fetch likes', err))
+2-5
src/view/com/post-thread/PostRepostedBy.tsx
···22import {observer} from 'mobx-react-lite'
33import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
44import {CenteredView, FlatList} from '../util/Views'
55-import {
66- RepostedByViewModel,
77- RepostedByItem,
88-} from 'state/models/reposted-by-view'
55+import {RepostedByModel, RepostedByItem} from 'state/models/lists/reposted-by'
96import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
107import {ErrorMessage} from '../util/error/ErrorMessage'
118import {useStores} from 'state/index'
···1916 const pal = usePalette('default')
2017 const store = useStores()
2118 const view = React.useMemo(
2222- () => new RepostedByViewModel(store, {uri}),
1919+ () => new RepostedByModel(store, {uri}),
2320 [store, uri],
2421 )
2522
+9-9
src/view/com/post-thread/PostThread.tsx
···99} from 'react-native'
1010import {CenteredView, FlatList} from '../util/Views'
1111import {
1212- PostThreadViewModel,
1313- PostThreadViewPostModel,
1414-} from 'state/models/post-thread-view'
1212+ PostThreadModel,
1313+ PostThreadItemModel,
1414+} from 'state/models/content/post-thread'
1515import {
1616 FontAwesomeIcon,
1717 FontAwesomeIconStyle,
···3131 _reactKey: '__bottom_border__',
3232 _isHighlightedPost: false,
3333}
3434-type YieldedItem = PostThreadViewPostModel | typeof REPLY_PROMPT
3434+type YieldedItem = PostThreadItemModel | typeof REPLY_PROMPT
35353636export const PostThread = observer(function PostThread({
3737 uri,
···3939 onPressReply,
4040}: {
4141 uri: string
4242- view: PostThreadViewModel
4242+ view: PostThreadModel
4343 onPressReply: () => void
4444}) {
4545 const pal = usePalette('default')
···109109 // I could find to get a border positioned directly under the last item
110110 // -prf
111111 return <View style={[styles.bottomBorder, pal.border]} />
112112- } else if (item instanceof PostThreadViewPostModel) {
112112+ } else if (item instanceof PostThreadItemModel) {
113113 return <PostThreadItem item={item} onPostReply={onRefresh} />
114114 }
115115 return <></>
···187187})
188188189189function* flattenThread(
190190- post: PostThreadViewPostModel,
190190+ post: PostThreadItemModel,
191191 isAscending = false,
192192): Generator<YieldedItem, void> {
193193 if (post.parent) {
194194 if ('notFound' in post.parent && post.parent.notFound) {
195195 // TODO render not found
196196 } else {
197197- yield* flattenThread(post.parent as PostThreadViewPostModel, true)
197197+ yield* flattenThread(post.parent as PostThreadItemModel, true)
198198 }
199199 }
200200 yield post
···206206 if ('notFound' in reply && reply.notFound) {
207207 // TODO render not found
208208 } else {
209209- yield* flattenThread(reply as PostThreadViewPostModel)
209209+ yield* flattenThread(reply as PostThreadItemModel)
210210 }
211211 }
212212 } else if (!isAscending && !post.parent && post.post.replyCount) {
+2-2
src/view/com/post-thread/PostThreadItem.tsx
···77 FontAwesomeIcon,
88 FontAwesomeIconStyle,
99} from '@fortawesome/react-native-fontawesome'
1010-import {PostThreadViewPostModel} from 'state/models/post-thread-view'
1010+import {PostThreadItemModel} from 'state/models/content/post-thread'
1111import {Link} from '../util/Link'
1212import {RichText} from '../util/text/RichText'
1313import {Text} from '../util/text/Text'
···3131 item,
3232 onPostReply,
3333}: {
3434- item: PostThreadViewPostModel
3434+ item: PostThreadItemModel
3535 onPostReply: () => void
3636}) {
3737 const pal = usePalette('default')
+4-4
src/view/com/post/Post.tsx
···1111import Clipboard from '@react-native-clipboard/clipboard'
1212import {AtUri} from '../../../third-party/uri'
1313import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
1414-import {PostThreadViewModel} from 'state/models/post-thread-view'
1414+import {PostThreadModel} from 'state/models/content/post-thread'
1515import {Link} from '../util/Link'
1616import {UserInfoText} from '../util/UserInfoText'
1717import {PostMeta} from '../util/PostMeta'
···3434 style,
3535}: {
3636 uri: string
3737- initView?: PostThreadViewModel
3737+ initView?: PostThreadModel
3838 showReplyLine?: boolean
3939 hideError?: boolean
4040 style?: StyleProp<ViewStyle>
4141}) {
4242 const pal = usePalette('default')
4343 const store = useStores()
4444- const [view, setView] = useState<PostThreadViewModel | undefined>(initView)
4444+ const [view, setView] = useState<PostThreadModel | undefined>(initView)
4545 const [deleted, setDeleted] = useState(false)
46464747 useEffect(() => {
4848 if (initView || view?.params.uri === uri) {
4949 return // no change needed? or trigger refresh?
5050 }
5151- const newView = new PostThreadViewModel(store, {uri, depth: 0})
5151+ const newView = new PostThreadModel(store, {uri, depth: 0})
5252 setView(newView)
5353 newView.setup().catch(err => store.log.error('Failed to fetch post', err))
5454 }, [initView, uri, view?.params.uri, store])
+1-1
src/view/com/post/PostText.tsx
···44import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
55import {ErrorMessage} from '../util/error/ErrorMessage'
66import {Text} from '../util/text/Text'
77-import {PostModel} from 'state/models/post'
77+import {PostModel} from 'state/models/content/post'
88import {useStores} from 'state/index'
991010export const PostText = observer(function PostText({
+2-2
src/view/com/posts/Feed.tsx
···1111import {FlatList} from '../util/Views'
1212import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
1313import {ErrorMessage} from '../util/error/ErrorMessage'
1414-import {FeedModel} from 'state/models/feed-view'
1414+import {PostsFeedModel} from 'state/models/feeds/posts'
1515import {FeedSlice} from './FeedSlice'
1616import {OnScrollCb} from 'lib/hooks/useOnMainScroll'
1717import {s} from 'lib/styles'
···3333 testID,
3434 headerOffset = 0,
3535}: {
3636- feed: FeedModel
3636+ feed: PostsFeedModel
3737 style?: StyleProp<ViewStyle>
3838 showPostFollowBtn?: boolean
3939 scrollElRef?: MutableRefObject<FlatList<any> | null>
+2-2
src/view/com/posts/FeedItem.tsx
···77 FontAwesomeIcon,
88 FontAwesomeIconStyle,
99} from '@fortawesome/react-native-fontawesome'
1010-import {FeedItemModel} from 'state/models/feed-view'
1010+import {PostsFeedItemModel} from 'state/models/feeds/posts'
1111import {Link, DesktopWebTextLink} from '../util/Link'
1212import {Text} from '../util/text/Text'
1313import {UserInfoText} from '../util/UserInfoText'
···3030 showFollowBtn,
3131 ignoreMuteFor,
3232}: {
3333- item: FeedItemModel
3333+ item: PostsFeedItemModel
3434 isThreadChild?: boolean
3535 isThreadParent?: boolean
3636 showReplyLine?: boolean
+3-3
src/view/com/posts/FeedSlice.tsx
···11import React from 'react'
22import {StyleSheet, View} from 'react-native'
33-import {FeedSliceModel} from 'state/models/feed-view'
33+import {PostsFeedSliceModel} from 'state/models/feeds/posts'
44import {AtUri} from '../../../third-party/uri'
55import {Link} from '../util/Link'
66import {Text} from '../util/text/Text'
···1313 showFollowBtn,
1414 ignoreMuteFor,
1515}: {
1616- slice: FeedSliceModel
1616+ slice: PostsFeedSliceModel
1717 showFollowBtn?: boolean
1818 ignoreMuteFor?: string
1919}) {
···6666 )
6767}
68686969-function ViewFullThread({slice}: {slice: FeedSliceModel}) {
6969+function ViewFullThread({slice}: {slice: PostsFeedSliceModel}) {
7070 const pal = usePalette('default')
7171 const itemHref = React.useMemo(() => {
7272 const urip = new AtUri(slice.rootItem.post.uri)
+3-3
src/view/com/profile/ProfileFollowers.tsx
···22import {observer} from 'mobx-react-lite'
33import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
44import {
55- UserFollowersViewModel,
55+ UserFollowersModel,
66 FollowerItem,
77-} from 'state/models/user-followers-view'
77+} from 'state/models/lists/user-followers'
88import {CenteredView, FlatList} from '../util/Views'
99import {ErrorMessage} from '../util/error/ErrorMessage'
1010import {ProfileCardWithFollowBtn} from './ProfileCard'
···1919 const pal = usePalette('default')
2020 const store = useStores()
2121 const view = React.useMemo(
2222- () => new UserFollowersViewModel(store, {actor: name}),
2222+ () => new UserFollowersModel(store, {actor: name}),
2323 [store, name],
2424 )
2525
+2-2
src/view/com/profile/ProfileFollows.tsx
···22import {observer} from 'mobx-react-lite'
33import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
44import {CenteredView, FlatList} from '../util/Views'
55-import {UserFollowsViewModel, FollowItem} from 'state/models/user-follows-view'
55+import {UserFollowsModel, FollowItem} from 'state/models/lists/user-follows'
66import {ErrorMessage} from '../util/error/ErrorMessage'
77import {ProfileCardWithFollowBtn} from './ProfileCard'
88import {useStores} from 'state/index'
···1616 const pal = usePalette('default')
1717 const store = useStores()
1818 const view = React.useMemo(
1919- () => new UserFollowsViewModel(store, {actor: name}),
1919+ () => new UserFollowsModel(store, {actor: name}),
2020 [store, name],
2121 )
2222