diff --git a/__mocks__/@gorhom/bottom-sheet.tsx b/__mocks__/@gorhom/bottom-sheet.tsx index d6f907a3..31098601 100644 --- a/__mocks__/@gorhom/bottom-sheet.tsx +++ b/__mocks__/@gorhom/bottom-sheet.tsx @@ -6,7 +6,7 @@ const BottomSheetModalContext = React.createContext(null) const BottomSheetModalProvider = (props: any) => { return } -class BottomSheet extends React.Component { +class BottomSheet extends React.Component<{onClose?: () => void}> { snapToIndex() {} snapToPosition() {} expand() {} diff --git a/__mocks__/state-mock.ts b/__mocks__/state-mock.ts index f5676288..f269bfc6 100644 --- a/__mocks__/state-mock.ts +++ b/__mocks__/state-mock.ts @@ -9,11 +9,9 @@ import {MeModel} from '../src/state/models/me' import {OnboardModel} from '../src/state/models/onboard' import {ProfilesViewModel} from '../src/state/models/profiles-view' import {LinkMetasViewModel} from '../src/state/models/link-metas-view' -import {MembershipsViewModel} from '../src/state/models/memberships-view' import {FeedModel} from '../src/state/models/feed-view' import {NotificationsViewModel} from '../src/state/models/notifications-view' import {ProfileViewModel} from '../src/state/models/profile-view' -import {MembersViewModel} from '../src/state/models/members-view' import {ProfileUiModel, Sections} from '../src/state/models/profile-ui' import {SessionServiceClient} from '@atproto/api' import {UserAutocompleteViewModel} from '../src/state/models/user-autocomplete-view' @@ -70,95 +68,13 @@ export const mockedProfileStore = { // unknown required because of the missing private methods: _xLoading, _xIdle, _load, _replaceAll } as unknown as ProfileViewModel -export const mockedMembersStore = { - isLoading: false, - isRefreshing: false, - hasLoaded: true, - error: '', - params: { - actor: 'test actor', - }, - subject: { - did: 'test did', - handle: '', - displayName: '', - declaration: { - cid: '', - actorType: '', - }, - avatar: undefined, - }, - members: [ - { - did: 'test did2', - declaration: { - cid: '', - actorType: '', - }, - handle: 'testhandle', - displayName: 'test name', - indexedAt: '', - }, - ], - rootStore: {} as RootStoreModel, - hasContent: true, - hasError: false, - isEmpty: false, - isMember: jest.fn(), - setup: jest.fn().mockResolvedValue({aborted: false}), - refresh: jest.fn().mockResolvedValue({}), - loadMore: jest.fn(), - removeMember: jest.fn(), - // unknown required because of the missing private methods: _xLoading, _xIdle, _fetch, _replaceAll, _append -} as unknown as MembersViewModel - -export const mockedMembershipsStore = { - isLoading: false, - isRefreshing: false, - hasLoaded: true, - error: '', - params: { - actor: '', - limit: 1, - before: '', - }, - subject: { - did: 'test did', - handle: '', - displayName: '', - declaration: {cid: '', actorType: ''}, - avatar: undefined, - }, - memberships: [ - { - did: 'test did', - declaration: { - cid: '', - actorType: 'app.bsky.system.actorUser', - }, - handle: ',', - displayName: '', - createdAt: '', - indexedAt: '', - _reactKey: 'item-1', - }, - ], - rootStore: {} as RootStoreModel, - hasContent: true, - hasError: false, - isEmpty: false, - isMemberOf: jest.fn(), - setup: jest.fn().mockResolvedValue({aborted: false}), - refresh: jest.fn().mockResolvedValue({}), - loadMore: jest.fn(), - // unknown required because of the missing private methods: _xLoading, _xIdle, _fetch, _replaceAll, _append -} as unknown as MembershipsViewModel - export const mockedFeedItemStore = { _reactKey: 'item-1', _isThreadParent: false, _isThreadChildElided: false, _isThreadChild: false, + _hideParent: false, + _isRenderingAsThread: false, post: { uri: 'testuri', cid: 'test cid', @@ -475,13 +391,13 @@ export const mockedSessionStore = { export const mockedNavigationTabStore = { serialize: jest.fn(), hydrate: jest.fn(), - id: 0, + id: '0', history: [ { url: '', ts: 0, title: '', - id: 0, + id: '0', }, ], index: 0, @@ -490,7 +406,7 @@ export const mockedNavigationTabStore = { url: '', ts: 0, title: '', - id: 0, + id: '0', }, canGoBack: false, canGoForward: false, @@ -499,7 +415,7 @@ export const mockedNavigationTabStore = { url: '', title: '', index: 0, - id: 0, + id: '0', }, ], forwardTen: [ @@ -507,7 +423,7 @@ export const mockedNavigationTabStore = { url: '', title: '', index: 0, - id: 0, + id: '0', }, ], navigate: jest.fn(), @@ -524,7 +440,7 @@ export const mockedNavigationTabStore = { url: '/', title: '', index: 1, - id: 1, + id: '1', }, ], getForwardList: jest.fn(), @@ -582,13 +498,13 @@ export const mockedMeStore = { avatar: '', notificationCount: 0, rootStore: {} as RootStoreModel, - memberships: mockedMembershipsStore, mainFeed: mockedFeedStore, notifications: mockedNotificationsStore, clear: jest.fn(), load: jest.fn(), clearNotificationCount: jest.fn(), fetchNotifications: jest.fn(), + bgFetchNotifications: jest.fn(), refreshMemberships: jest.fn(), } as MeModel @@ -650,6 +566,11 @@ export const mockedRootStore = { hydrate: jest.fn(), fetchStateUpdate: jest.fn(), clearAll: jest.fn(), + onPostDeleted: jest.fn(), + emitPostDeleted: jest.fn(), + initBgFetch: jest.fn(), + onBgFetch: jest.fn(), + onBgFetchTimeout: jest.fn(), session: mockedSessionStore, nav: mockedNavigationStore, shell: mockedShellStore, @@ -663,8 +584,6 @@ export const mockedRootStore = { export const mockedProfileUiStore = { profile: mockedProfileStore, feed: mockedFeedStore, - memberships: mockedMembershipsStore, - members: mockedMembersStore, selectedViewIndex: 0, rootStore: mockedRootStore, params: { @@ -675,7 +594,7 @@ export const mockedProfileUiStore = { isRefreshing: false, isUser: true, isScene: false, - selectorItems: [Sections.Posts, Sections.PostsWithReplies, Sections.Scenes], + selectorItems: [Sections.Posts, Sections.PostsWithReplies], selectedView: Sections.Posts, setSelectedViewIndex: jest.fn(), setup: jest.fn().mockResolvedValue({aborted: false}), diff --git a/__tests__/lib/extractHtmlMeta.test.ts b/__tests__/lib/extractHtmlMeta.test.ts index c3308407..18a0df4c 100644 --- a/__tests__/lib/extractHtmlMeta.test.ts +++ b/__tests__/lib/extractHtmlMeta.test.ts @@ -41,6 +41,7 @@ describe('extractHtmlMeta', () => { it.each(cases)( 'given the html tag %p, returns %p', + // @ts-ignore not worth fixing -prf (input, expectedResult) => { const output = extractHtmlMeta({html: input as string, hostname: ''}) expect(output).toEqual(expectedResult) @@ -86,6 +87,7 @@ describe('extractHtmlMeta', () => { title: '@bluesky on Twitter', } const output = extractHtmlMeta({ + html: '', hostname: 'twitter.com', pathname: '/bluesky', }) @@ -97,6 +99,7 @@ describe('extractHtmlMeta', () => { title: 'Tweet by @bluesky', } const output = extractHtmlMeta({ + html: '', hostname: 'twitter.com', pathname: '/bluesky/status/1582437529969917953', }) @@ -108,6 +111,7 @@ describe('extractHtmlMeta', () => { title: 'Twitter', } const output = extractHtmlMeta({ + html: '', hostname: 'twitter.com', pathname: '/i/articles/follows/-1675653703?time_window=24', }) diff --git a/__tests__/view/lib/useOnMainScroll.test.tsx b/__tests__/view/lib/useOnMainScroll.test.tsx index 9a31e79e..6fae0378 100644 --- a/__tests__/view/lib/useOnMainScroll.test.tsx +++ b/__tests__/view/lib/useOnMainScroll.test.tsx @@ -5,7 +5,7 @@ import {mockedRootStore, mockedShellStore} from '../../../__mocks__/state-mock' describe('useOnMainScroll', () => { const mockedProps = { - navIdx: [0, 0] as [number, number], + navIdx: '0-0', params: {}, visible: true, } diff --git a/__tests__/view/screens/Search.test.tsx b/__tests__/view/screens/Search.test.tsx index f769c7a5..c53e80b4 100644 --- a/__tests__/view/screens/Search.test.tsx +++ b/__tests__/view/screens/Search.test.tsx @@ -5,7 +5,7 @@ import {cleanup, fireEvent, render} from '../../../jest/test-utils' describe('Search', () => { jest.useFakeTimers() const mockedProps = { - navIdx: [0, 0] as [number, number], + navIdx: '0-0', params: { name: 'test name', }, diff --git a/jest/test-pds.ts b/jest/test-pds.ts index 01b37efb..31dcb3cb 100644 --- a/jest/test-pds.ts +++ b/jest/test-pds.ts @@ -179,7 +179,7 @@ async function genMockData(pdsUrl: string): Promise { did: subject.did, declarationCid: subject.declarationCid, }, - createdAt: date.next().value, + createdAt: date.next().value || '', }, ) } diff --git a/src/App.web.tsx b/src/App.web.tsx index cc6f3815..0be05486 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -2,7 +2,7 @@ import React, {useState, useEffect} from 'react' import * as view from './view/index' import {RootStoreModel, setupState, RootStoreProvider} from './state' import {DesktopWebShell} from './view/shell/desktop-web' -import Toast from 'react-native-root-toast' +// import Toast from 'react-native-root-toast' TODO function App() { const [rootStore, setRootStore] = useState( @@ -23,9 +23,9 @@ function App() { return ( - ) + // TODO } export default App diff --git a/src/lib/extractHtmlMeta.ts b/src/lib/extractHtmlMeta.ts index 038ca81c..70387f71 100644 --- a/src/lib/extractHtmlMeta.ts +++ b/src/lib/extractHtmlMeta.ts @@ -63,7 +63,7 @@ export const extractHtmlMeta = ({ // Workaround for some websites not having a title or description in the meta tags in the initial serve if (isYoutubeUrl) { res = {...res, ...extractYoutubeMeta(html)} - } else if (isTwitterUrl) { + } else if (isTwitterUrl && pathname) { res = {...extractTwitterMeta({pathname})} } diff --git a/src/state/models/profile-ui.ts b/src/state/models/profile-ui.ts index 55fb2506..89723361 100644 --- a/src/state/models/profile-ui.ts +++ b/src/state/models/profile-ui.ts @@ -98,8 +98,6 @@ export class ProfileUiModel { const view = this.currentView if (view instanceof FeedModel) { await view.update() - } else { - await view.refresh() } } diff --git a/src/view/com/composer/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx index a414a756..64e75328 100644 --- a/src/view/com/composer/ComposePost.tsx +++ b/src/view/com/composer/ComposePost.tsx @@ -16,7 +16,10 @@ import PasteInput, { PasteInputRef, } from '@mattermost/react-native-paste-input' import LinearGradient from 'react-native-linear-gradient' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {useAnalytics} from '@segment/analytics-react-native' import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view' import {Autocomplete} from './Autocomplete' @@ -438,7 +441,11 @@ export const ComposePost = observer(function ComposePost({ hitSlop={HITSLOP}> diff --git a/src/view/com/composer/PhotoCarouselPicker.tsx b/src/view/com/composer/PhotoCarouselPicker.tsx index 5a5b1cc3..383027de 100644 --- a/src/view/com/composer/PhotoCarouselPicker.tsx +++ b/src/view/com/composer/PhotoCarouselPicker.tsx @@ -1,6 +1,9 @@ import React, {useCallback} from 'react' import {Image, StyleSheet, TouchableOpacity, ScrollView} from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import { openPicker, openCamera, @@ -131,13 +134,21 @@ export const PhotoCarouselPicker = ({ testID="openCameraButton" style={[styles.galleryButton, pal.border, styles.photo]} onPress={handleOpenCamera}> - + - + {localPhotos.photos.map((item: PhotoIdentifier, index: number) => ( Follow diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx new file mode 100644 index 00000000..fd377dde --- /dev/null +++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx @@ -0,0 +1,21 @@ +// default implementation fallback for web + +import React from 'react' +import {View} from 'react-native' +import {ImageSource} from '../../@types' + +type Props = { + imageSrc: ImageSource + onRequestClose: () => void + onZoom: (scaled: boolean) => void + onLongPress: (image: ImageSource) => void + delayLongPress: number + swipeToCloseEnabled?: boolean + doubleTapToZoomEnabled?: boolean +} + +const ImageItem = (_props: Props) => { + return +} + +export default React.memo(ImageItem) diff --git a/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts b/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts index bab136c5..a5b0b6bd 100644 --- a/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts +++ b/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts @@ -47,8 +47,8 @@ const useImageDimensions = (image: ImageSource): Dimensions | null => { if (imageDimensions) { resolve(imageDimensions) } else { - // @ts-ignore Image.getSizeWithHeaders( + // @ts-ignore source.uri, source.headers, (width: number, height: number) => { diff --git a/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts b/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts index 4600cf1a..036e7246 100644 --- a/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts +++ b/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts @@ -61,7 +61,7 @@ const usePanResponder = ({ let tmpTranslate: Position | null = null let isDoubleTapPerformed = false let lastTapTS: number | null = null - let longPressHandlerRef: number | null = null + let longPressHandlerRef: NodeJS.Timeout | null = null const meaningfulShift = MIN_DIMENSION * 0.01 const scaleValue = new Animated.Value(initialScale) diff --git a/src/view/com/lightbox/ImageViewing/utils.ts b/src/view/com/lightbox/ImageViewing/utils.ts index 7fcdc84c..8c9c1b34 100644 --- a/src/view/com/lightbox/ImageViewing/utils.ts +++ b/src/view/com/lightbox/ImageViewing/utils.ts @@ -77,6 +77,7 @@ export const getImageStyles = ( const transform = translate.getTranslateTransform() if (scale) { + // @ts-ignore TODO - is scale incorrect? might need to remove -prf transform.push({scale}, {perspective: new Animated.Value(1000)}) } diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx index c777a552..df583978 100644 --- a/src/view/com/lightbox/Lightbox.tsx +++ b/src/view/com/lightbox/Lightbox.tsx @@ -5,6 +5,7 @@ import ImageView from './ImageViewing' import {useStores} from '../../../state' import * as models from '../../../state/models/shell-ui' import {saveImageModal} from '../../../lib/images' +import {ImageSource} from './ImageViewing/@types' export const Lightbox = observer(function Lightbox() { const store = useStores() @@ -15,8 +16,14 @@ export const Lightbox = observer(function Lightbox() { const onClose = () => { store.shell.closeLightbox() } - const onLongPress = ({uri}: {uri: string}) => { - saveImageModal({uri}) + const onLongPress = (image: ImageSource) => { + if ( + typeof image === 'object' && + 'uri' in image && + typeof image.uri === 'string' + ) { + saveImageModal({uri: image.uri}) + } } if (store.shell.activeLightbox?.name === 'profile-image') { diff --git a/src/view/com/login/CreateAccount.tsx b/src/view/com/login/CreateAccount.tsx index c5507b76..be5074ee 100644 --- a/src/view/com/login/CreateAccount.tsx +++ b/src/view/com/login/CreateAccount.tsx @@ -9,7 +9,10 @@ import { TouchableOpacity, View, } from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {ComAtprotoAccountCreate} from '@atproto/api' import * as EmailValidator from 'email-validator' import {useAnalytics} from '@segment/analytics-react-native' @@ -264,7 +267,7 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => { ({ label: `.${d}`, @@ -371,7 +374,11 @@ const Policies = ({ return ( - + This service has not provided terms of service or a privacy policy. diff --git a/src/view/com/login/Signin.tsx b/src/view/com/login/Signin.tsx index 2dfb012e..1c8a54ad 100644 --- a/src/view/com/login/Signin.tsx +++ b/src/view/com/login/Signin.tsx @@ -8,7 +8,10 @@ import { TouchableOpacity, View, } from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import * as EmailValidator from 'email-validator' import {sessionClient as AtpApi, SessionServiceClient} from '@atproto/api' import {useAnalytics} from '@segment/analytics-react-native' @@ -337,7 +340,11 @@ const LoginForm = ({ {toNiceDomain(serviceUrl)} - + @@ -514,7 +521,11 @@ const ForgotPasswordForm = ({ {toNiceDomain(serviceUrl)} - + diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index ba99feb3..8449fda6 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -108,7 +108,6 @@ export function Component({ - ) + element = } else if (store.shell.activeModal?.name === 'report-account') { snapPoints = ReportAccountModal.snapPoints - element = ( - - ) + element = } else { element = } diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx index 31ef4b12..85c0d70b 100644 --- a/src/view/com/modals/ServerInput.tsx +++ b/src/view/com/modals/ServerInput.tsx @@ -1,6 +1,9 @@ import React, {useState} from 'react' import {Platform, StyleSheet, TouchableOpacity, View} from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet' import {Text} from '../util/text/Text' import {useStores} from '../../../state' @@ -37,13 +40,19 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) { style={styles.btn} onPress={() => doSelect(LOCAL_DEV_SERVICE)}> Local dev server - + doSelect(STAGING_SERVICE)}> Staging - + ) : undefined} @@ -51,7 +60,10 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) { style={styles.btn} onPress={() => doSelect(PROD_SERVICE)}> Bluesky.Social - + @@ -74,7 +86,7 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) { onPress={() => doSelect(customUrl)}> diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index 48c8b9a1..da6fc7d3 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -9,7 +9,11 @@ import { } from 'react-native' import {AppBskyEmbedImages} from '@atproto/api' import {AtUri} from '../../../third-party/uri' -import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, + Props, +} from '@fortawesome/react-native-fontawesome' import {NotificationsViewItemModel} from '../../../state/models/notifications-view' import {PostThreadViewModel} from '../../../state/models/post-thread-view' import {s, colors} from '../../lib/styles' @@ -98,18 +102,21 @@ export const FeedItem = observer(function FeedItem({ if (item.isUpvote) { action = 'liked your post' icon = 'HeartIconSolid' - iconStyle = [s.red3, {position: 'relative', top: -4}] + iconStyle = [ + s.red3 as FontAwesomeIconStyle, + {position: 'relative', top: -4}, + ] } else if (item.isRepost) { action = 'reposted your post' icon = 'retweet' - iconStyle = [s.green3] + iconStyle = [s.green3 as FontAwesomeIconStyle] } else if (item.isReply) { action = 'replied to your post' icon = ['far', 'comment'] } else if (item.isFollow) { action = 'followed you' icon = 'user-plus' - iconStyle = [s.blue3] + iconStyle = [s.blue3 as FontAwesomeIconStyle] } else { return <> } @@ -292,7 +299,6 @@ function ExpandedAuthorsList({ authors.length * (EXPANDED_AUTHOR_EL_HEIGHT + 10) /*10=margin*/ const heightStyle = { height: Animated.multiply(heightInterp, targetHeight), - overflow: 'hidden', } React.useEffect(() => { Animated.timing(heightInterp, { @@ -302,7 +308,12 @@ function ExpandedAuthorsList({ }).start() }, [heightInterp, visible]) return ( - + {authors.map(author => ( ( ( @@ -62,14 +72,10 @@ export const FeatureExplainer = () => { const layout = useWindowDimensions() const store = useStores() const [index, setIndex] = useState(0) - const routes = [ - {key: 'intro', title: 'Intro'}, - TABS_ENABLED ? {key: 'tabs', title: 'Tabs'} : undefined, - ].filter(Boolean) const onPressSkip = () => store.onboard.next() const onPressNext = () => { - if (index >= routes.length - 1) { + if (index >= ROUTES.length - 1) { store.onboard.next() } else { setIndex(index + 1) @@ -103,12 +109,12 @@ export const FeatureExplainer = () => { ) } - const FirstExplainer = SCENE_MAP[routes[0]?.key as keyof typeof SCENE_MAP] + const FirstExplainer = SCENE_MAP[ROUTES[0]?.key as keyof typeof SCENE_MAP] return ( - {routes.length > 1 ? ( + {ROUTES.length > 1 ? ( - + This post has been deleted. ) diff --git a/src/view/com/post-thread/PostVotedBy.tsx b/src/view/com/post-thread/PostVotedBy.tsx index f167a3ab..9fd53da5 100644 --- a/src/view/com/post-thread/PostVotedBy.tsx +++ b/src/view/com/post-thread/PostVotedBy.tsx @@ -1,7 +1,7 @@ import React, {useEffect} from 'react' import {observer} from 'mobx-react-lite' import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native' -import {VotesViewModel, VotesItem} from '../../../state/models/votes-view' +import {VotesViewModel, VoteItem} from '../../../state/models/votes-view' import {Link} from '../util/Link' import {Text} from '../util/text/Text' import {ErrorMessage} from '../util/error/ErrorMessage' @@ -56,7 +56,7 @@ export const PostVotedBy = observer(function PostVotedBy({ // loaded // = - const renderItem = ({item}: {item: VotesItem}) => + const renderItem = ({item}: {item: VoteItem}) => return ( { +const LikedByItem = ({item}: {item: VoteItem}) => { const pal = usePalette('default') return ( diff --git a/src/view/com/post/PostText.tsx b/src/view/com/post/PostText.tsx index 0cdc875a..a3bcfed6 100644 --- a/src/view/com/post/PostText.tsx +++ b/src/view/com/post/PostText.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from 'react' import {observer} from 'mobx-react-lite' -import {StyleSheet, View} from 'react-native' +import {StyleProp, StyleSheet, TextStyle, View} from 'react-native' import {LoadingPlaceholder} from '../util/LoadingPlaceholder' import {ErrorMessage} from '../util/error/ErrorMessage' import {Text} from '../util/text/Text' @@ -12,7 +12,7 @@ export const PostText = observer(function PostText({ style, }: { uri: string - style?: StyleProp + style?: StyleProp }) { const store = useStores() const [model, setModel] = useState() diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index 584fa097..cda2ac0b 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -4,7 +4,10 @@ import {StyleSheet, View} from 'react-native' import Clipboard from '@react-native-clipboard/clipboard' import Svg, {Circle, Line} from 'react-native-svg' import {AtUri} from '../../../third-party/uri' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {FeedItemModel} from '../../../state/models/feed-view' import {Link} from '../util/Link' import {Text} from '../util/text/Text' @@ -137,7 +140,10 @@ export const FeedItem = observer(function ({ }> Reposted by{' '} @@ -167,7 +173,10 @@ export const FeedItem = observer(function ({ Reply to diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx index 2e67873c..bd7e7a3c 100644 --- a/src/view/com/profile/ProfileFollows.tsx +++ b/src/view/com/profile/ProfileFollows.tsx @@ -97,7 +97,11 @@ const User = ({item}: {item: FollowItem}) => { size={40} displayName={item.displayName} handle={item.handle} - avatar={item.avatar} + avatar={ + item.avatar as + | string + | undefined /* HACK: type signature is wrong in the api */ + } /> diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 2f98fce2..d0cf4976 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -8,7 +8,10 @@ import { View, } from 'react-native' import LinearGradient from 'react-native-linear-gradient' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {BlurView} from '@react-native-community/blur' import {ProfileViewModel} from '../../../state/models/profile-view' import {useStores} from '../../../state' @@ -142,7 +145,7 @@ export const ProfileHeader = observer(function ProfileHeader({ } return ( - + {isMe ? ( @@ -181,7 +184,10 @@ export const ProfileHeader = observer(function ProfileHeader({ start={{x: 0, y: 0}} end={{x: 1, y: 1}} style={[styles.btn, styles.gradientBtn]}> - + Follow diff --git a/src/view/com/util/EmptyState.tsx b/src/view/com/util/EmptyState.tsx index 6218027d..6c5c3f34 100644 --- a/src/view/com/util/EmptyState.tsx +++ b/src/view/com/util/EmptyState.tsx @@ -1,7 +1,10 @@ import React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {IconProp} from '@fortawesome/fontawesome-svg-core' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {Text} from './text/Text' import {UserGroupIcon} from '../../lib/icons' import {usePalette} from '../../lib/hooks/usePalette' @@ -25,7 +28,10 @@ export function EmptyState({ )} diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx index 9828058e..9bb200d5 100644 --- a/src/view/com/util/LoadingPlaceholder.tsx +++ b/src/view/com/util/LoadingPlaceholder.tsx @@ -63,7 +63,7 @@ export function PostLoadingPlaceholder({ diff --git a/src/view/com/util/PostCtrls.tsx b/src/view/com/util/PostCtrls.tsx index bde44aba..fca70b68 100644 --- a/src/view/com/util/PostCtrls.tsx +++ b/src/view/com/util/PostCtrls.tsx @@ -7,7 +7,10 @@ import { View, ViewStyle, } from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import ReactNativeHapticFeedback from 'react-native-haptic-feedback' import {Text} from './text/Text' import {PostDropdownBtn} from './forms/DropdownButton' @@ -147,7 +150,9 @@ export function PostCtrls(opts: PostCtrlsOpts) { {opts.isUpvoted ? ( ) : ( @@ -214,7 +222,7 @@ export function PostCtrls(opts: PostCtrlsOpts) { { color: theme.colorScheme === 'light' ? colors.gray4 : colors.gray5, - }, + } as FontAwesomeIconStyle, ]} /> diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index c8b1b2d9..472db7ee 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -6,7 +6,10 @@ import { TouchableOpacity, View, } from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeIconStyle, +} from '@fortawesome/react-native-fontawesome' import {UserAvatar} from './UserAvatar' import {Text} from './text/Text' import {MagnifyingGlassIcon} from '../../lib/icons' @@ -92,7 +95,11 @@ export const ViewHeader = observer(function ViewHeader({ ) : ( <> - + - + - + Try again diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx index 33387f89..1fa03f4c 100644 --- a/src/view/com/util/forms/DropdownButton.tsx +++ b/src/view/com/util/forms/DropdownButton.tsx @@ -37,7 +37,7 @@ export function DropdownButton({ menuWidth, children, }: { - type: DropdownButtonType + type?: DropdownButtonType style?: StyleProp items: DropdownItem[] label?: string diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx index cedd3bc9..cdefc712 100644 --- a/src/view/com/util/images/AutoSizedImage.tsx +++ b/src/view/com/util/images/AutoSizedImage.tsx @@ -30,6 +30,7 @@ export function AutoSizedImage({ }: { uri: string onPress?: () => void + onLongPress?: () => void style?: StyleProp containerStyle?: StyleProp }) { @@ -68,7 +69,7 @@ export function AutoSizedImage({ }) } - let calculatedStyle: StyleProp | undefined + let calculatedStyle: StyleProp | undefined if (imgInfo && containerInfo) { // imgInfo.height / imgInfo.width = x / containerInfo.width // x = imgInfo.height / imgInfo.width * containerInfo.width diff --git a/src/view/com/util/images/ImageLayoutGrid.tsx b/src/view/com/util/images/ImageLayoutGrid.tsx index dd0ea377..97ad9d70 100644 --- a/src/view/com/util/images/ImageLayoutGrid.tsx +++ b/src/view/com/util/images/ImageLayoutGrid.tsx @@ -13,7 +13,7 @@ import {DELAY_PRESS_IN} from './constants' interface Dim { width: number - height: numberPressIn + height: number } export type ImageLayoutGridType = 'two' | 'three' | 'four' @@ -28,6 +28,7 @@ export function ImageLayoutGrid({ type: ImageLayoutGridType uris: string[] onPress?: (index: number) => void + onLongPress?: (index: number) => void style?: StyleProp }) { const [containerInfo, setContainerInfo] = React.useState() @@ -64,6 +65,7 @@ function ImageLayoutGridInner({ type: ImageLayoutGridType uris: string[] onPress?: (index: number) => void + onLongPress?: (index: number) => void containerInfo: Dim }) { const size1 = React.useMemo(() => { @@ -91,14 +93,14 @@ function ImageLayoutGridInner({ onPress?.(0)} - onLongPress={() => onLongPress(0)}> + onLongPress={() => onLongPress?.(0)}> onPress?.(1)} - onLongPress={() => onLongPress(1)}> + onLongPress={() => onLongPress?.(1)}> @@ -110,7 +112,7 @@ function ImageLayoutGridInner({ onPress?.(0)} - onLongPress={() => onLongPress(0)}> + onLongPress={() => onLongPress?.(0)}> @@ -118,14 +120,14 @@ function ImageLayoutGridInner({ onPress?.(1)} - onLongPress={() => onLongPress(1)}> + onLongPress={() => onLongPress?.(1)}> onPress?.(2)} - onLongPress={() => onLongPress(2)}> + onLongPress={() => onLongPress?.(2)}> @@ -139,14 +141,14 @@ function ImageLayoutGridInner({ onPress?.(0)} - onLongPress={() => onLongPress(0)}> + onLongPress={() => onLongPress?.(0)}> onPress?.(1)} - onLongPress={() => onLongPress(1)}> + onLongPress={() => onLongPress?.(1)}> @@ -155,14 +157,14 @@ function ImageLayoutGridInner({ onPress?.(2)} - onLongPress={() => onLongPress(2)}> + onLongPress={() => onLongPress?.(2)}> onPress?.(3)} - onLongPress={() => onLongPress(3)}> + onLongPress={() => onLongPress?.(3)}> diff --git a/src/view/lib/icons.tsx b/src/view/lib/icons.tsx index bfcbb26b..f4224ea2 100644 --- a/src/view/lib/icons.tsx +++ b/src/view/lib/icons.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {StyleProp, ViewStyle} from 'react-native' +import {StyleProp, TextStyle, ViewStyle} from 'react-native' import Svg, {Path} from 'react-native-svg' export function GridIcon({ @@ -428,12 +428,21 @@ export function CommentBottomArrow({ size?: string | number strokeWidth?: number }) { + let color = 'currentColor' + if ( + style && + typeof style === 'object' && + 'color' in style && + typeof style.color === 'string' + ) { + color = style.color + } return ( diff --git a/src/view/routes.ts b/src/view/routes.ts index b5cc014f..98e8111b 100644 --- a/src/view/routes.ts +++ b/src/view/routes.ts @@ -21,7 +21,7 @@ export type ScreenParams = { navIdx: string params: Record visible: boolean - scrollElRef?: MutableRefObject | undefined> + scrollElRef?: MutableRefObject | null> } export type Route = [React.FC, string, IconProp, RegExp] export type MatchResult = { diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx index 865f62dc..0223e631 100644 --- a/src/view/screens/Debug.tsx +++ b/src/view/screens/Debug.tsx @@ -5,14 +5,13 @@ import {ThemeProvider} from '../lib/ThemeContext' import {PaletteColorName} from '../lib/ThemeContext' import {usePalette} from '../lib/hooks/usePalette' import {s} from '../lib/styles' -import {DEF_AVATAR} from '../lib/assets' import {displayNotification} from '../lib/notifee' import {Text} from '../com/util/text/Text' import {ViewSelector} from '../com/util/ViewSelector' import {EmptyState} from '../com/util/EmptyState' import * as LoadingPlaceholder from '../com/util/LoadingPlaceholder' -import {Button} from '../com/util/forms/Button' +import {Button, ButtonType} from '../com/util/forms/Button' import {DropdownButton, DropdownItem} from '../com/util/forms/DropdownButton' import {ToggleButton} from '../com/util/forms/ToggleButton' import {RadioGroup} from '../com/util/forms/RadioGroup' @@ -48,9 +47,9 @@ function DebugInner({ const [currentView, setCurrentView] = React.useState(0) const pal = usePalette('default') - const renderItem = (item, i) => { + const renderItem = (item: any) => { return ( - + { - displayNotification( - 'Paul Frazee liked your post', - "Hello world! This is a test of the notifications card. The text is long to see how that's handled.", - DEF_AVATAR, - ) - } return ( - ) @@ -484,14 +475,14 @@ const RADIO_BUTTON_ITEMS = [ ] function RadioButtonsView() { const defaultPal = usePalette('default') - const [rgType, setRgType] = React.useState('default-light') + const [rgType, setRgType] = React.useState('default-light') return ( setRgType(v as ButtonType)} /> ) diff --git a/src/view/shell/desktop-web/left-column.tsx b/src/view/shell/desktop-web/left-column.tsx index fabb8bc9..3ce6c2ec 100644 --- a/src/view/shell/desktop-web/left-column.tsx +++ b/src/view/shell/desktop-web/left-column.tsx @@ -1,55 +1,57 @@ import React from 'react' -import {Pressable, View, StyleSheet} from 'react-native' +import {View} from 'react-native' -export const NavItem: React.FC<{label: string; screen: string}> = ({ - label, - screen, -}) => { - const Link = <> // TODO - return ( - - [ - // @ts-ignore it does exist! (react-native-web) -prf - state.hovered && styles.navItemHovered, - ]}> - - {label} - - - - ) -} +// export const NavItem: React.FC<{label: string; screen: string}> = ({ +// label, +// screen, +// }) => { +// const Link = <> // TODO +// return ( +// +// [ +// // @ts-ignore it does exist! (react-native-web) -prf +// state.hovered && styles.navItemHovered, +// ]}> +// +// {label} +// +// +// +// ) +// } export const DesktopLeftColumn: React.FC = () => { - return ( - - - - - - ) + // TODO + return + // return ( + // + // + // + // + // + // ) } -const styles = StyleSheet.create({ - container: { - position: 'absolute', - left: 'calc(50vw - 500px)', - width: '200px', - height: '100%', - }, - navItemHovered: { - backgroundColor: 'gray', - }, - navItemLink: { - padding: '1rem', - }, - navItemLinkSelected: { - color: 'blue', - }, -}) +// const styles = StyleSheet.create({ +// container: { +// position: 'absolute', +// left: 'calc(50vw - 500px)', +// width: '200px', +// height: '100%', +// }, +// navItemHovered: { +// backgroundColor: 'gray', +// }, +// navItemLink: { +// padding: '1rem', +// }, +// navItemLinkSelected: { +// color: 'blue', +// }, +// }) diff --git a/src/view/shell/mobile/TabsSelector.tsx b/src/view/shell/mobile/TabsSelector.tsx index 43347160..921a0c85 100644 --- a/src/view/shell/mobile/TabsSelector.tsx +++ b/src/view/shell/mobile/TabsSelector.tsx @@ -36,11 +36,12 @@ export const TabsSelector = observer( undefined, ) const closeInterp = useAnimatedValue(0) + const tabsContainerRef = useRef(null) const tabsRef = useRef(null) const tabRefs = useMemo( () => Array.from({length: store.nav.tabs.length}).map(() => - createRef(), + createRef(), ), [store.nav.tabs.length], ) @@ -90,9 +91,9 @@ export const TabsSelector = observer( const onLayout = () => { // focus the current tab const targetTab = tabRefs[store.nav.tabIndex] - if (tabsRef.current && targetTab.current) { + if (tabsContainerRef.current && tabsRef.current && targetTab.current) { targetTab.current.measureLayout?.( - tabsRef.current, + tabsContainerRef.current, (_left: number, top: number) => { tabsRef.current?.scrollTo({y: top, animated: false}) }, @@ -162,7 +163,9 @@ export const TabsSelector = observer( - + {store.nav.tabs.map((tab, tabIndex) => { const {icon} = match(tab.current.url) diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx index 62ab7a2a..b0b83b12 100644 --- a/src/view/shell/mobile/index.tsx +++ b/src/view/shell/mobile/index.tsx @@ -67,29 +67,36 @@ const Btn = ({ onLongPress?: (event: GestureResponderEvent) => void }) => { const pal = usePalette('default') - let size = 24 - let addedStyles - let IconEl + let iconEl if (icon === 'menu') { - IconEl = GridIcon + iconEl = } else if (icon === 'menu-solid') { - IconEl = GridIconSolid + iconEl = } else if (icon === 'home') { - IconEl = HomeIcon - size = 27 + iconEl = } else if (icon === 'home-solid') { - IconEl = HomeIconSolid - size = 27 + iconEl = } else if (icon === 'bell') { - IconEl = BellIcon - size = 27 - addedStyles = {position: 'relative', top: -1} as ViewStyle + const addedStyles = {position: 'relative', top: -1} as ViewStyle + iconEl = ( + + ) } else if (icon === 'bell-solid') { - IconEl = BellIconSolid - size = 27 - addedStyles = {position: 'relative', top: -1} as ViewStyle + const addedStyles = {position: 'relative', top: -1} as ViewStyle + iconEl = ( + + ) } else { - IconEl = FontAwesomeIcon + iconEl = ( + + ) } return ( @@ -108,11 +115,7 @@ const Btn = ({ {tabCount} ) : undefined} - + {iconEl} ) } @@ -122,7 +125,7 @@ export const MobileShell: React.FC = observer(() => { const pal = usePalette('default') const store = useStores() const [isTabsSelectorActive, setTabsSelectorActive] = useState(false) - const scrollElRef = useRef() + const scrollElRef = useRef(null) const winDim = useWindowDimensions() const [menuSwipingDirection, setMenuSwipingDirection] = useState(0) const swipeGestureInterp = useAnimatedValue(0) @@ -292,9 +295,11 @@ export const MobileShell: React.FC = observer(() => { ) shouldRenderMenu = true } - const menuSwipeTransform = { - transform: [{translateX: menuTranslateX}], - } + const menuSwipeTransform = menuTranslateX + ? { + transform: [{translateX: menuTranslateX}], + } + : undefined const swipeOpacity = { opacity: swipeGestureInterp.interpolate({ inputRange: [-1, 0, 1], @@ -417,10 +422,7 @@ export const MobileShell: React.FC = observer(() => { ) : undefined} {shouldRenderMenu && ( - store.shell.setMainMenuOpen(false)} - /> + store.shell.setMainMenuOpen(false)} /> )}