Fix all type errors
parent
c4ba5e7fd5
commit
7e3f6f0306
|
@ -6,7 +6,7 @@ const BottomSheetModalContext = React.createContext(null)
|
||||||
const BottomSheetModalProvider = (props: any) => {
|
const BottomSheetModalProvider = (props: any) => {
|
||||||
return <BottomSheetModalContext.Provider {...props} value={{}} />
|
return <BottomSheetModalContext.Provider {...props} value={{}} />
|
||||||
}
|
}
|
||||||
class BottomSheet extends React.Component {
|
class BottomSheet extends React.Component<{onClose?: () => void}> {
|
||||||
snapToIndex() {}
|
snapToIndex() {}
|
||||||
snapToPosition() {}
|
snapToPosition() {}
|
||||||
expand() {}
|
expand() {}
|
||||||
|
|
|
@ -9,11 +9,9 @@ import {MeModel} from '../src/state/models/me'
|
||||||
import {OnboardModel} from '../src/state/models/onboard'
|
import {OnboardModel} from '../src/state/models/onboard'
|
||||||
import {ProfilesViewModel} from '../src/state/models/profiles-view'
|
import {ProfilesViewModel} from '../src/state/models/profiles-view'
|
||||||
import {LinkMetasViewModel} from '../src/state/models/link-metas-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 {FeedModel} from '../src/state/models/feed-view'
|
||||||
import {NotificationsViewModel} from '../src/state/models/notifications-view'
|
import {NotificationsViewModel} from '../src/state/models/notifications-view'
|
||||||
import {ProfileViewModel} from '../src/state/models/profile-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 {ProfileUiModel, Sections} from '../src/state/models/profile-ui'
|
||||||
import {SessionServiceClient} from '@atproto/api'
|
import {SessionServiceClient} from '@atproto/api'
|
||||||
import {UserAutocompleteViewModel} from '../src/state/models/user-autocomplete-view'
|
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
|
// unknown required because of the missing private methods: _xLoading, _xIdle, _load, _replaceAll
|
||||||
} as unknown as ProfileViewModel
|
} 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 = {
|
export const mockedFeedItemStore = {
|
||||||
_reactKey: 'item-1',
|
_reactKey: 'item-1',
|
||||||
_isThreadParent: false,
|
_isThreadParent: false,
|
||||||
_isThreadChildElided: false,
|
_isThreadChildElided: false,
|
||||||
_isThreadChild: false,
|
_isThreadChild: false,
|
||||||
|
_hideParent: false,
|
||||||
|
_isRenderingAsThread: false,
|
||||||
post: {
|
post: {
|
||||||
uri: 'testuri',
|
uri: 'testuri',
|
||||||
cid: 'test cid',
|
cid: 'test cid',
|
||||||
|
@ -475,13 +391,13 @@ export const mockedSessionStore = {
|
||||||
export const mockedNavigationTabStore = {
|
export const mockedNavigationTabStore = {
|
||||||
serialize: jest.fn(),
|
serialize: jest.fn(),
|
||||||
hydrate: jest.fn(),
|
hydrate: jest.fn(),
|
||||||
id: 0,
|
id: '0',
|
||||||
history: [
|
history: [
|
||||||
{
|
{
|
||||||
url: '',
|
url: '',
|
||||||
ts: 0,
|
ts: 0,
|
||||||
title: '',
|
title: '',
|
||||||
id: 0,
|
id: '0',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
index: 0,
|
index: 0,
|
||||||
|
@ -490,7 +406,7 @@ export const mockedNavigationTabStore = {
|
||||||
url: '',
|
url: '',
|
||||||
ts: 0,
|
ts: 0,
|
||||||
title: '',
|
title: '',
|
||||||
id: 0,
|
id: '0',
|
||||||
},
|
},
|
||||||
canGoBack: false,
|
canGoBack: false,
|
||||||
canGoForward: false,
|
canGoForward: false,
|
||||||
|
@ -499,7 +415,7 @@ export const mockedNavigationTabStore = {
|
||||||
url: '',
|
url: '',
|
||||||
title: '',
|
title: '',
|
||||||
index: 0,
|
index: 0,
|
||||||
id: 0,
|
id: '0',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
forwardTen: [
|
forwardTen: [
|
||||||
|
@ -507,7 +423,7 @@ export const mockedNavigationTabStore = {
|
||||||
url: '',
|
url: '',
|
||||||
title: '',
|
title: '',
|
||||||
index: 0,
|
index: 0,
|
||||||
id: 0,
|
id: '0',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
navigate: jest.fn(),
|
navigate: jest.fn(),
|
||||||
|
@ -524,7 +440,7 @@ export const mockedNavigationTabStore = {
|
||||||
url: '/',
|
url: '/',
|
||||||
title: '',
|
title: '',
|
||||||
index: 1,
|
index: 1,
|
||||||
id: 1,
|
id: '1',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
getForwardList: jest.fn(),
|
getForwardList: jest.fn(),
|
||||||
|
@ -582,13 +498,13 @@ export const mockedMeStore = {
|
||||||
avatar: '',
|
avatar: '',
|
||||||
notificationCount: 0,
|
notificationCount: 0,
|
||||||
rootStore: {} as RootStoreModel,
|
rootStore: {} as RootStoreModel,
|
||||||
memberships: mockedMembershipsStore,
|
|
||||||
mainFeed: mockedFeedStore,
|
mainFeed: mockedFeedStore,
|
||||||
notifications: mockedNotificationsStore,
|
notifications: mockedNotificationsStore,
|
||||||
clear: jest.fn(),
|
clear: jest.fn(),
|
||||||
load: jest.fn(),
|
load: jest.fn(),
|
||||||
clearNotificationCount: jest.fn(),
|
clearNotificationCount: jest.fn(),
|
||||||
fetchNotifications: jest.fn(),
|
fetchNotifications: jest.fn(),
|
||||||
|
bgFetchNotifications: jest.fn(),
|
||||||
refreshMemberships: jest.fn(),
|
refreshMemberships: jest.fn(),
|
||||||
} as MeModel
|
} as MeModel
|
||||||
|
|
||||||
|
@ -650,6 +566,11 @@ export const mockedRootStore = {
|
||||||
hydrate: jest.fn(),
|
hydrate: jest.fn(),
|
||||||
fetchStateUpdate: jest.fn(),
|
fetchStateUpdate: jest.fn(),
|
||||||
clearAll: jest.fn(),
|
clearAll: jest.fn(),
|
||||||
|
onPostDeleted: jest.fn(),
|
||||||
|
emitPostDeleted: jest.fn(),
|
||||||
|
initBgFetch: jest.fn(),
|
||||||
|
onBgFetch: jest.fn(),
|
||||||
|
onBgFetchTimeout: jest.fn(),
|
||||||
session: mockedSessionStore,
|
session: mockedSessionStore,
|
||||||
nav: mockedNavigationStore,
|
nav: mockedNavigationStore,
|
||||||
shell: mockedShellStore,
|
shell: mockedShellStore,
|
||||||
|
@ -663,8 +584,6 @@ export const mockedRootStore = {
|
||||||
export const mockedProfileUiStore = {
|
export const mockedProfileUiStore = {
|
||||||
profile: mockedProfileStore,
|
profile: mockedProfileStore,
|
||||||
feed: mockedFeedStore,
|
feed: mockedFeedStore,
|
||||||
memberships: mockedMembershipsStore,
|
|
||||||
members: mockedMembersStore,
|
|
||||||
selectedViewIndex: 0,
|
selectedViewIndex: 0,
|
||||||
rootStore: mockedRootStore,
|
rootStore: mockedRootStore,
|
||||||
params: {
|
params: {
|
||||||
|
@ -675,7 +594,7 @@ export const mockedProfileUiStore = {
|
||||||
isRefreshing: false,
|
isRefreshing: false,
|
||||||
isUser: true,
|
isUser: true,
|
||||||
isScene: false,
|
isScene: false,
|
||||||
selectorItems: [Sections.Posts, Sections.PostsWithReplies, Sections.Scenes],
|
selectorItems: [Sections.Posts, Sections.PostsWithReplies],
|
||||||
selectedView: Sections.Posts,
|
selectedView: Sections.Posts,
|
||||||
setSelectedViewIndex: jest.fn(),
|
setSelectedViewIndex: jest.fn(),
|
||||||
setup: jest.fn().mockResolvedValue({aborted: false}),
|
setup: jest.fn().mockResolvedValue({aborted: false}),
|
||||||
|
|
|
@ -41,6 +41,7 @@ describe('extractHtmlMeta', () => {
|
||||||
|
|
||||||
it.each(cases)(
|
it.each(cases)(
|
||||||
'given the html tag %p, returns %p',
|
'given the html tag %p, returns %p',
|
||||||
|
// @ts-ignore not worth fixing -prf
|
||||||
(input, expectedResult) => {
|
(input, expectedResult) => {
|
||||||
const output = extractHtmlMeta({html: input as string, hostname: ''})
|
const output = extractHtmlMeta({html: input as string, hostname: ''})
|
||||||
expect(output).toEqual(expectedResult)
|
expect(output).toEqual(expectedResult)
|
||||||
|
@ -86,6 +87,7 @@ describe('extractHtmlMeta', () => {
|
||||||
title: '@bluesky on Twitter',
|
title: '@bluesky on Twitter',
|
||||||
}
|
}
|
||||||
const output = extractHtmlMeta({
|
const output = extractHtmlMeta({
|
||||||
|
html: '',
|
||||||
hostname: 'twitter.com',
|
hostname: 'twitter.com',
|
||||||
pathname: '/bluesky',
|
pathname: '/bluesky',
|
||||||
})
|
})
|
||||||
|
@ -97,6 +99,7 @@ describe('extractHtmlMeta', () => {
|
||||||
title: 'Tweet by @bluesky',
|
title: 'Tweet by @bluesky',
|
||||||
}
|
}
|
||||||
const output = extractHtmlMeta({
|
const output = extractHtmlMeta({
|
||||||
|
html: '',
|
||||||
hostname: 'twitter.com',
|
hostname: 'twitter.com',
|
||||||
pathname: '/bluesky/status/1582437529969917953',
|
pathname: '/bluesky/status/1582437529969917953',
|
||||||
})
|
})
|
||||||
|
@ -108,6 +111,7 @@ describe('extractHtmlMeta', () => {
|
||||||
title: 'Twitter',
|
title: 'Twitter',
|
||||||
}
|
}
|
||||||
const output = extractHtmlMeta({
|
const output = extractHtmlMeta({
|
||||||
|
html: '',
|
||||||
hostname: 'twitter.com',
|
hostname: 'twitter.com',
|
||||||
pathname: '/i/articles/follows/-1675653703?time_window=24',
|
pathname: '/i/articles/follows/-1675653703?time_window=24',
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {mockedRootStore, mockedShellStore} from '../../../__mocks__/state-mock'
|
||||||
|
|
||||||
describe('useOnMainScroll', () => {
|
describe('useOnMainScroll', () => {
|
||||||
const mockedProps = {
|
const mockedProps = {
|
||||||
navIdx: [0, 0] as [number, number],
|
navIdx: '0-0',
|
||||||
params: {},
|
params: {},
|
||||||
visible: true,
|
visible: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {cleanup, fireEvent, render} from '../../../jest/test-utils'
|
||||||
describe('Search', () => {
|
describe('Search', () => {
|
||||||
jest.useFakeTimers()
|
jest.useFakeTimers()
|
||||||
const mockedProps = {
|
const mockedProps = {
|
||||||
navIdx: [0, 0] as [number, number],
|
navIdx: '0-0',
|
||||||
params: {
|
params: {
|
||||||
name: 'test name',
|
name: 'test name',
|
||||||
},
|
},
|
||||||
|
|
|
@ -179,7 +179,7 @@ async function genMockData(pdsUrl: string): Promise<TestUsers> {
|
||||||
did: subject.did,
|
did: subject.did,
|
||||||
declarationCid: subject.declarationCid,
|
declarationCid: subject.declarationCid,
|
||||||
},
|
},
|
||||||
createdAt: date.next().value,
|
createdAt: date.next().value || '',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, {useState, useEffect} from 'react'
|
||||||
import * as view from './view/index'
|
import * as view from './view/index'
|
||||||
import {RootStoreModel, setupState, RootStoreProvider} from './state'
|
import {RootStoreModel, setupState, RootStoreProvider} from './state'
|
||||||
import {DesktopWebShell} from './view/shell/desktop-web'
|
import {DesktopWebShell} from './view/shell/desktop-web'
|
||||||
import Toast from 'react-native-root-toast'
|
// import Toast from 'react-native-root-toast' TODO
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
|
const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
|
||||||
|
@ -23,9 +23,9 @@ function App() {
|
||||||
return (
|
return (
|
||||||
<RootStoreProvider value={rootStore}>
|
<RootStoreProvider value={rootStore}>
|
||||||
<DesktopWebShell />
|
<DesktopWebShell />
|
||||||
<Toast.ToastContainer />
|
|
||||||
</RootStoreProvider>
|
</RootStoreProvider>
|
||||||
)
|
)
|
||||||
|
// <Toast.ToastContainer /> TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App
|
||||||
|
|
|
@ -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
|
// Workaround for some websites not having a title or description in the meta tags in the initial serve
|
||||||
if (isYoutubeUrl) {
|
if (isYoutubeUrl) {
|
||||||
res = {...res, ...extractYoutubeMeta(html)}
|
res = {...res, ...extractYoutubeMeta(html)}
|
||||||
} else if (isTwitterUrl) {
|
} else if (isTwitterUrl && pathname) {
|
||||||
res = {...extractTwitterMeta({pathname})}
|
res = {...extractTwitterMeta({pathname})}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,8 +98,6 @@ export class ProfileUiModel {
|
||||||
const view = this.currentView
|
const view = this.currentView
|
||||||
if (view instanceof FeedModel) {
|
if (view instanceof FeedModel) {
|
||||||
await view.update()
|
await view.update()
|
||||||
} else {
|
|
||||||
await view.refresh()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@ import PasteInput, {
|
||||||
PasteInputRef,
|
PasteInputRef,
|
||||||
} from '@mattermost/react-native-paste-input'
|
} from '@mattermost/react-native-paste-input'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
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 {useAnalytics} from '@segment/analytics-react-native'
|
||||||
import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
|
import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
|
||||||
import {Autocomplete} from './Autocomplete'
|
import {Autocomplete} from './Autocomplete'
|
||||||
|
@ -438,7 +441,11 @@ export const ComposePost = observer(function ComposePost({
|
||||||
hitSlop={HITSLOP}>
|
hitSlop={HITSLOP}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={['far', 'image']}
|
icon={['far', 'image']}
|
||||||
style={selectedPhotos.length < 4 ? pal.link : pal.textLight}
|
style={
|
||||||
|
(selectedPhotos.length < 4
|
||||||
|
? pal.link
|
||||||
|
: pal.textLight) as FontAwesomeIconStyle
|
||||||
|
}
|
||||||
size={24}
|
size={24}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React, {useCallback} from 'react'
|
import React, {useCallback} from 'react'
|
||||||
import {Image, StyleSheet, TouchableOpacity, ScrollView} from 'react-native'
|
import {Image, StyleSheet, TouchableOpacity, ScrollView} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {
|
import {
|
||||||
openPicker,
|
openPicker,
|
||||||
openCamera,
|
openCamera,
|
||||||
|
@ -131,13 +134,21 @@ export const PhotoCarouselPicker = ({
|
||||||
testID="openCameraButton"
|
testID="openCameraButton"
|
||||||
style={[styles.galleryButton, pal.border, styles.photo]}
|
style={[styles.galleryButton, pal.border, styles.photo]}
|
||||||
onPress={handleOpenCamera}>
|
onPress={handleOpenCamera}>
|
||||||
<FontAwesomeIcon icon="camera" size={24} style={pal.link} />
|
<FontAwesomeIcon
|
||||||
|
icon="camera"
|
||||||
|
size={24}
|
||||||
|
style={pal.link as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="openGalleryButton"
|
testID="openGalleryButton"
|
||||||
style={[styles.galleryButton, pal.border, styles.photo]}
|
style={[styles.galleryButton, pal.border, styles.photo]}
|
||||||
onPress={handleOpenGallery}>
|
onPress={handleOpenGallery}>
|
||||||
<FontAwesomeIcon icon="image" style={pal.link} size={24} />
|
<FontAwesomeIcon
|
||||||
|
icon="image"
|
||||||
|
style={pal.link as FontAwesomeIconStyle}
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
{localPhotos.photos.map((item: PhotoIdentifier, index: number) => (
|
{localPhotos.photos.map((item: PhotoIdentifier, index: number) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
|
|
@ -7,7 +7,10 @@ import {
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import _omit from 'lodash.omit'
|
import _omit from 'lodash.omit'
|
||||||
import {ErrorScreen} from '../util/error/ErrorScreen'
|
import {ErrorScreen} from '../util/error/ErrorScreen'
|
||||||
|
@ -199,7 +202,7 @@ const User = ({
|
||||||
style={[styles.btn, styles.gradientBtn]}>
|
style={[styles.btn, styles.gradientBtn]}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="plus"
|
icon="plus"
|
||||||
style={[s.white, s.mr5]}
|
style={[s.white as FontAwesomeIconStyle, s.mr5]}
|
||||||
size={15}
|
size={15}
|
||||||
/>
|
/>
|
||||||
<Text style={[s.white, s.fw600, s.f15]}>Follow</Text>
|
<Text style={[s.white, s.fw600, s.f15]}>Follow</Text>
|
||||||
|
|
|
@ -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 <View />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ImageItem)
|
|
@ -47,8 +47,8 @@ const useImageDimensions = (image: ImageSource): Dimensions | null => {
|
||||||
if (imageDimensions) {
|
if (imageDimensions) {
|
||||||
resolve(imageDimensions)
|
resolve(imageDimensions)
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
|
||||||
Image.getSizeWithHeaders(
|
Image.getSizeWithHeaders(
|
||||||
|
// @ts-ignore
|
||||||
source.uri,
|
source.uri,
|
||||||
source.headers,
|
source.headers,
|
||||||
(width: number, height: number) => {
|
(width: number, height: number) => {
|
||||||
|
|
|
@ -61,7 +61,7 @@ const usePanResponder = ({
|
||||||
let tmpTranslate: Position | null = null
|
let tmpTranslate: Position | null = null
|
||||||
let isDoubleTapPerformed = false
|
let isDoubleTapPerformed = false
|
||||||
let lastTapTS: number | null = null
|
let lastTapTS: number | null = null
|
||||||
let longPressHandlerRef: number | null = null
|
let longPressHandlerRef: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
const meaningfulShift = MIN_DIMENSION * 0.01
|
const meaningfulShift = MIN_DIMENSION * 0.01
|
||||||
const scaleValue = new Animated.Value(initialScale)
|
const scaleValue = new Animated.Value(initialScale)
|
||||||
|
|
|
@ -77,6 +77,7 @@ export const getImageStyles = (
|
||||||
const transform = translate.getTranslateTransform()
|
const transform = translate.getTranslateTransform()
|
||||||
|
|
||||||
if (scale) {
|
if (scale) {
|
||||||
|
// @ts-ignore TODO - is scale incorrect? might need to remove -prf
|
||||||
transform.push({scale}, {perspective: new Animated.Value(1000)})
|
transform.push({scale}, {perspective: new Animated.Value(1000)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ImageView from './ImageViewing'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import * as models from '../../../state/models/shell-ui'
|
import * as models from '../../../state/models/shell-ui'
|
||||||
import {saveImageModal} from '../../../lib/images'
|
import {saveImageModal} from '../../../lib/images'
|
||||||
|
import {ImageSource} from './ImageViewing/@types'
|
||||||
|
|
||||||
export const Lightbox = observer(function Lightbox() {
|
export const Lightbox = observer(function Lightbox() {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
@ -15,8 +16,14 @@ export const Lightbox = observer(function Lightbox() {
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
store.shell.closeLightbox()
|
store.shell.closeLightbox()
|
||||||
}
|
}
|
||||||
const onLongPress = ({uri}: {uri: string}) => {
|
const onLongPress = (image: ImageSource) => {
|
||||||
saveImageModal({uri})
|
if (
|
||||||
|
typeof image === 'object' &&
|
||||||
|
'uri' in image &&
|
||||||
|
typeof image.uri === 'string'
|
||||||
|
) {
|
||||||
|
saveImageModal({uri: image.uri})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (store.shell.activeLightbox?.name === 'profile-image') {
|
if (store.shell.activeLightbox?.name === 'profile-image') {
|
||||||
|
|
|
@ -9,7 +9,10 @@ import {
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {ComAtprotoAccountCreate} from '@atproto/api'
|
import {ComAtprotoAccountCreate} from '@atproto/api'
|
||||||
import * as EmailValidator from 'email-validator'
|
import * as EmailValidator from 'email-validator'
|
||||||
import {useAnalytics} from '@segment/analytics-react-native'
|
import {useAnalytics} from '@segment/analytics-react-native'
|
||||||
|
@ -264,7 +267,7 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
|
||||||
<Picker
|
<Picker
|
||||||
style={[pal.text, styles.picker]}
|
style={[pal.text, styles.picker]}
|
||||||
labelStyle={styles.pickerLabel}
|
labelStyle={styles.pickerLabel}
|
||||||
iconStyle={pal.textLight}
|
iconStyle={pal.textLight as FontAwesomeIconStyle}
|
||||||
value={userDomain}
|
value={userDomain}
|
||||||
items={serviceDescription.availableUserDomains.map(d => ({
|
items={serviceDescription.availableUserDomains.map(d => ({
|
||||||
label: `.${d}`,
|
label: `.${d}`,
|
||||||
|
@ -371,7 +374,11 @@ const Policies = ({
|
||||||
return (
|
return (
|
||||||
<View style={styles.policies}>
|
<View style={styles.policies}>
|
||||||
<View style={[styles.errorIcon, {borderColor: pal.colors.text}, s.mt2]}>
|
<View style={[styles.errorIcon, {borderColor: pal.colors.text}, s.mt2]}>
|
||||||
<FontAwesomeIcon icon="exclamation" style={pal.textLight} size={10} />
|
<FontAwesomeIcon
|
||||||
|
icon="exclamation"
|
||||||
|
style={pal.textLight as FontAwesomeIconStyle}
|
||||||
|
size={10}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Text style={[pal.textLight, s.pl5, s.flex1]}>
|
<Text style={[pal.textLight, s.pl5, s.flex1]}>
|
||||||
This service has not provided terms of service or a privacy policy.
|
This service has not provided terms of service or a privacy policy.
|
||||||
|
|
|
@ -8,7 +8,10 @@ import {
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} 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 * as EmailValidator from 'email-validator'
|
||||||
import {sessionClient as AtpApi, SessionServiceClient} from '@atproto/api'
|
import {sessionClient as AtpApi, SessionServiceClient} from '@atproto/api'
|
||||||
import {useAnalytics} from '@segment/analytics-react-native'
|
import {useAnalytics} from '@segment/analytics-react-native'
|
||||||
|
@ -337,7 +340,11 @@ const LoginForm = ({
|
||||||
{toNiceDomain(serviceUrl)}
|
{toNiceDomain(serviceUrl)}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
|
<View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
|
||||||
<FontAwesomeIcon icon="pen" size={12} style={pal.textLight} />
|
<FontAwesomeIcon
|
||||||
|
icon="pen"
|
||||||
|
size={12}
|
||||||
|
style={pal.textLight as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
@ -514,7 +521,11 @@ const ForgotPasswordForm = ({
|
||||||
{toNiceDomain(serviceUrl)}
|
{toNiceDomain(serviceUrl)}
|
||||||
</Text>
|
</Text>
|
||||||
<View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
|
<View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
|
||||||
<FontAwesomeIcon icon="pen" size={12} style={pal.text} />
|
<FontAwesomeIcon
|
||||||
|
icon="pen"
|
||||||
|
size={12}
|
||||||
|
style={pal.text as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={[pal.borderDark, styles.groupContent]}>
|
<View style={[pal.borderDark, styles.groupContent]}>
|
||||||
|
|
|
@ -108,7 +108,6 @@ export function Component({
|
||||||
<UserBanner
|
<UserBanner
|
||||||
banner={userBanner}
|
banner={userBanner}
|
||||||
onSelectNewBanner={onSelectNewBanner}
|
onSelectNewBanner={onSelectNewBanner}
|
||||||
handle={profileView.handle}
|
|
||||||
/>
|
/>
|
||||||
<View style={styles.avi}>
|
<View style={styles.avi}>
|
||||||
<UserAvatar
|
<UserAvatar
|
||||||
|
|
|
@ -62,18 +62,10 @@ export const Modal = observer(function Modal() {
|
||||||
)
|
)
|
||||||
} else if (store.shell.activeModal?.name === 'report-post') {
|
} else if (store.shell.activeModal?.name === 'report-post') {
|
||||||
snapPoints = ReportPostModal.snapPoints
|
snapPoints = ReportPostModal.snapPoints
|
||||||
element = (
|
element = <ReportPostModal.Component />
|
||||||
<ReportPostModal.Component
|
|
||||||
{...(store.shell.activeModal as models.ReportPostModal)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
} else if (store.shell.activeModal?.name === 'report-account') {
|
} else if (store.shell.activeModal?.name === 'report-account') {
|
||||||
snapPoints = ReportAccountModal.snapPoints
|
snapPoints = ReportAccountModal.snapPoints
|
||||||
element = (
|
element = <ReportAccountModal.Component />
|
||||||
<ReportAccountModal.Component
|
|
||||||
{...(store.shell.activeModal as models.ReportAccountModal)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
element = <View />
|
element = <View />
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {Platform, StyleSheet, TouchableOpacity, View} from 'react-native'
|
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 {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
|
@ -37,13 +40,19 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
||||||
style={styles.btn}
|
style={styles.btn}
|
||||||
onPress={() => doSelect(LOCAL_DEV_SERVICE)}>
|
onPress={() => doSelect(LOCAL_DEV_SERVICE)}>
|
||||||
<Text style={styles.btnText}>Local dev server</Text>
|
<Text style={styles.btnText}>Local dev server</Text>
|
||||||
<FontAwesomeIcon icon="arrow-right" style={s.white} />
|
<FontAwesomeIcon
|
||||||
|
icon="arrow-right"
|
||||||
|
style={s.white as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.btn}
|
style={styles.btn}
|
||||||
onPress={() => doSelect(STAGING_SERVICE)}>
|
onPress={() => doSelect(STAGING_SERVICE)}>
|
||||||
<Text style={styles.btnText}>Staging</Text>
|
<Text style={styles.btnText}>Staging</Text>
|
||||||
<FontAwesomeIcon icon="arrow-right" style={s.white} />
|
<FontAwesomeIcon
|
||||||
|
icon="arrow-right"
|
||||||
|
style={s.white as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</>
|
</>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
@ -51,7 +60,10 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
||||||
style={styles.btn}
|
style={styles.btn}
|
||||||
onPress={() => doSelect(PROD_SERVICE)}>
|
onPress={() => doSelect(PROD_SERVICE)}>
|
||||||
<Text style={styles.btnText}>Bluesky.Social</Text>
|
<Text style={styles.btnText}>Bluesky.Social</Text>
|
||||||
<FontAwesomeIcon icon="arrow-right" style={s.white} />
|
<FontAwesomeIcon
|
||||||
|
icon="arrow-right"
|
||||||
|
style={s.white as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.group}>
|
<View style={styles.group}>
|
||||||
|
@ -74,7 +86,7 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
||||||
onPress={() => doSelect(customUrl)}>
|
onPress={() => doSelect(customUrl)}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="check"
|
icon="check"
|
||||||
style={[s.black, styles.checkIcon]}
|
style={[s.black as FontAwesomeIconStyle, styles.checkIcon]}
|
||||||
size={18}
|
size={18}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
|
@ -9,7 +9,11 @@ import {
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {AppBskyEmbedImages} from '@atproto/api'
|
import {AppBskyEmbedImages} from '@atproto/api'
|
||||||
import {AtUri} from '../../../third-party/uri'
|
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 {NotificationsViewItemModel} from '../../../state/models/notifications-view'
|
||||||
import {PostThreadViewModel} from '../../../state/models/post-thread-view'
|
import {PostThreadViewModel} from '../../../state/models/post-thread-view'
|
||||||
import {s, colors} from '../../lib/styles'
|
import {s, colors} from '../../lib/styles'
|
||||||
|
@ -98,18 +102,21 @@ export const FeedItem = observer(function FeedItem({
|
||||||
if (item.isUpvote) {
|
if (item.isUpvote) {
|
||||||
action = 'liked your post'
|
action = 'liked your post'
|
||||||
icon = 'HeartIconSolid'
|
icon = 'HeartIconSolid'
|
||||||
iconStyle = [s.red3, {position: 'relative', top: -4}]
|
iconStyle = [
|
||||||
|
s.red3 as FontAwesomeIconStyle,
|
||||||
|
{position: 'relative', top: -4},
|
||||||
|
]
|
||||||
} else if (item.isRepost) {
|
} else if (item.isRepost) {
|
||||||
action = 'reposted your post'
|
action = 'reposted your post'
|
||||||
icon = 'retweet'
|
icon = 'retweet'
|
||||||
iconStyle = [s.green3]
|
iconStyle = [s.green3 as FontAwesomeIconStyle]
|
||||||
} else if (item.isReply) {
|
} else if (item.isReply) {
|
||||||
action = 'replied to your post'
|
action = 'replied to your post'
|
||||||
icon = ['far', 'comment']
|
icon = ['far', 'comment']
|
||||||
} else if (item.isFollow) {
|
} else if (item.isFollow) {
|
||||||
action = 'followed you'
|
action = 'followed you'
|
||||||
icon = 'user-plus'
|
icon = 'user-plus'
|
||||||
iconStyle = [s.blue3]
|
iconStyle = [s.blue3 as FontAwesomeIconStyle]
|
||||||
} else {
|
} else {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
@ -292,7 +299,6 @@ function ExpandedAuthorsList({
|
||||||
authors.length * (EXPANDED_AUTHOR_EL_HEIGHT + 10) /*10=margin*/
|
authors.length * (EXPANDED_AUTHOR_EL_HEIGHT + 10) /*10=margin*/
|
||||||
const heightStyle = {
|
const heightStyle = {
|
||||||
height: Animated.multiply(heightInterp, targetHeight),
|
height: Animated.multiply(heightInterp, targetHeight),
|
||||||
overflow: 'hidden',
|
|
||||||
}
|
}
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
Animated.timing(heightInterp, {
|
Animated.timing(heightInterp, {
|
||||||
|
@ -302,7 +308,12 @@ function ExpandedAuthorsList({
|
||||||
}).start()
|
}).start()
|
||||||
}, [heightInterp, visible])
|
}, [heightInterp, visible])
|
||||||
return (
|
return (
|
||||||
<Animated.View style={[heightStyle, visible ? s.mb10 : undefined]}>
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
heightStyle,
|
||||||
|
styles.overflowHidden,
|
||||||
|
visible ? s.mb10 : undefined,
|
||||||
|
]}>
|
||||||
{authors.map(author => (
|
{authors.map(author => (
|
||||||
<Link
|
<Link
|
||||||
key={author.href}
|
key={author.href}
|
||||||
|
@ -360,6 +371,10 @@ function AdditionalPostText({
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
overflowHidden: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
|
||||||
outer: {
|
outer: {
|
||||||
padding: 10,
|
padding: 10,
|
||||||
paddingRight: 15,
|
paddingRight: 15,
|
||||||
|
|
|
@ -9,13 +9,23 @@ import {
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {TabView, SceneMap, Route, TabBarProps} from 'react-native-tab-view'
|
import {TabView, SceneMap, Route, TabBarProps} from 'react-native-tab-view'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
import {s} from '../../lib/styles'
|
import {s} from '../../lib/styles'
|
||||||
import {TABS_EXPLAINER} from '../../lib/assets'
|
import {TABS_EXPLAINER} from '../../lib/assets'
|
||||||
import {TABS_ENABLED} from '../../../build-flags'
|
import {TABS_ENABLED} from '../../../build-flags'
|
||||||
|
|
||||||
|
const ROUTES = TABS_ENABLED
|
||||||
|
? [
|
||||||
|
{key: 'intro', title: 'Intro'},
|
||||||
|
{key: 'tabs', title: 'Tabs'},
|
||||||
|
]
|
||||||
|
: [{key: 'intro', title: 'Intro'}]
|
||||||
|
|
||||||
const Intro = () => (
|
const Intro = () => (
|
||||||
<View style={styles.explainer}>
|
<View style={styles.explainer}>
|
||||||
<Text
|
<Text
|
||||||
|
@ -37,7 +47,7 @@ const Tabs = () => (
|
||||||
<View style={s.flex1} />
|
<View style={s.flex1} />
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={['far', 'clone']}
|
icon={['far', 'clone']}
|
||||||
style={[s.black, s.mb5]}
|
style={[s.black as FontAwesomeIconStyle, s.mb5]}
|
||||||
size={36}
|
size={36}
|
||||||
/>
|
/>
|
||||||
<View style={s.flex1} />
|
<View style={s.flex1} />
|
||||||
|
@ -62,14 +72,10 @@ export const FeatureExplainer = () => {
|
||||||
const layout = useWindowDimensions()
|
const layout = useWindowDimensions()
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const [index, setIndex] = useState(0)
|
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 onPressSkip = () => store.onboard.next()
|
||||||
const onPressNext = () => {
|
const onPressNext = () => {
|
||||||
if (index >= routes.length - 1) {
|
if (index >= ROUTES.length - 1) {
|
||||||
store.onboard.next()
|
store.onboard.next()
|
||||||
} else {
|
} else {
|
||||||
setIndex(index + 1)
|
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 (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
{routes.length > 1 ? (
|
{ROUTES.length > 1 ? (
|
||||||
<TabView
|
<TabView
|
||||||
navigationState={{index, routes}}
|
navigationState={{index, routes: ROUTES}}
|
||||||
renderScene={renderScene}
|
renderScene={renderScene}
|
||||||
renderTabBar={renderTabBar}
|
renderTabBar={renderTabBar}
|
||||||
onIndexChange={setIndex}
|
onIndexChange={setIndex}
|
||||||
|
|
|
@ -3,7 +3,10 @@ import {observer} from 'mobx-react-lite'
|
||||||
import {StyleSheet, View} from 'react-native'
|
import {StyleSheet, View} from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import {AtUri} from '../../../third-party/uri'
|
import {AtUri} from '../../../third-party/uri'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {PostThreadViewPostModel} from '../../../state/models/post-thread-view'
|
import {PostThreadViewPostModel} from '../../../state/models/post-thread-view'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {RichText} from '../util/text/RichText'
|
import {RichText} from '../util/text/RichText'
|
||||||
|
@ -59,7 +62,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
replyTo: {
|
replyTo: {
|
||||||
uri: item.post.uri,
|
uri: item.post.uri,
|
||||||
cid: item.post.cid,
|
cid: item.post.cid,
|
||||||
text: record.text as string,
|
text: record?.text as string,
|
||||||
author: {
|
author: {
|
||||||
handle: item.post.author.handle,
|
handle: item.post.author.handle,
|
||||||
displayName: item.post.author.displayName,
|
displayName: item.post.author.displayName,
|
||||||
|
@ -103,7 +106,10 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
return (
|
return (
|
||||||
<View style={[styles.outer, pal.border, pal.view, s.p20, s.flexRow]}>
|
<View style={[styles.outer, pal.border, pal.view, s.p20, s.flexRow]}>
|
||||||
<FontAwesomeIcon icon={['far', 'trash-can']} style={pal.icon} />
|
<FontAwesomeIcon
|
||||||
|
icon={['far', 'trash-can']}
|
||||||
|
style={pal.icon as FontAwesomeIconStyle}
|
||||||
|
/>
|
||||||
<Text style={[pal.textLight, s.ml10]}>This post has been deleted.</Text>
|
<Text style={[pal.textLight, s.ml10]}>This post has been deleted.</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, {useEffect} from 'react'
|
import React, {useEffect} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native'
|
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 {Link} from '../util/Link'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
|
@ -56,7 +56,7 @@ export const PostVotedBy = observer(function PostVotedBy({
|
||||||
|
|
||||||
// loaded
|
// loaded
|
||||||
// =
|
// =
|
||||||
const renderItem = ({item}: {item: VotesItem}) => <LikedByItem item={item} />
|
const renderItem = ({item}: {item: VoteItem}) => <LikedByItem item={item} />
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
data={view.votes}
|
data={view.votes}
|
||||||
|
@ -76,7 +76,7 @@ export const PostVotedBy = observer(function PostVotedBy({
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const LikedByItem = ({item}: {item: VotesItem}) => {
|
const LikedByItem = ({item}: {item: VoteItem}) => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, {useState, useEffect} from 'react'
|
import React, {useState, useEffect} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
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 {LoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
|
@ -12,7 +12,7 @@ export const PostText = observer(function PostText({
|
||||||
style,
|
style,
|
||||||
}: {
|
}: {
|
||||||
uri: string
|
uri: string
|
||||||
style?: StyleProp
|
style?: StyleProp<TextStyle>
|
||||||
}) {
|
}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const [model, setModel] = useState<PostModel | undefined>()
|
const [model, setModel] = useState<PostModel | undefined>()
|
||||||
|
|
|
@ -4,7 +4,10 @@ import {StyleSheet, View} from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import Svg, {Circle, Line} from 'react-native-svg'
|
import Svg, {Circle, Line} from 'react-native-svg'
|
||||||
import {AtUri} from '../../../third-party/uri'
|
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 {FeedItemModel} from '../../../state/models/feed-view'
|
||||||
import {Link} from '../util/Link'
|
import {Link} from '../util/Link'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
|
@ -137,7 +140,10 @@ export const FeedItem = observer(function ({
|
||||||
}>
|
}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="retweet"
|
icon="retweet"
|
||||||
style={[styles.includeReasonIcon, {color: pal.colors.textLight}]}
|
style={[
|
||||||
|
styles.includeReasonIcon,
|
||||||
|
{color: pal.colors.textLight} as FontAwesomeIconStyle,
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
<Text type="sm-bold" style={pal.textLight}>
|
<Text type="sm-bold" style={pal.textLight}>
|
||||||
Reposted by{' '}
|
Reposted by{' '}
|
||||||
|
@ -167,7 +173,10 @@ export const FeedItem = observer(function ({
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="reply"
|
icon="reply"
|
||||||
size={9}
|
size={9}
|
||||||
style={[{color: pal.colors.textLight}, s.mr5]}
|
style={[
|
||||||
|
{color: pal.colors.textLight} as FontAwesomeIconStyle,
|
||||||
|
s.mr5,
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
<Text type="md" style={[pal.textLight, s.mr2]}>
|
<Text type="md" style={[pal.textLight, s.mr2]}>
|
||||||
Reply to
|
Reply to
|
||||||
|
|
|
@ -97,7 +97,11 @@ const User = ({item}: {item: FollowItem}) => {
|
||||||
size={40}
|
size={40}
|
||||||
displayName={item.displayName}
|
displayName={item.displayName}
|
||||||
handle={item.handle}
|
handle={item.handle}
|
||||||
avatar={item.avatar}
|
avatar={
|
||||||
|
item.avatar as
|
||||||
|
| string
|
||||||
|
| undefined /* HACK: type signature is wrong in the api */
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.layoutContent}>
|
<View style={styles.layoutContent}>
|
||||||
|
|
|
@ -8,7 +8,10 @@ import {
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {BlurView} from '@react-native-community/blur'
|
import {BlurView} from '@react-native-community/blur'
|
||||||
import {ProfileViewModel} from '../../../state/models/profile-view'
|
import {ProfileViewModel} from '../../../state/models/profile-view'
|
||||||
import {useStores} from '../../../state'
|
import {useStores} from '../../../state'
|
||||||
|
@ -142,7 +145,7 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={pal.view}>
|
<View style={pal.view}>
|
||||||
<UserBanner handle={view.handle} banner={view.banner} />
|
<UserBanner banner={view.banner} />
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<View style={[styles.buttonsLine]}>
|
<View style={[styles.buttonsLine]}>
|
||||||
{isMe ? (
|
{isMe ? (
|
||||||
|
@ -181,7 +184,10 @@ export const ProfileHeader = observer(function ProfileHeader({
|
||||||
start={{x: 0, y: 0}}
|
start={{x: 0, y: 0}}
|
||||||
end={{x: 1, y: 1}}
|
end={{x: 1, y: 1}}
|
||||||
style={[styles.btn, styles.gradientBtn]}>
|
style={[styles.btn, styles.gradientBtn]}>
|
||||||
<FontAwesomeIcon icon="plus" style={[s.white, s.mr5]} />
|
<FontAwesomeIcon
|
||||||
|
icon="plus"
|
||||||
|
style={[s.white as FontAwesomeIconStyle, s.mr5]}
|
||||||
|
/>
|
||||||
<Text type="button" style={[s.white, s.bold]}>
|
<Text type="button" style={[s.white, s.bold]}>
|
||||||
Follow
|
Follow
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
|
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
|
||||||
import {IconProp} from '@fortawesome/fontawesome-svg-core'
|
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 {Text} from './text/Text'
|
||||||
import {UserGroupIcon} from '../../lib/icons'
|
import {UserGroupIcon} from '../../lib/icons'
|
||||||
import {usePalette} from '../../lib/hooks/usePalette'
|
import {usePalette} from '../../lib/hooks/usePalette'
|
||||||
|
@ -25,7 +28,10 @@ export function EmptyState({
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={icon}
|
icon={icon}
|
||||||
size={64}
|
size={64}
|
||||||
style={[styles.icon, {color: pal.colors.emptyStateIcon}]}
|
style={[
|
||||||
|
styles.icon,
|
||||||
|
{color: pal.colors.emptyStateIcon} as FontAwesomeIconStyle,
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -63,7 +63,7 @@ export function PostLoadingPlaceholder({
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flex1}>
|
<View style={s.flex1}>
|
||||||
<HeartIcon
|
<HeartIcon
|
||||||
style={{color: theme.palette.default.icon}}
|
style={{color: theme.palette.default.icon} as ViewStyle}
|
||||||
size={17}
|
size={17}
|
||||||
strokeWidth={1.7}
|
strokeWidth={1.7}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -7,7 +7,10 @@ import {
|
||||||
View,
|
View,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} 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 ReactNativeHapticFeedback from 'react-native-haptic-feedback'
|
||||||
import {Text} from './text/Text'
|
import {Text} from './text/Text'
|
||||||
import {PostDropdownBtn} from './forms/DropdownButton'
|
import {PostDropdownBtn} from './forms/DropdownButton'
|
||||||
|
@ -147,7 +150,9 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
<Animated.View style={anim1Style}>
|
<Animated.View style={anim1Style}>
|
||||||
<RepostIcon
|
<RepostIcon
|
||||||
style={
|
style={
|
||||||
opts.isReposted ? styles.ctrlIconReposted : defaultCtrlColor
|
(opts.isReposted
|
||||||
|
? styles.ctrlIconReposted
|
||||||
|
: defaultCtrlColor) as ViewStyle
|
||||||
}
|
}
|
||||||
strokeWidth={2.4}
|
strokeWidth={2.4}
|
||||||
size={opts.big ? 24 : 20}
|
size={opts.big ? 24 : 20}
|
||||||
|
@ -173,12 +178,15 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
<Animated.View style={anim2Style}>
|
<Animated.View style={anim2Style}>
|
||||||
{opts.isUpvoted ? (
|
{opts.isUpvoted ? (
|
||||||
<HeartIconSolid
|
<HeartIconSolid
|
||||||
style={[styles.ctrlIconUpvoted]}
|
style={styles.ctrlIconUpvoted as ViewStyle}
|
||||||
size={opts.big ? 22 : 16}
|
size={opts.big ? 22 : 16}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<HeartIcon
|
<HeartIcon
|
||||||
style={[defaultCtrlColor, opts.big ? styles.mt1 : undefined]}
|
style={[
|
||||||
|
defaultCtrlColor as ViewStyle,
|
||||||
|
opts.big ? styles.mt1 : undefined,
|
||||||
|
]}
|
||||||
strokeWidth={3}
|
strokeWidth={3}
|
||||||
size={opts.big ? 20 : 16}
|
size={opts.big ? 20 : 16}
|
||||||
/>
|
/>
|
||||||
|
@ -214,7 +222,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
|
||||||
{
|
{
|
||||||
color:
|
color:
|
||||||
theme.colorScheme === 'light' ? colors.gray4 : colors.gray5,
|
theme.colorScheme === 'light' ? colors.gray4 : colors.gray5,
|
||||||
},
|
} as FontAwesomeIconStyle,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</PostDropdownBtn>
|
</PostDropdownBtn>
|
||||||
|
|
|
@ -6,7 +6,10 @@ import {
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {UserAvatar} from './UserAvatar'
|
import {UserAvatar} from './UserAvatar'
|
||||||
import {Text} from './text/Text'
|
import {Text} from './text/Text'
|
||||||
import {MagnifyingGlassIcon} from '../../lib/icons'
|
import {MagnifyingGlassIcon} from '../../lib/icons'
|
||||||
|
@ -92,7 +95,11 @@ export const ViewHeader = observer(function ViewHeader({
|
||||||
<ActivityIndicator />
|
<ActivityIndicator />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<FontAwesomeIcon icon="signal" style={pal.text} size={16} />
|
<FontAwesomeIcon
|
||||||
|
icon="signal"
|
||||||
|
style={pal.text as FontAwesomeIconStyle}
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon="x"
|
icon="x"
|
||||||
style={[
|
style={[
|
||||||
|
|
|
@ -6,7 +6,10 @@ import {
|
||||||
View,
|
View,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {Text} from '../text/Text'
|
import {Text} from '../text/Text'
|
||||||
import {useTheme} from '../../../lib/ThemeContext'
|
import {useTheme} from '../../../lib/ThemeContext'
|
||||||
import {usePalette} from '../../../lib/hooks/usePalette'
|
import {usePalette} from '../../../lib/hooks/usePalette'
|
||||||
|
@ -28,7 +31,11 @@ export function ErrorMessage({
|
||||||
<View testID="errorMessageView" style={[styles.outer, pal.view, style]}>
|
<View testID="errorMessageView" style={[styles.outer, pal.view, style]}>
|
||||||
<View
|
<View
|
||||||
style={[styles.errorIcon, {backgroundColor: theme.palette.error.icon}]}>
|
style={[styles.errorIcon, {backgroundColor: theme.palette.error.icon}]}>
|
||||||
<FontAwesomeIcon icon="exclamation" style={pal.text} size={16} />
|
<FontAwesomeIcon
|
||||||
|
icon="exclamation"
|
||||||
|
style={pal.text as FontAwesomeIconStyle}
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Text
|
<Text
|
||||||
type="sm"
|
type="sm"
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {
|
||||||
|
FontAwesomeIcon,
|
||||||
|
FontAwesomeIconStyle,
|
||||||
|
} from '@fortawesome/react-native-fontawesome'
|
||||||
import {Text} from '../text/Text'
|
import {Text} from '../text/Text'
|
||||||
import {colors} from '../../../lib/styles'
|
import {colors} from '../../../lib/styles'
|
||||||
import {useTheme} from '../../../lib/ThemeContext'
|
import {useTheme} from '../../../lib/ThemeContext'
|
||||||
|
@ -58,7 +61,11 @@ export function ErrorScreen({
|
||||||
testID="errorScreenTryAgainButton"
|
testID="errorScreenTryAgainButton"
|
||||||
style={[styles.btn, {backgroundColor: theme.palette.error.icon}]}
|
style={[styles.btn, {backgroundColor: theme.palette.error.icon}]}
|
||||||
onPress={onPressTryAgain}>
|
onPress={onPressTryAgain}>
|
||||||
<FontAwesomeIcon icon="arrows-rotate" style={pal.text} size={16} />
|
<FontAwesomeIcon
|
||||||
|
icon="arrows-rotate"
|
||||||
|
style={pal.text as FontAwesomeIconStyle}
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
<Text type="button" style={[styles.btnText, pal.text]}>
|
<Text type="button" style={[styles.btnText, pal.text]}>
|
||||||
Try again
|
Try again
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -37,7 +37,7 @@ export function DropdownButton({
|
||||||
menuWidth,
|
menuWidth,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
type: DropdownButtonType
|
type?: DropdownButtonType
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
items: DropdownItem[]
|
items: DropdownItem[]
|
||||||
label?: string
|
label?: string
|
||||||
|
|
|
@ -30,6 +30,7 @@ export function AutoSizedImage({
|
||||||
}: {
|
}: {
|
||||||
uri: string
|
uri: string
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
|
onLongPress?: () => void
|
||||||
style?: StyleProp<ImageStyle>
|
style?: StyleProp<ImageStyle>
|
||||||
containerStyle?: StyleProp<ViewStyle>
|
containerStyle?: StyleProp<ViewStyle>
|
||||||
}) {
|
}) {
|
||||||
|
@ -68,7 +69,7 @@ export function AutoSizedImage({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let calculatedStyle: StyleProp<ViewStyle> | undefined
|
let calculatedStyle: StyleProp<ImageStyle> | undefined
|
||||||
if (imgInfo && containerInfo) {
|
if (imgInfo && containerInfo) {
|
||||||
// imgInfo.height / imgInfo.width = x / containerInfo.width
|
// imgInfo.height / imgInfo.width = x / containerInfo.width
|
||||||
// x = imgInfo.height / imgInfo.width * containerInfo.width
|
// x = imgInfo.height / imgInfo.width * containerInfo.width
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {DELAY_PRESS_IN} from './constants'
|
||||||
|
|
||||||
interface Dim {
|
interface Dim {
|
||||||
width: number
|
width: number
|
||||||
height: numberPressIn
|
height: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ImageLayoutGridType = 'two' | 'three' | 'four'
|
export type ImageLayoutGridType = 'two' | 'three' | 'four'
|
||||||
|
@ -28,6 +28,7 @@ export function ImageLayoutGrid({
|
||||||
type: ImageLayoutGridType
|
type: ImageLayoutGridType
|
||||||
uris: string[]
|
uris: string[]
|
||||||
onPress?: (index: number) => void
|
onPress?: (index: number) => void
|
||||||
|
onLongPress?: (index: number) => void
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
}) {
|
}) {
|
||||||
const [containerInfo, setContainerInfo] = React.useState<Dim | undefined>()
|
const [containerInfo, setContainerInfo] = React.useState<Dim | undefined>()
|
||||||
|
@ -64,6 +65,7 @@ function ImageLayoutGridInner({
|
||||||
type: ImageLayoutGridType
|
type: ImageLayoutGridType
|
||||||
uris: string[]
|
uris: string[]
|
||||||
onPress?: (index: number) => void
|
onPress?: (index: number) => void
|
||||||
|
onLongPress?: (index: number) => void
|
||||||
containerInfo: Dim
|
containerInfo: Dim
|
||||||
}) {
|
}) {
|
||||||
const size1 = React.useMemo<ImageStyle>(() => {
|
const size1 = React.useMemo<ImageStyle>(() => {
|
||||||
|
@ -91,14 +93,14 @@ function ImageLayoutGridInner({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(0)}
|
onPress={() => onPress?.(0)}
|
||||||
onLongPress={() => onLongPress(0)}>
|
onLongPress={() => onLongPress?.(0)}>
|
||||||
<Image source={{uri: uris[0]}} style={size1} />
|
<Image source={{uri: uris[0]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.wSpace} />
|
<View style={styles.wSpace} />
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(1)}
|
onPress={() => onPress?.(1)}
|
||||||
onLongPress={() => onLongPress(1)}>
|
onLongPress={() => onLongPress?.(1)}>
|
||||||
<Image source={{uri: uris[1]}} style={size1} />
|
<Image source={{uri: uris[1]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
@ -110,7 +112,7 @@ function ImageLayoutGridInner({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(0)}
|
onPress={() => onPress?.(0)}
|
||||||
onLongPress={() => onLongPress(0)}>
|
onLongPress={() => onLongPress?.(0)}>
|
||||||
<Image source={{uri: uris[0]}} style={size2} />
|
<Image source={{uri: uris[0]}} style={size2} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.wSpace} />
|
<View style={styles.wSpace} />
|
||||||
|
@ -118,14 +120,14 @@ function ImageLayoutGridInner({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(1)}
|
onPress={() => onPress?.(1)}
|
||||||
onLongPress={() => onLongPress(1)}>
|
onLongPress={() => onLongPress?.(1)}>
|
||||||
<Image source={{uri: uris[1]}} style={size1} />
|
<Image source={{uri: uris[1]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.hSpace} />
|
<View style={styles.hSpace} />
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(2)}
|
onPress={() => onPress?.(2)}
|
||||||
onLongPress={() => onLongPress(2)}>
|
onLongPress={() => onLongPress?.(2)}>
|
||||||
<Image source={{uri: uris[2]}} style={size1} />
|
<Image source={{uri: uris[2]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
@ -139,14 +141,14 @@ function ImageLayoutGridInner({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(0)}
|
onPress={() => onPress?.(0)}
|
||||||
onLongPress={() => onLongPress(0)}>
|
onLongPress={() => onLongPress?.(0)}>
|
||||||
<Image source={{uri: uris[0]}} style={size1} />
|
<Image source={{uri: uris[0]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.hSpace} />
|
<View style={styles.hSpace} />
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(1)}
|
onPress={() => onPress?.(1)}
|
||||||
onLongPress={() => onLongPress(1)}>
|
onLongPress={() => onLongPress?.(1)}>
|
||||||
<Image source={{uri: uris[1]}} style={size1} />
|
<Image source={{uri: uris[1]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
@ -155,14 +157,14 @@ function ImageLayoutGridInner({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(2)}
|
onPress={() => onPress?.(2)}
|
||||||
onLongPress={() => onLongPress(2)}>
|
onLongPress={() => onLongPress?.(2)}>
|
||||||
<Image source={{uri: uris[2]}} style={size1} />
|
<Image source={{uri: uris[2]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.hSpace} />
|
<View style={styles.hSpace} />
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
delayPressIn={DELAY_PRESS_IN}
|
delayPressIn={DELAY_PRESS_IN}
|
||||||
onPress={() => onPress?.(3)}
|
onPress={() => onPress?.(3)}
|
||||||
onLongPress={() => onLongPress(3)}>
|
onLongPress={() => onLongPress?.(3)}>
|
||||||
<Image source={{uri: uris[3]}} style={size1} />
|
<Image source={{uri: uris[3]}} style={size1} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleProp, ViewStyle} from 'react-native'
|
import {StyleProp, TextStyle, ViewStyle} from 'react-native'
|
||||||
import Svg, {Path} from 'react-native-svg'
|
import Svg, {Path} from 'react-native-svg'
|
||||||
|
|
||||||
export function GridIcon({
|
export function GridIcon({
|
||||||
|
@ -428,12 +428,21 @@ export function CommentBottomArrow({
|
||||||
size?: string | number
|
size?: string | number
|
||||||
strokeWidth?: number
|
strokeWidth?: number
|
||||||
}) {
|
}) {
|
||||||
|
let color = 'currentColor'
|
||||||
|
if (
|
||||||
|
style &&
|
||||||
|
typeof style === 'object' &&
|
||||||
|
'color' in style &&
|
||||||
|
typeof style.color === 'string'
|
||||||
|
) {
|
||||||
|
color = style.color
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Svg
|
<Svg
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
strokeWidth={strokeWidth || 2.5}
|
strokeWidth={strokeWidth || 2.5}
|
||||||
stroke={style?.color || 'currentColor'}
|
stroke={color}
|
||||||
width={size || 24}
|
width={size || 24}
|
||||||
height={size || 24}
|
height={size || 24}
|
||||||
style={style}>
|
style={style}>
|
||||||
|
|
|
@ -21,7 +21,7 @@ export type ScreenParams = {
|
||||||
navIdx: string
|
navIdx: string
|
||||||
params: Record<string, any>
|
params: Record<string, any>
|
||||||
visible: boolean
|
visible: boolean
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | undefined>
|
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
||||||
}
|
}
|
||||||
export type Route = [React.FC<ScreenParams>, string, IconProp, RegExp]
|
export type Route = [React.FC<ScreenParams>, string, IconProp, RegExp]
|
||||||
export type MatchResult = {
|
export type MatchResult = {
|
||||||
|
|
|
@ -5,14 +5,13 @@ import {ThemeProvider} from '../lib/ThemeContext'
|
||||||
import {PaletteColorName} from '../lib/ThemeContext'
|
import {PaletteColorName} from '../lib/ThemeContext'
|
||||||
import {usePalette} from '../lib/hooks/usePalette'
|
import {usePalette} from '../lib/hooks/usePalette'
|
||||||
import {s} from '../lib/styles'
|
import {s} from '../lib/styles'
|
||||||
import {DEF_AVATAR} from '../lib/assets'
|
|
||||||
import {displayNotification} from '../lib/notifee'
|
import {displayNotification} from '../lib/notifee'
|
||||||
|
|
||||||
import {Text} from '../com/util/text/Text'
|
import {Text} from '../com/util/text/Text'
|
||||||
import {ViewSelector} from '../com/util/ViewSelector'
|
import {ViewSelector} from '../com/util/ViewSelector'
|
||||||
import {EmptyState} from '../com/util/EmptyState'
|
import {EmptyState} from '../com/util/EmptyState'
|
||||||
import * as LoadingPlaceholder from '../com/util/LoadingPlaceholder'
|
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 {DropdownButton, DropdownItem} from '../com/util/forms/DropdownButton'
|
||||||
import {ToggleButton} from '../com/util/forms/ToggleButton'
|
import {ToggleButton} from '../com/util/forms/ToggleButton'
|
||||||
import {RadioGroup} from '../com/util/forms/RadioGroup'
|
import {RadioGroup} from '../com/util/forms/RadioGroup'
|
||||||
|
@ -48,9 +47,9 @@ function DebugInner({
|
||||||
const [currentView, setCurrentView] = React.useState<number>(0)
|
const [currentView, setCurrentView] = React.useState<number>(0)
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
|
||||||
const renderItem = (item, i) => {
|
const renderItem = (item: any) => {
|
||||||
return (
|
return (
|
||||||
<View key={`view-${i}`}>
|
<View key={`view-${item.currentView}`}>
|
||||||
<View style={[s.pt10, s.pl10, s.pr10]}>
|
<View style={[s.pt10, s.pl10, s.pr10]}>
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
type="default-light"
|
type="default-light"
|
||||||
|
@ -179,18 +178,10 @@ function NotifsView() {
|
||||||
"Hello world! This is a test of the notifications card. The text is long to see how that's handled.",
|
"Hello world! This is a test of the notifications card. The text is long to see how that's handled.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const triggerImg = () => {
|
|
||||||
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 (
|
return (
|
||||||
<View style={s.p10}>
|
<View style={s.p10}>
|
||||||
<View style={s.flexRow}>
|
<View style={s.flexRow}>
|
||||||
<Button onPress={trigger} label="Trigger" />
|
<Button onPress={trigger} label="Trigger" />
|
||||||
<Button onPress={triggerImg} label="Trigger w/image" style={s.ml5} />
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -484,14 +475,14 @@ const RADIO_BUTTON_ITEMS = [
|
||||||
]
|
]
|
||||||
function RadioButtonsView() {
|
function RadioButtonsView() {
|
||||||
const defaultPal = usePalette('default')
|
const defaultPal = usePalette('default')
|
||||||
const [rgType, setRgType] = React.useState('default-light')
|
const [rgType, setRgType] = React.useState<ButtonType>('default-light')
|
||||||
return (
|
return (
|
||||||
<View style={[defaultPal.view]}>
|
<View style={[defaultPal.view]}>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
type={rgType}
|
type={rgType}
|
||||||
items={RADIO_BUTTON_ITEMS}
|
items={RADIO_BUTTON_ITEMS}
|
||||||
initialSelection="default-light"
|
initialSelection="default-light"
|
||||||
onSelect={setRgType}
|
onSelect={v => setRgType(v as ButtonType)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,55 +1,57 @@
|
||||||
import React from 'react'
|
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}> = ({
|
// export const NavItem: React.FC<{label: string; screen: string}> = ({
|
||||||
label,
|
// label,
|
||||||
screen,
|
// screen,
|
||||||
}) => {
|
// }) => {
|
||||||
const Link = <></> // TODO
|
// const Link = <></> // TODO
|
||||||
return (
|
// return (
|
||||||
<View>
|
// <View>
|
||||||
<Pressable
|
// <Pressable
|
||||||
style={state => [
|
// style={state => [
|
||||||
// @ts-ignore it does exist! (react-native-web) -prf
|
// // @ts-ignore it does exist! (react-native-web) -prf
|
||||||
state.hovered && styles.navItemHovered,
|
// state.hovered && styles.navItemHovered,
|
||||||
]}>
|
// ]}>
|
||||||
<Link
|
// <Link
|
||||||
style={[
|
// style={[
|
||||||
styles.navItemLink,
|
// styles.navItemLink,
|
||||||
false /* TODO route.name === screen*/ && styles.navItemLinkSelected,
|
// false /* TODO route.name === screen*/ && styles.navItemLinkSelected,
|
||||||
]}
|
// ]}
|
||||||
to={{screen, params: {}}}>
|
// to={{screen, params: {}}}>
|
||||||
{label}
|
// {label}
|
||||||
</Link>
|
// </Link>
|
||||||
</Pressable>
|
// </Pressable>
|
||||||
</View>
|
// </View>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const DesktopLeftColumn: React.FC = () => {
|
export const DesktopLeftColumn: React.FC = () => {
|
||||||
return (
|
// TODO
|
||||||
<View style={styles.container}>
|
return <View />
|
||||||
<NavItem screen="Home" label="Home" />
|
// return (
|
||||||
<NavItem screen="Search" label="Search" />
|
// <View style={styles.container}>
|
||||||
<NavItem screen="Notifications" label="Notifications" />
|
// <NavItem screen="Home" label="Home" />
|
||||||
</View>
|
// <NavItem screen="Search" label="Search" />
|
||||||
)
|
// <NavItem screen="Notifications" label="Notifications" />
|
||||||
|
// </View>
|
||||||
|
// )
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
// const styles = StyleSheet.create({
|
||||||
container: {
|
// container: {
|
||||||
position: 'absolute',
|
// position: 'absolute',
|
||||||
left: 'calc(50vw - 500px)',
|
// left: 'calc(50vw - 500px)',
|
||||||
width: '200px',
|
// width: '200px',
|
||||||
height: '100%',
|
// height: '100%',
|
||||||
},
|
// },
|
||||||
navItemHovered: {
|
// navItemHovered: {
|
||||||
backgroundColor: 'gray',
|
// backgroundColor: 'gray',
|
||||||
},
|
// },
|
||||||
navItemLink: {
|
// navItemLink: {
|
||||||
padding: '1rem',
|
// padding: '1rem',
|
||||||
},
|
// },
|
||||||
navItemLinkSelected: {
|
// navItemLinkSelected: {
|
||||||
color: 'blue',
|
// color: 'blue',
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
|
|
|
@ -36,11 +36,12 @@ export const TabsSelector = observer(
|
||||||
undefined,
|
undefined,
|
||||||
)
|
)
|
||||||
const closeInterp = useAnimatedValue(0)
|
const closeInterp = useAnimatedValue(0)
|
||||||
|
const tabsContainerRef = useRef<View>(null)
|
||||||
const tabsRef = useRef<ScrollView>(null)
|
const tabsRef = useRef<ScrollView>(null)
|
||||||
const tabRefs = useMemo(
|
const tabRefs = useMemo(
|
||||||
() =>
|
() =>
|
||||||
Array.from({length: store.nav.tabs.length}).map(() =>
|
Array.from({length: store.nav.tabs.length}).map(() =>
|
||||||
createRef<Animated.View>(),
|
createRef<View>(),
|
||||||
),
|
),
|
||||||
[store.nav.tabs.length],
|
[store.nav.tabs.length],
|
||||||
)
|
)
|
||||||
|
@ -90,9 +91,9 @@ export const TabsSelector = observer(
|
||||||
const onLayout = () => {
|
const onLayout = () => {
|
||||||
// focus the current tab
|
// focus the current tab
|
||||||
const targetTab = tabRefs[store.nav.tabIndex]
|
const targetTab = tabRefs[store.nav.tabIndex]
|
||||||
if (tabsRef.current && targetTab.current) {
|
if (tabsContainerRef.current && tabsRef.current && targetTab.current) {
|
||||||
targetTab.current.measureLayout?.(
|
targetTab.current.measureLayout?.(
|
||||||
tabsRef.current,
|
tabsContainerRef.current,
|
||||||
(_left: number, top: number) => {
|
(_left: number, top: number) => {
|
||||||
tabsRef.current?.scrollTo({y: top, animated: false})
|
tabsRef.current?.scrollTo({y: top, animated: false})
|
||||||
},
|
},
|
||||||
|
@ -162,7 +163,9 @@ export const TabsSelector = observer(
|
||||||
</TouchableWithoutFeedback>
|
</TouchableWithoutFeedback>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={[s.p10, styles.section, styles.sectionGrayBg]}>
|
<View
|
||||||
|
ref={tabsContainerRef}
|
||||||
|
style={[s.p10, styles.section, styles.sectionGrayBg]}>
|
||||||
<ScrollView ref={tabsRef} style={styles.tabs}>
|
<ScrollView ref={tabsRef} style={styles.tabs}>
|
||||||
{store.nav.tabs.map((tab, tabIndex) => {
|
{store.nav.tabs.map((tab, tabIndex) => {
|
||||||
const {icon} = match(tab.current.url)
|
const {icon} = match(tab.current.url)
|
||||||
|
|
|
@ -67,29 +67,36 @@ const Btn = ({
|
||||||
onLongPress?: (event: GestureResponderEvent) => void
|
onLongPress?: (event: GestureResponderEvent) => void
|
||||||
}) => {
|
}) => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
let size = 24
|
let iconEl
|
||||||
let addedStyles
|
|
||||||
let IconEl
|
|
||||||
if (icon === 'menu') {
|
if (icon === 'menu') {
|
||||||
IconEl = GridIcon
|
iconEl = <GridIcon style={[styles.ctrlIcon, pal.text]} />
|
||||||
} else if (icon === 'menu-solid') {
|
} else if (icon === 'menu-solid') {
|
||||||
IconEl = GridIconSolid
|
iconEl = <GridIconSolid style={[styles.ctrlIcon, pal.text]} />
|
||||||
} else if (icon === 'home') {
|
} else if (icon === 'home') {
|
||||||
IconEl = HomeIcon
|
iconEl = <HomeIcon size={27} style={[styles.ctrlIcon, pal.text]} />
|
||||||
size = 27
|
|
||||||
} else if (icon === 'home-solid') {
|
} else if (icon === 'home-solid') {
|
||||||
IconEl = HomeIconSolid
|
iconEl = <HomeIconSolid size={27} style={[styles.ctrlIcon, pal.text]} />
|
||||||
size = 27
|
|
||||||
} else if (icon === 'bell') {
|
} else if (icon === 'bell') {
|
||||||
IconEl = BellIcon
|
const addedStyles = {position: 'relative', top: -1} as ViewStyle
|
||||||
size = 27
|
iconEl = (
|
||||||
addedStyles = {position: 'relative', top: -1} as ViewStyle
|
<BellIcon size={27} style={[styles.ctrlIcon, pal.text, addedStyles]} />
|
||||||
|
)
|
||||||
} else if (icon === 'bell-solid') {
|
} else if (icon === 'bell-solid') {
|
||||||
IconEl = BellIconSolid
|
const addedStyles = {position: 'relative', top: -1} as ViewStyle
|
||||||
size = 27
|
iconEl = (
|
||||||
addedStyles = {position: 'relative', top: -1} as ViewStyle
|
<BellIconSolid
|
||||||
|
size={27}
|
||||||
|
style={[styles.ctrlIcon, pal.text, addedStyles]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
IconEl = FontAwesomeIcon
|
iconEl = (
|
||||||
|
<FontAwesomeIcon
|
||||||
|
size={24}
|
||||||
|
icon={icon}
|
||||||
|
style={[styles.ctrlIcon, pal.text]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -108,11 +115,7 @@ const Btn = ({
|
||||||
<Text style={styles.tabCountLabel}>{tabCount}</Text>
|
<Text style={styles.tabCountLabel}>{tabCount}</Text>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<IconEl
|
{iconEl}
|
||||||
size={size}
|
|
||||||
style={[styles.ctrlIcon, pal.text, addedStyles]}
|
|
||||||
icon={icon}
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +125,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const [isTabsSelectorActive, setTabsSelectorActive] = useState(false)
|
const [isTabsSelectorActive, setTabsSelectorActive] = useState(false)
|
||||||
const scrollElRef = useRef<FlatList | undefined>()
|
const scrollElRef = useRef<FlatList>(null)
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
|
const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
|
||||||
const swipeGestureInterp = useAnimatedValue(0)
|
const swipeGestureInterp = useAnimatedValue(0)
|
||||||
|
@ -292,9 +295,11 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
)
|
)
|
||||||
shouldRenderMenu = true
|
shouldRenderMenu = true
|
||||||
}
|
}
|
||||||
const menuSwipeTransform = {
|
const menuSwipeTransform = menuTranslateX
|
||||||
|
? {
|
||||||
transform: [{translateX: menuTranslateX}],
|
transform: [{translateX: menuTranslateX}],
|
||||||
}
|
}
|
||||||
|
: undefined
|
||||||
const swipeOpacity = {
|
const swipeOpacity = {
|
||||||
opacity: swipeGestureInterp.interpolate({
|
opacity: swipeGestureInterp.interpolate({
|
||||||
inputRange: [-1, 0, 1],
|
inputRange: [-1, 0, 1],
|
||||||
|
@ -417,10 +422,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{shouldRenderMenu && (
|
{shouldRenderMenu && (
|
||||||
<Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
|
<Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
|
||||||
<Menu
|
<Menu onClose={() => store.shell.setMainMenuOpen(false)} />
|
||||||
visible={isMenuActive}
|
|
||||||
onClose={() => store.shell.setMainMenuOpen(false)}
|
|
||||||
/>
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
)}
|
)}
|
||||||
</HorzSwipe>
|
</HorzSwipe>
|
||||||
|
|
Loading…
Reference in New Issue