mirror of https://github.com/tooot-app/app
parent
de7498b218
commit
bb3ddd2779
|
@ -274,6 +274,7 @@ declare namespace Mastodon {
|
|||
type List = {
|
||||
id: string
|
||||
title: string
|
||||
replies_policy: 'none' | 'list' | 'followed'
|
||||
}
|
||||
|
||||
type Instance = {
|
||||
|
|
|
@ -121,7 +121,8 @@ const contextMenuStatus = ({ actions, status, queryKey, rootQueryKey }: Props) =
|
|||
}
|
||||
},
|
||||
{
|
||||
text: t('common:buttons.cancel')
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
])
|
||||
}
|
||||
|
|
|
@ -60,11 +60,11 @@ const ComponentInstance: React.FC<Props> = ({
|
|||
if (instances && instances.filter(instance => instance.url === domain).length) {
|
||||
Alert.alert(t('update.alert.title'), t('update.alert.message'), [
|
||||
{
|
||||
text: t('update.alert.buttons.cancel'),
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: t('update.alert.buttons.continue'),
|
||||
text: t('common:buttons.continue'),
|
||||
onPress: () => {
|
||||
appsQuery.refetch()
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ const Message = React.forwardRef<FlashMessage>((_, ref) => {
|
|||
shadowOpacity: theme === 'light' ? 0.16 : 0.24,
|
||||
shadowRadius: 4,
|
||||
paddingRight: StyleConstants.Spacing.M * 2,
|
||||
marginTop: insets.top
|
||||
marginTop: ref ? undefined : insets.top
|
||||
}}
|
||||
titleStyle={{
|
||||
color: colors.primaryDefault,
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { Pressable, View } from 'react-native'
|
||||
import haptics from './haptics'
|
||||
import Icon from './Icon'
|
||||
import { ParseEmojis } from './Parse'
|
||||
import CustomText from './Text'
|
||||
|
||||
export interface Props {
|
||||
multiple?: boolean
|
||||
options: { selected: boolean; content: string }[]
|
||||
setOptions: React.Dispatch<React.SetStateAction<{ selected: boolean; content: string }[]>>
|
||||
}
|
||||
|
||||
const Selections: React.FC<Props> = ({ multiple = false, options, setOptions }) => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
const isSelected = (index: number): string =>
|
||||
options[index].selected
|
||||
? `Check${multiple ? 'Square' : 'Circle'}`
|
||||
: `${multiple ? 'Square' : 'Circle'}`
|
||||
|
||||
return (
|
||||
<>
|
||||
{options.map((option, index) => (
|
||||
<Pressable
|
||||
key={index}
|
||||
style={{ flex: 1, paddingVertical: StyleConstants.Spacing.S }}
|
||||
onPress={() => {
|
||||
if (multiple) {
|
||||
haptics('Light')
|
||||
|
||||
setOptions(options.map((o, i) => (i === index ? { ...o, selected: !o.selected } : o)))
|
||||
} else {
|
||||
if (!option.selected) {
|
||||
haptics('Light')
|
||||
setOptions(
|
||||
options.map((o, i) => {
|
||||
if (i === index) {
|
||||
return { ...o, selected: true }
|
||||
} else {
|
||||
return { ...o, selected: false }
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<Icon
|
||||
style={{
|
||||
paddingTop: StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
}}
|
||||
name={isSelected(index)}
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={colors.primaryDefault}
|
||||
/>
|
||||
<CustomText style={{ flex: 1 }}>
|
||||
<ParseEmojis content={option.content} />
|
||||
</CustomText>
|
||||
</View>
|
||||
</Pressable>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Selections
|
|
@ -2,7 +2,9 @@
|
|||
"buttons": {
|
||||
"OK": "OK",
|
||||
"apply": "Apply",
|
||||
"cancel": "Cancel"
|
||||
"cancel": "Cancel",
|
||||
"discard": "Discard",
|
||||
"continue": "Continue"
|
||||
},
|
||||
"customEmoji": {
|
||||
"accessibilityLabel": "Custom emoji {{emoji}}"
|
||||
|
@ -18,5 +20,9 @@
|
|||
"message": "{{function}} failed, please retry"
|
||||
}
|
||||
},
|
||||
"separator": ", "
|
||||
"separator": ", ",
|
||||
"discard": {
|
||||
"title": "Change Not Saved",
|
||||
"message": "Your change has not been saved. Would you discard saving the changes?"
|
||||
}
|
||||
}
|
|
@ -20,11 +20,7 @@
|
|||
"update": {
|
||||
"alert": {
|
||||
"title": "Logged in to this instance",
|
||||
"message": "You can login to another account, keeping existing logged in account",
|
||||
"buttons": {
|
||||
"cancel": "$t(common:buttons.cancel)",
|
||||
"continue": "Continue"
|
||||
}
|
||||
"message": "You can login to another account, keeping existing logged in account"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@
|
|||
"removeReply": {
|
||||
"title": "Replied toot could not be found",
|
||||
"description": "Replied toot could have been deleted. Do you want to remove it from your reference?",
|
||||
"cancel": "$t(common:buttons.cancel)",
|
||||
"confirm": "Remove reference"
|
||||
}
|
||||
}
|
||||
|
@ -89,8 +88,7 @@
|
|||
"heading": "Choice type",
|
||||
"options": {
|
||||
"single": "Single choice",
|
||||
"multiple": "Multiple choice",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"multiple": "Multiple choice"
|
||||
}
|
||||
},
|
||||
"expiration": {
|
||||
|
@ -102,8 +100,7 @@
|
|||
"21600": "6 hours",
|
||||
"86400": "1 day",
|
||||
"259200": "3 days",
|
||||
"604800": "7 days",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"604800": "7 days"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,8 +127,7 @@
|
|||
"public": "Public",
|
||||
"unlisted": "Unlisted",
|
||||
"private": "Followers only",
|
||||
"direct": "Direct message",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"direct": "Direct message"
|
||||
}
|
||||
},
|
||||
"spoiler": {
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
},
|
||||
"options": {
|
||||
"save": "Save image",
|
||||
"share": "Share image",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"share": "Share image"
|
||||
},
|
||||
"save": {
|
||||
"succeed": "Image saved",
|
||||
|
|
|
@ -49,6 +49,12 @@
|
|||
"lists": {
|
||||
"name": "Lists"
|
||||
},
|
||||
"listAdd": {
|
||||
"name": "Add a List"
|
||||
},
|
||||
"listEdit": {
|
||||
"name": "Edit List"
|
||||
},
|
||||
"list": {
|
||||
"name": "List: {{list}}"
|
||||
},
|
||||
|
@ -87,15 +93,18 @@
|
|||
"XXL": "XXL"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"cancellation": {
|
||||
"title": "Change Not Saved",
|
||||
"message": "Your change has not been saved. Would you discard saving the changes?",
|
||||
"buttons": {
|
||||
"cancel": "$t(common:buttons.cancel)",
|
||||
"discard": "Discard"
|
||||
"listEdit": {
|
||||
"title": "Title",
|
||||
"repliesPolicy": {
|
||||
"heading": "Show replies to:",
|
||||
"options": {
|
||||
"none": "No one",
|
||||
"list": "Members of the list",
|
||||
"followed": "Any followed user"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"feedback": {
|
||||
"succeed": "{{type}} updated",
|
||||
"failed": "{{type}} update failed, please try again"
|
||||
|
@ -125,8 +134,7 @@
|
|||
"options": {
|
||||
"public": "Public",
|
||||
"unlisted": "Unlisted",
|
||||
"private": "Followers only",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"private": "Followers only"
|
||||
}
|
||||
},
|
||||
"sensitive": {
|
||||
|
@ -211,8 +219,7 @@
|
|||
"title": "Logging out?",
|
||||
"message": "After logging out, you need to log in again",
|
||||
"buttons": {
|
||||
"logout": "Logout",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"logout": "Logout"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,34 +236,28 @@
|
|||
}
|
||||
},
|
||||
"language": {
|
||||
"heading": "$t(me.stacks.language.name)",
|
||||
"options": {
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
}
|
||||
"heading": "$t(me.stacks.language.name)"
|
||||
},
|
||||
"theme": {
|
||||
"heading": "Appearance",
|
||||
"options": {
|
||||
"auto": "As system",
|
||||
"light": "Light mode",
|
||||
"dark": "Dark mode",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"dark": "Dark mode"
|
||||
}
|
||||
},
|
||||
"darkTheme": {
|
||||
"heading": "Dark theme",
|
||||
"options": {
|
||||
"lighter": "Lighter",
|
||||
"darker": "Darker",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"darker": "Darker"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"heading": "Opening Link",
|
||||
"options": {
|
||||
"internal": "Inside app",
|
||||
"external": "Use system browser",
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
"external": "Use system browser"
|
||||
}
|
||||
},
|
||||
"staticEmoji": {
|
||||
|
|
|
@ -43,10 +43,6 @@ const ActionsDomain: React.FC<Props> = ({ queryKey, rootQueryKey, domain, dismis
|
|||
t('shared.header.actions.domain.alert.title', { domain }),
|
||||
t('shared.header.actions.domain.alert.message'),
|
||||
[
|
||||
{
|
||||
text: t('shared.header.actions.domain.alert.buttons.cancel'),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: t('shared.header.actions.domain.alert.buttons.confirm'),
|
||||
style: 'destructive',
|
||||
|
@ -58,6 +54,10 @@ const ActionsDomain: React.FC<Props> = ({ queryKey, rootQueryKey, domain, dismis
|
|||
domain: domain
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
text: t('shared.header.actions.domain.alert.buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
|
|
@ -38,8 +38,7 @@ const ActionsStatus: React.FC<Props> = ({
|
|||
const mutation = useTimelineMutation({
|
||||
onMutate: true,
|
||||
onError: (err: any, params, oldData) => {
|
||||
const theFunction = (params as MutationVarsTimelineUpdateStatusProperty)
|
||||
.payload
|
||||
const theFunction = (params as MutationVarsTimelineUpdateStatusProperty).payload
|
||||
? (params as MutationVarsTimelineUpdateStatusProperty).payload.property
|
||||
: 'delete'
|
||||
displayMessage({
|
||||
|
@ -108,15 +107,7 @@ const ActionsStatus: React.FC<Props> = ({
|
|||
t('shared.header.actions.status.delete.alert.message'),
|
||||
[
|
||||
{
|
||||
text: t(
|
||||
'shared.header.actions.status.delete.alert.buttons.cancel'
|
||||
),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: t(
|
||||
'shared.header.actions.status.delete.alert.buttons.confirm'
|
||||
),
|
||||
text: t('shared.header.actions.status.delete.alert.buttons.confirm'),
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
dismiss()
|
||||
|
@ -128,6 +119,10 @@ const ActionsStatus: React.FC<Props> = ({
|
|||
id: status.id
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
text: t('shared.header.actions.status.delete.alert.buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
@ -142,15 +137,7 @@ const ActionsStatus: React.FC<Props> = ({
|
|||
t('shared.header.actions.status.deleteEdit.alert.message'),
|
||||
[
|
||||
{
|
||||
text: t(
|
||||
'shared.header.actions.status.deleteEdit.alert.buttons.cancel'
|
||||
),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: t(
|
||||
'shared.header.actions.status.deleteEdit.alert.buttons.confirm'
|
||||
),
|
||||
text: t('shared.header.actions.status.deleteEdit.alert.buttons.confirm'),
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
let replyToStatus: Mastodon.Status | undefined = undefined
|
||||
|
@ -177,6 +164,10 @@ const ActionsStatus: React.FC<Props> = ({
|
|||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
text: t('shared.header.actions.status.deleteEdit.alert.buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
|
|
@ -300,7 +300,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
|||
t('heading.right.alert.removeReply.description'),
|
||||
[
|
||||
{
|
||||
text: t('heading.right.alert.removeReply.cancel'),
|
||||
text: t('common:buttons.cancel'),
|
||||
onPress: () => {
|
||||
composeDispatch({ type: 'posting', payload: false })
|
||||
},
|
||||
|
|
|
@ -86,7 +86,7 @@ const ComposeActions: React.FC = () => {
|
|||
t('content.root.actions.visibility.options.unlisted'),
|
||||
t('content.root.actions.visibility.options.private'),
|
||||
t('content.root.actions.visibility.options.direct'),
|
||||
t('content.root.actions.visibility.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 4,
|
||||
userInterfaceStyle: mode
|
||||
|
|
|
@ -195,7 +195,7 @@ const ComposePoll: React.FC = () => {
|
|||
options: [
|
||||
t('content.root.footer.poll.multiple.options.single'),
|
||||
t('content.root.footer.poll.multiple.options.multiple'),
|
||||
t('content.root.footer.poll.multiple.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2,
|
||||
userInterfaceStyle: mode
|
||||
|
@ -235,7 +235,7 @@ const ComposePoll: React.FC = () => {
|
|||
...expirations.map(e =>
|
||||
t(`content.root.footer.poll.expiration.options.${e}`)
|
||||
),
|
||||
t('content.root.footer.poll.expiration.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: expirations.length,
|
||||
userInterfaceStyle: mode
|
||||
|
|
|
@ -53,7 +53,7 @@ const ScreenImagesViewer = ({
|
|||
options: [
|
||||
t('content.options.save'),
|
||||
t('content.options.share'),
|
||||
t('content.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2,
|
||||
userInterfaceStyle: mode
|
||||
|
|
|
@ -7,8 +7,9 @@ import { Platform } from 'react-native'
|
|||
import TabMeBookmarks from './Me/Bookmarks'
|
||||
import TabMeConversations from './Me/Cconversations'
|
||||
import TabMeFavourites from './Me/Favourites'
|
||||
import TabMeList from './Me/List'
|
||||
import TabMeListEdit from './Me/ListEdit'
|
||||
import TabMeLists from './Me/Lists'
|
||||
import TabMeListsList from './Me/ListsList'
|
||||
import TabMeProfile from './Me/Profile'
|
||||
import TabMePush from './Me/Push'
|
||||
import TabMeRoot from './Me/Root'
|
||||
|
@ -41,9 +42,7 @@ const TabMe = React.memo(
|
|||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.bookmarks.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.bookmarks.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.bookmarks.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
|
@ -54,9 +53,7 @@ const TabMe = React.memo(
|
|||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.conversations.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.conversations.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.conversations.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
|
@ -67,29 +64,14 @@ const TabMe = React.memo(
|
|||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.favourites.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.favourites.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.favourites.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Lists'
|
||||
component={TabMeLists}
|
||||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.lists.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.lists.name')} />
|
||||
)
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Lists-List'
|
||||
component={TabMeListsList}
|
||||
name='Tab-Me-List'
|
||||
component={TabMeList}
|
||||
options={({ route, navigation }: any) => ({
|
||||
title: t('me.stacks.list.name', { list: route.params.title }),
|
||||
...(Platform.OS === 'android' && {
|
||||
|
@ -104,6 +86,29 @@ const TabMe = React.memo(
|
|||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-List-Edit'
|
||||
component={TabMeListEdit}
|
||||
options={{
|
||||
gestureEnabled: false,
|
||||
presentation: 'modal',
|
||||
title: t('me.stacks.listsAdd.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.listsAdd.name')} />
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Lists'
|
||||
component={TabMeLists}
|
||||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.lists.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.lists.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Profile'
|
||||
component={TabMeProfile}
|
||||
|
@ -120,15 +125,10 @@ const TabMe = React.memo(
|
|||
headerShown: true,
|
||||
title: t('me.stacks.push.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.push.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.push.name')} />
|
||||
}),
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
content='ChevronDown'
|
||||
onPress={() => navigation.goBack()}
|
||||
/>
|
||||
<HeaderLeft content='ChevronDown' onPress={() => navigation.goBack()} />
|
||||
)
|
||||
})}
|
||||
/>
|
||||
|
@ -146,9 +146,7 @@ const TabMe = React.memo(
|
|||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.fontSize.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.fontSize.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.fontSize.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
|
@ -159,9 +157,7 @@ const TabMe = React.memo(
|
|||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.language.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.language.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.language.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
|
@ -174,15 +170,10 @@ const TabMe = React.memo(
|
|||
headerShown: true,
|
||||
title: t('me.stacks.switch.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.switch.name')} />
|
||||
)
|
||||
headerCenter: () => <HeaderCenter content={t('me.stacks.switch.name')} />
|
||||
}),
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
content='ChevronDown'
|
||||
onPress={() => navigation.goBack()}
|
||||
/>
|
||||
<HeaderLeft content='ChevronDown' onPress={() => navigation.goBack()} />
|
||||
)
|
||||
})}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import { HeaderRight } from '@components/Header'
|
||||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
||||
navigation,
|
||||
route: { key, params }
|
||||
}) => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list: params.id }]
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<HeaderRight
|
||||
accessibilityLabel={t('me.stacks.listEdit.name')}
|
||||
content='Edit'
|
||||
onPress={() =>
|
||||
navigation.navigate('Tab-Me-List-Edit', { type: 'edit', payload: params, key })
|
||||
}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [params])
|
||||
|
||||
return (
|
||||
<Timeline
|
||||
queryKey={queryKey}
|
||||
customProps={{
|
||||
renderItem: ({ item }) => <TimelineDefault item={item} queryKey={queryKey} />
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default TabMeList
|
|
@ -0,0 +1,163 @@
|
|||
import { EmojisState } from '@components/Emojis/helpers/EmojisContext'
|
||||
import haptics from '@components/haptics'
|
||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import ComponentInput from '@components/Input'
|
||||
import { displayMessage, Message } from '@components/Message'
|
||||
import Selections from '@components/Selections'
|
||||
import CustomText from '@components/Text'
|
||||
import { CommonActions } from '@react-navigation/native'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyLists, useListsMutation } from '@utils/queryHooks/lists'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Alert, ScrollView, TextInput } from 'react-native'
|
||||
import { useQueryClient } from 'react-query'
|
||||
|
||||
const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
|
||||
navigation,
|
||||
route: { params }
|
||||
}) => {
|
||||
const { colors, theme } = useTheme()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
const messageRef = useRef(null)
|
||||
|
||||
const queryKeyLists: QueryKeyLists = ['Lists']
|
||||
const queryClient = useQueryClient()
|
||||
const mutation = useListsMutation({
|
||||
onSuccess: res => {
|
||||
haptics('Success')
|
||||
queryClient.refetchQueries(queryKeyLists)
|
||||
navigation.pop(1)
|
||||
if (params.type === 'edit') {
|
||||
navigation.dispatch({
|
||||
...CommonActions.setParams(res),
|
||||
source: params.key
|
||||
})
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
displayMessage({
|
||||
ref: messageRef,
|
||||
theme,
|
||||
type: 'error',
|
||||
message: t('common:message.error.message', {
|
||||
function:
|
||||
params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name')
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const ref = useRef<TextInput>(null)
|
||||
const [title, setTitle] = useState(params.type === 'edit' ? params.payload.title : '')
|
||||
const inputProps: EmojisState['inputProps'][0] = {
|
||||
ref,
|
||||
value: [title, setTitle],
|
||||
selection: useState({ start: title.length }),
|
||||
isFocused: useRef<boolean>(false),
|
||||
maxLength: 50
|
||||
}
|
||||
|
||||
const [options, setOptions] = useState<
|
||||
{ id: 'none' | 'list' | 'followed'; content: string; selected: boolean }[]
|
||||
>([
|
||||
{
|
||||
id: 'none',
|
||||
content: t('me.listEdit.repliesPolicy.options.none'),
|
||||
selected: params.type === 'edit' ? params.payload.replies_policy === 'none' : false
|
||||
},
|
||||
{
|
||||
id: 'list',
|
||||
content: t('me.listEdit.repliesPolicy.options.list'),
|
||||
selected: params.type === 'edit' ? params.payload.replies_policy === 'list' : true
|
||||
},
|
||||
{
|
||||
id: 'followed',
|
||||
content: t('me.listEdit.repliesPolicy.options.followed'),
|
||||
selected: params.type === 'edit' ? params.payload.replies_policy === 'followed' : false
|
||||
}
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
content='X'
|
||||
onPress={() => {
|
||||
if (params.type === 'edit' ? params.payload.title !== title : title.length) {
|
||||
Alert.alert(t('common:discard.title'), t('common:discard.message'), [
|
||||
{
|
||||
text: t('common:buttons.discard'),
|
||||
style: 'destructive',
|
||||
onPress: () => navigation.pop(1)
|
||||
},
|
||||
{
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
])
|
||||
} else {
|
||||
navigation.pop(1)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerRight: () => (
|
||||
<HeaderRight
|
||||
content='Save'
|
||||
disabled={!title.length}
|
||||
loading={mutation.isLoading}
|
||||
onPress={() => {
|
||||
switch (params.type) {
|
||||
case 'add':
|
||||
mutation.mutate({
|
||||
type: 'add',
|
||||
payload: {
|
||||
title,
|
||||
replies_policy: options.find(option => option.selected)?.id || 'list'
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'edit':
|
||||
mutation.mutate({
|
||||
type: 'edit',
|
||||
payload: {
|
||||
id: params.payload.id,
|
||||
title,
|
||||
replies_policy: options.find(option => option.selected)?.id || 'list'
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [title.length, options])
|
||||
|
||||
return (
|
||||
<ScrollView style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}>
|
||||
<ComponentInput {...inputProps} autoFocus title={t('me.listEdit.title')} />
|
||||
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
fontWeight='Bold'
|
||||
style={{
|
||||
color: colors.primaryDefault,
|
||||
marginBottom: StyleConstants.Spacing.XS,
|
||||
marginTop: StyleConstants.Spacing.M
|
||||
}}
|
||||
>
|
||||
{t('me.listEdit.repliesPolicy.heading')}
|
||||
</CustomText>
|
||||
<Selections options={options} setOptions={setOptions} />
|
||||
|
||||
<Message ref={messageRef} />
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
export default TabMeListEdit
|
|
@ -1,12 +1,25 @@
|
|||
import { HeaderRight } from '@components/Header'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useListsQuery } from '@utils/queryHooks/lists'
|
||||
import React from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({
|
||||
navigation
|
||||
}) => {
|
||||
const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({ navigation }) => {
|
||||
const { data } = useListsQuery({})
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<HeaderRight
|
||||
accessibilityLabel={t('me.stacks.listAdd.name')}
|
||||
content='Plus'
|
||||
onPress={() => navigation.navigate('Tab-Me-List-Edit', { type: 'add' })}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
|
@ -16,12 +29,7 @@ const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({
|
|||
iconFront='List'
|
||||
iconBack='ChevronRight'
|
||||
title={d.title}
|
||||
onPress={() =>
|
||||
navigation.navigate('Tab-Me-Lists-List', {
|
||||
list: d.id,
|
||||
title: d.title
|
||||
})
|
||||
}
|
||||
onPress={() => navigation.navigate('Tab-Me-List', d)}
|
||||
/>
|
||||
))}
|
||||
</MenuContainer>
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React from 'react'
|
||||
|
||||
const TabMeListsList: React.FC<TabMeStackScreenProps<'Tab-Me-Lists-List'>> = ({
|
||||
route: {
|
||||
params: { list }
|
||||
}
|
||||
}) => {
|
||||
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list }]
|
||||
|
||||
return (
|
||||
<Timeline
|
||||
queryKey={queryKey}
|
||||
customProps={{
|
||||
renderItem: ({ item }) => (
|
||||
<TimelineDefault item={item} queryKey={queryKey} />
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default TabMeListsList
|
|
@ -90,20 +90,21 @@ const TabMeProfileFields: React.FC<
|
|||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
content='X'
|
||||
onPress={() => {
|
||||
if (dirty) {
|
||||
Alert.alert(
|
||||
t('me.profile.cancellation.title'),
|
||||
t('me.profile.cancellation.message'),
|
||||
t('common:discard.title'),
|
||||
t('common:discard.message'),
|
||||
[
|
||||
{
|
||||
text: t('me.profile.cancellation.buttons.cancel'),
|
||||
style: 'default'
|
||||
},
|
||||
{
|
||||
text: t('me.profile.cancellation.buttons.discard'),
|
||||
text: t('common:buttons.discard'),
|
||||
style: 'destructive',
|
||||
onPress: () => navigation.navigate('Tab-Me-Profile-Root')
|
||||
},
|
||||
{
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
|
|
@ -44,20 +44,21 @@ const TabMeProfileName: React.FC<
|
|||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
content='X'
|
||||
onPress={() => {
|
||||
if (dirty) {
|
||||
Alert.alert(
|
||||
t('me.profile.cancellation.title'),
|
||||
t('me.profile.cancellation.message'),
|
||||
t('common:discard.title'),
|
||||
t('common:discard.message'),
|
||||
[
|
||||
{
|
||||
text: t('me.profile.cancellation.buttons.cancel'),
|
||||
style: 'default'
|
||||
},
|
||||
{
|
||||
text: t('me.profile.cancellation.buttons.discard'),
|
||||
text: t('common:buttons.discard'),
|
||||
style: 'destructive',
|
||||
onPress: () => navigation.navigate('Tab-Me-Profile-Root')
|
||||
},
|
||||
{
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
|
|
@ -44,20 +44,21 @@ const TabMeProfileNote: React.FC<
|
|||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<HeaderLeft
|
||||
content='X'
|
||||
onPress={() => {
|
||||
if (dirty) {
|
||||
Alert.alert(
|
||||
t('me.profile.cancellation.title'),
|
||||
t('me.profile.cancellation.message'),
|
||||
t('common:discard.title'),
|
||||
t('common:discard.message'),
|
||||
[
|
||||
{
|
||||
text: t('me.profile.cancellation.buttons.cancel'),
|
||||
style: 'default'
|
||||
},
|
||||
{
|
||||
text: t('me.profile.cancellation.buttons.discard'),
|
||||
text: t('common:buttons.discard'),
|
||||
style: 'destructive',
|
||||
onPress: () => navigation.navigate('Tab-Me-Profile-Root')
|
||||
},
|
||||
{
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
|
|
@ -33,7 +33,7 @@ const TabMeProfileRoot: React.FC<
|
|||
t('me.profile.root.visibility.options.public'),
|
||||
t('me.profile.root.visibility.options.unlisted'),
|
||||
t('me.profile.root.visibility.options.private'),
|
||||
t('me.profile.root.visibility.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 3,
|
||||
userInterfaceStyle: mode
|
||||
|
|
|
@ -27,27 +27,23 @@ const Logout: React.FC = () => {
|
|||
}}
|
||||
destructive
|
||||
onPress={() =>
|
||||
Alert.alert(
|
||||
t('me.root.logout.alert.title'),
|
||||
t('me.root.logout.alert.message'),
|
||||
[
|
||||
{
|
||||
text: t('me.root.logout.alert.buttons.logout'),
|
||||
style: 'destructive' as const,
|
||||
onPress: () => {
|
||||
if (instance) {
|
||||
haptics('Success')
|
||||
queryClient.clear()
|
||||
dispatch(removeInstance(instance))
|
||||
}
|
||||
Alert.alert(t('me.root.logout.alert.title'), t('me.root.logout.alert.message'), [
|
||||
{
|
||||
text: t('me.root.logout.alert.buttons.logout'),
|
||||
style: 'destructive',
|
||||
onPress: () => {
|
||||
if (instance) {
|
||||
haptics('Success')
|
||||
queryClient.clear()
|
||||
dispatch(removeInstance(instance))
|
||||
}
|
||||
},
|
||||
{
|
||||
text: t('me.root.logout.alert.buttons.cancel'),
|
||||
style: 'cancel' as const
|
||||
}
|
||||
]
|
||||
)
|
||||
},
|
||||
{
|
||||
text: t('common:buttons.cancel'),
|
||||
style: 'default'
|
||||
}
|
||||
])
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -69,7 +69,7 @@ const SettingsApp: React.FC = () => {
|
|||
t('me.settings.theme.options.auto'),
|
||||
t('me.settings.theme.options.light'),
|
||||
t('me.settings.theme.options.dark'),
|
||||
t('me.settings.theme.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 3
|
||||
},
|
||||
|
@ -103,7 +103,7 @@ const SettingsApp: React.FC = () => {
|
|||
options: [
|
||||
t('me.settings.darkTheme.options.lighter'),
|
||||
t('me.settings.darkTheme.options.darker'),
|
||||
t('me.settings.darkTheme.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
},
|
||||
|
@ -133,7 +133,7 @@ const SettingsApp: React.FC = () => {
|
|||
options: [
|
||||
t('me.settings.browser.options.internal'),
|
||||
t('me.settings.browser.options.external'),
|
||||
t('me.settings.browser.options.cancel')
|
||||
t('common:buttons.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
},
|
||||
|
|
|
@ -63,17 +63,18 @@ export type RootStackParamList = {
|
|||
share?: { text?: string; media?: { uri: string; mime: string }[] }
|
||||
}
|
||||
}
|
||||
export type RootStackScreenProps<T extends keyof RootStackParamList> =
|
||||
NativeStackScreenProps<RootStackParamList, T>
|
||||
export type RootStackScreenProps<T extends keyof RootStackParamList> = NativeStackScreenProps<
|
||||
RootStackParamList,
|
||||
T
|
||||
>
|
||||
|
||||
export type ScreenComposeStackParamList = {
|
||||
'Screen-Compose-Root': undefined
|
||||
'Screen-Compose-EditAttachment': { index: number }
|
||||
'Screen-Compose-DraftsList': { timestamp: number }
|
||||
}
|
||||
export type ScreenComposeStackScreenProps<
|
||||
T extends keyof ScreenComposeStackParamList
|
||||
> = NativeStackScreenProps<ScreenComposeStackParamList, T>
|
||||
export type ScreenComposeStackScreenProps<T extends keyof ScreenComposeStackParamList> =
|
||||
NativeStackScreenProps<ScreenComposeStackParamList, T>
|
||||
|
||||
export type ScreenTabsStackParamList = {
|
||||
'Tab-Local': NavigatorScreenParams<TabLocalStackParamList>
|
||||
|
@ -82,8 +83,10 @@ export type ScreenTabsStackParamList = {
|
|||
'Tab-Notifications': NavigatorScreenParams<TabNotificationsStackParamList>
|
||||
'Tab-Me': NavigatorScreenParams<TabMeStackParamList>
|
||||
}
|
||||
export type ScreenTabsScreenProps<T extends keyof ScreenTabsStackParamList> =
|
||||
BottomTabScreenProps<ScreenTabsStackParamList, T>
|
||||
export type ScreenTabsScreenProps<T extends keyof ScreenTabsStackParamList> = BottomTabScreenProps<
|
||||
ScreenTabsStackParamList,
|
||||
T
|
||||
>
|
||||
|
||||
export type TabSharedStackParamList = {
|
||||
'Tab-Shared-Account': {
|
||||
|
@ -135,11 +138,17 @@ export type TabMeStackParamList = {
|
|||
'Tab-Me-Bookmarks': undefined
|
||||
'Tab-Me-Conversations': undefined
|
||||
'Tab-Me-Favourites': undefined
|
||||
'Tab-Me-List': Mastodon.List
|
||||
'Tab-Me-List-Edit':
|
||||
| {
|
||||
type: 'add'
|
||||
}
|
||||
| {
|
||||
type: 'edit'
|
||||
payload: Mastodon.List
|
||||
key: string // To update title after successful mutation
|
||||
}
|
||||
'Tab-Me-Lists': undefined
|
||||
'Tab-Me-Lists-List': {
|
||||
list: Mastodon.List['id']
|
||||
title: Mastodon.List['title']
|
||||
}
|
||||
'Tab-Me-Profile': undefined
|
||||
'Tab-Me-Push': undefined
|
||||
'Tab-Me-Settings': undefined
|
||||
|
@ -147,11 +156,12 @@ export type TabMeStackParamList = {
|
|||
'Tab-Me-Settings-Language': undefined
|
||||
'Tab-Me-Switch': undefined
|
||||
} & TabSharedStackParamList
|
||||
export type TabMeStackScreenProps<T extends keyof TabMeStackParamList> =
|
||||
NativeStackScreenProps<TabMeStackParamList, T>
|
||||
export type TabMeStackNavigationProp<
|
||||
RouteName extends keyof TabMeStackParamList
|
||||
> = StackNavigationProp<TabMeStackParamList, RouteName>
|
||||
export type TabMeStackScreenProps<T extends keyof TabMeStackParamList> = NativeStackScreenProps<
|
||||
TabMeStackParamList,
|
||||
T
|
||||
>
|
||||
export type TabMeStackNavigationProp<RouteName extends keyof TabMeStackParamList> =
|
||||
StackNavigationProp<TabMeStackParamList, RouteName>
|
||||
|
||||
export type TabMeProfileStackParamList = {
|
||||
'Tab-Me-Profile-Root': undefined
|
||||
|
@ -165,6 +175,5 @@ export type TabMeProfileStackParamList = {
|
|||
fields?: Mastodon.Source['fields']
|
||||
}
|
||||
}
|
||||
export type TabMeProfileStackScreenProps<
|
||||
T extends keyof TabMeProfileStackParamList
|
||||
> = NativeStackScreenProps<TabMeProfileStackParamList, T>
|
||||
export type TabMeProfileStackScreenProps<T extends keyof TabMeProfileStackParamList> =
|
||||
NativeStackScreenProps<TabMeProfileStackParamList, T>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import apiInstance from '@api/instance'
|
||||
import { AxiosError } from 'axios'
|
||||
import { useQuery, UseQueryOptions } from 'react-query'
|
||||
import { useMutation, UseMutationOptions, useQuery, UseQueryOptions } from 'react-query'
|
||||
|
||||
export type QueryKey = ['Lists']
|
||||
export type QueryKeyLists = ['Lists']
|
||||
|
||||
const queryFunction = async () => {
|
||||
const res = await apiInstance<Mastodon.List[]>({
|
||||
|
@ -12,13 +12,49 @@ const queryFunction = async () => {
|
|||
return res.body
|
||||
}
|
||||
|
||||
const useListsQuery = ({
|
||||
options
|
||||
}: {
|
||||
options?: UseQueryOptions<Mastodon.List[], AxiosError>
|
||||
}) => {
|
||||
const queryKey: QueryKey = ['Lists']
|
||||
const useListsQuery = ({ options }: { options?: UseQueryOptions<Mastodon.List[], AxiosError> }) => {
|
||||
const queryKey: QueryKeyLists = ['Lists']
|
||||
return useQuery(queryKey, queryFunction, options)
|
||||
}
|
||||
|
||||
export { useListsQuery }
|
||||
type MutationVarsLists =
|
||||
| {
|
||||
type: 'add'
|
||||
payload: Omit<Mastodon.List, 'id'>
|
||||
}
|
||||
| {
|
||||
type: 'edit'
|
||||
payload: Mastodon.List
|
||||
}
|
||||
|
||||
const mutationFunction = async (params: MutationVarsLists) => {
|
||||
const body = new FormData()
|
||||
switch (params.type) {
|
||||
case 'add':
|
||||
body.append('title', params.payload.title)
|
||||
body.append('replies_policy', params.payload.replies_policy)
|
||||
|
||||
return apiInstance<Mastodon.List>({
|
||||
method: 'post',
|
||||
url: 'lists',
|
||||
body
|
||||
}).then(res => res.body)
|
||||
case 'edit':
|
||||
body.append('title', params.payload.title)
|
||||
body.append('replies_policy', params.payload.replies_policy)
|
||||
|
||||
return apiInstance<Mastodon.List>({
|
||||
method: 'put',
|
||||
url: `lists/${params.payload.id}`,
|
||||
body
|
||||
}).then(res => res.body)
|
||||
}
|
||||
}
|
||||
|
||||
const useListsMutation = (
|
||||
options: UseMutationOptions<Mastodon.List, AxiosError, MutationVarsLists>
|
||||
) => {
|
||||
return useMutation(mutationFunction, options)
|
||||
}
|
||||
|
||||
export { useListsQuery, useListsMutation }
|
||||
|
|
Loading…
Reference in New Issue