mirror of https://github.com/tooot-app/app
commit
5f50662008
|
@ -7,7 +7,7 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- name: -- Step 0 -- Extract branch name
|
||||
shell: bash
|
||||
|
@ -20,11 +20,11 @@ jobs:
|
|||
with:
|
||||
node-version: 14.x
|
||||
- name: -- Step 3 -- Use Expo action
|
||||
uses: expo/expo-github-action@v5
|
||||
uses: expo/expo-github-action@v6
|
||||
with:
|
||||
expo-version: 4.x
|
||||
expo-username: ${{ secrets.EXPO_USERNAME }}
|
||||
expo-token: ${{ secrets.EXPO_TOKEN }}
|
||||
username: ${{ secrets.EXPO_USERNAME }}
|
||||
token: ${{ secrets.EXPO_TOKEN }}
|
||||
- name: -- Step 4 -- Install node dependencies
|
||||
run: yarn install
|
||||
- name: -- Step 5 -- Install native dependencies
|
||||
|
@ -33,6 +33,7 @@ jobs:
|
|||
run: bundle install
|
||||
- name: -- Step 7 -- Run fastlane
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_12.5.1.app/Contents/Developer
|
||||
ENVIRONMENT: ${{ steps.branch.outputs.branch }}
|
||||
LC_ALL: en_US.UTF-8
|
||||
LANG: en_US.UTF-8
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* A new app store version has to be submitted.
|
||||
* Outdated versions in principle do not receive further OTA updates.
|
||||
|
||||
## Minor releases - App Store and OTA
|
||||
## Minor releases - App Store
|
||||
|
||||
"Minor releases" are artifacts published as `?.y.?`:
|
||||
* An artifact can be released as `?.y.?` when there is no change nor update made to the native modules.
|
||||
|
@ -21,11 +21,12 @@
|
|||
|
||||
## OTA release channels
|
||||
|
||||
* `MAJOR-environment`. Environments include `release`, `candidate` and `development`.
|
||||
* `MAJOR.MINOR-environment`. Environments include `release`, `candidate` and `development`.
|
||||
|
||||
## Major versions mapping to native module versions
|
||||
|
||||
| Major version | Native module version | Expo version |
|
||||
| :-----------: | :-------------------: | :----------: |
|
||||
| `0` | `210201` | `40.0.0` |
|
||||
| `1` | `210317` | `40.0.0` |
|
||||
| Version | Native module version | Expo version |
|
||||
| :------:| :-------------------: | :----------: |
|
||||
| `0-` | `210201` | `40.0.0` |
|
||||
| `1-` | `210317` | `40.0.0` |
|
||||
| `2.2` | `210916` | `41.0.0` |
|
|
@ -78,7 +78,7 @@ import com.android.build.OutputFile
|
|||
*/
|
||||
|
||||
project.ext.react = [
|
||||
enableHermes: true
|
||||
enableHermes: (findProperty('expo.jsEngine') ?: "jsc") == "hermes"
|
||||
]
|
||||
|
||||
apply from: '../../node_modules/react-native-unimodules/gradle.groovy'
|
||||
|
|
|
@ -31,4 +31,8 @@ FLIPPER_VERSION=0.75.1
|
|||
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.daemon=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.configureondemand=true
|
||||
|
||||
# The hosted JavaScript engine
|
||||
# Supported values: expo.jsEngine = "hermes" | "jsc"
|
||||
expo.jsEngine=hermes
|
|
@ -34,7 +34,7 @@ export default (): ExpoConfig => ({
|
|||
bundleIdentifier: 'com.xmflsct.app.tooot'
|
||||
},
|
||||
android: {
|
||||
versionCode: 4,
|
||||
jsEngine: 'hermes',
|
||||
package: 'com.xmflsct.app.tooot',
|
||||
googleServicesFile: './configs/google-services.json',
|
||||
permissions: ['CAMERA', 'VIBRATE']
|
||||
|
|
|
@ -8,7 +8,7 @@ ensure_env_vars(
|
|||
VERSIONS = read_json( json_path: "./package.json" )[:versions]
|
||||
ENVIRONMENT = ENV["ENVIRONMENT"]
|
||||
VERSION = "#{VERSIONS[:major]}.#{VERSIONS[:minor]}"
|
||||
RELEASE_CHANNEL = "#{VERSIONS[:major]}-#{ENVIRONMENT}"
|
||||
RELEASE_CHANNEL = "#{VERSIONS[:major]}.#{VERSIONS[:minor]}-#{ENVIRONMENT}"
|
||||
BUILD_NUMBER = "#{Time.now.strftime("%y%m%d")}#{ENV["GITHUB_RUN_NUMBER"]}"
|
||||
GITHUB_REPO = "tooot-app/app"
|
||||
case ENVIRONMENT
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// File.swift
|
||||
// tooot
|
||||
//
|
||||
// Created by Zheng Zhiyuan (SEBD) on 2021-03-15.
|
||||
// Created by Zhiyuan Zheng on 2021-08-22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
|
|
@ -11,7 +11,7 @@ target 'tooot' do
|
|||
use_react_native!(
|
||||
:path => config[:reactNativePath],
|
||||
# to enable hermes on iOS, change `false` to `true` and then install pods
|
||||
:hermes_enabled => true
|
||||
:hermes_enabled => false
|
||||
)
|
||||
|
||||
# Enables Flipper.
|
||||
|
|
737
ios/Podfile.lock
737
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
|
@ -148,7 +148,6 @@
|
|||
13B07F8E1A680F5B00A75B9A /* Resources */,
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
|
||||
5C5B41FC5F9DBE367CF7EF21 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -247,24 +246,6 @@
|
|||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
5C5B41FC5F9DBE367CF7EF21 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-frameworks.sh",
|
||||
"${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/iphoneos/hermes.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -438,7 +419,7 @@
|
|||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 i386";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 ";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
|
@ -500,7 +481,7 @@
|
|||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 i386";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 ";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<key>EXUpdatesReleaseChannel</key>
|
||||
<string>0-development</string>
|
||||
<key>EXUpdatesSDKVersion</key>
|
||||
<string>40.0.0</string>
|
||||
<string>0</string>
|
||||
<key>EXUpdatesURL</key>
|
||||
<string>https://exp.host/@xmflsct/tooot</string>
|
||||
</dict>
|
||||
|
|
181
package.json
181
package.json
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "tooot",
|
||||
"versions": {
|
||||
"native": "210511",
|
||||
"native": "210916",
|
||||
"major": 2,
|
||||
"minor": 1,
|
||||
"patch": 3,
|
||||
"expo": "41.0.0"
|
||||
"minor": 2,
|
||||
"patch": 0,
|
||||
"expo": "42.0.0"
|
||||
},
|
||||
"description": "tooot app for Mastodon",
|
||||
"author": "xmflsct <me@xmflsct.com>",
|
||||
|
@ -19,108 +19,97 @@
|
|||
"android": "react-native run-android",
|
||||
"ios": "react-native run-ios",
|
||||
"app:build": "bundle exec fastlane build",
|
||||
"test": "jest --watchAll",
|
||||
"release": "scripts/release.sh",
|
||||
"clean": "react-native-clean-project"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/react-native-action-sheet": "^3.9.0",
|
||||
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
|
||||
"@react-native-async-storage/async-storage": "^1.15.4",
|
||||
"@react-native-community/blur": "^3.6.0",
|
||||
"@react-native-community/cameraroll": "^4.0.4",
|
||||
"@react-native-community/masked-view": "0.1.11",
|
||||
"@react-native-community/netinfo": "6.0.0",
|
||||
"@expo/react-native-action-sheet": "3.11.0",
|
||||
"@neverdull-agency/expo-unlimited-secure-store": "1.0.10",
|
||||
"@react-native-async-storage/async-storage": "1.15.8",
|
||||
"@react-native-community/blur": "3.6.0",
|
||||
"@react-native-community/cameraroll": "4.0.4",
|
||||
"@react-native-community/netinfo": "6.0.2",
|
||||
"@react-native-community/segmented-control": "2.2.2",
|
||||
"@react-navigation/bottom-tabs": "^5.11.11",
|
||||
"@react-navigation/native": "^5.9.4",
|
||||
"@react-navigation/stack": "^5.14.5",
|
||||
"@reduxjs/toolkit": "^1.5.1",
|
||||
"@sentry/react-native": "^2.4.3",
|
||||
"@sharcoux/slider": "^5.3.0",
|
||||
"axios": "^0.21.1",
|
||||
"expo": "^41.0.1",
|
||||
"expo-auth-session": "~3.2.3",
|
||||
"expo-av": "~9.1.2",
|
||||
"expo-crypto": "~9.1.0",
|
||||
"expo-firebase-analytics": "~4.0.2",
|
||||
"expo-haptics": "~10.0.0",
|
||||
"expo-image-manipulator": "~9.1.0",
|
||||
"expo-image-picker": "~10.1.4",
|
||||
"expo-linking": "~2.2.3",
|
||||
"expo-localization": "~10.1.0",
|
||||
"expo-notifications": "~0.11.6",
|
||||
"expo-random": "~11.1.2",
|
||||
"expo-screen-capture": "^3.1.0",
|
||||
"expo-secure-store": "~10.1.0",
|
||||
"expo-splash-screen": "~0.10.2",
|
||||
"expo-status-bar": "~1.0.4",
|
||||
"expo-store-review": "~4.0.2",
|
||||
"expo-video-thumbnails": "~5.1.0",
|
||||
"expo-web-browser": "~9.1.0",
|
||||
"i18next": "^20.3.0",
|
||||
"li": "^1.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"@react-navigation/bottom-tabs": "6.0.7",
|
||||
"@react-navigation/native": "6.0.4",
|
||||
"@react-navigation/native-stack": "6.2.2",
|
||||
"@react-navigation/stack": "6.0.9",
|
||||
"@reduxjs/toolkit": "1.6.1",
|
||||
"@sentry/react-native": "2.6.2",
|
||||
"@sharcoux/slider": "5.5.2",
|
||||
"axios": "0.22.0",
|
||||
"expo": "42.0.4",
|
||||
"expo-auth-session": "3.3.1",
|
||||
"expo-av": "9.2.3",
|
||||
"expo-crypto": "9.2.0",
|
||||
"expo-device": "^3.3.0",
|
||||
"expo-firebase-analytics": "4.1.0",
|
||||
"expo-haptics": "10.1.0",
|
||||
"expo-image-manipulator": "9.2.2",
|
||||
"expo-image-picker": "10.2.3",
|
||||
"expo-linking": "2.3.1",
|
||||
"expo-localization": "10.2.0",
|
||||
"expo-notifications": "0.12.3",
|
||||
"expo-permissions": "^12.1.1",
|
||||
"expo-random": "11.2.0",
|
||||
"expo-screen-capture": "3.2.0",
|
||||
"expo-secure-store": "10.2.0",
|
||||
"expo-splash-screen": "0.11.4",
|
||||
"expo-status-bar": "1.0.4",
|
||||
"expo-store-review": "4.1.0",
|
||||
"expo-updates": "^0.8.5",
|
||||
"expo-video-thumbnails": "^5.2.1",
|
||||
"expo-web-browser": "9.2.0",
|
||||
"i18next": "20.6.1",
|
||||
"li": "1.3.0",
|
||||
"lodash": "4.17.21",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-i18next": "^11.9.0",
|
||||
"react-native": "~0.64.1",
|
||||
"react-native-animated-spinkit": "^1.5.2",
|
||||
"react-native-blurhash": "^1.1.4",
|
||||
"react-native-fast-image": "^8.3.4",
|
||||
"react-native-feather": "^1.0.2",
|
||||
"react-native-flash-message": "^0.1.23",
|
||||
"react-native-gesture-handler": "~1.10.3",
|
||||
"react-native-htmlview": "^0.16.0",
|
||||
"react-native-pager-view": "5.1.9",
|
||||
"react-native-reanimated": "~2.1.0",
|
||||
"react-i18next": "11.12.0",
|
||||
"react-native": "0.64.2",
|
||||
"react-native-animated-spinkit": "1.5.2",
|
||||
"react-native-blurhash": "1.1.5",
|
||||
"react-native-fast-image": "8.5.11",
|
||||
"react-native-feather": "1.1.2",
|
||||
"react-native-flash-message": "0.2.0",
|
||||
"react-native-gesture-handler": "1.10.3",
|
||||
"react-native-htmlview": "0.16.0",
|
||||
"react-native-pager-view": "5.4.6",
|
||||
"react-native-reanimated": "2.2.2",
|
||||
"react-native-safe-area-context": "3.2.0",
|
||||
"react-native-screens": "~3.3.0",
|
||||
"react-native-screens": "3.8.0",
|
||||
"react-native-svg": "12.1.1",
|
||||
"react-native-swipe-list-view": "^3.2.7",
|
||||
"react-native-tab-view": "^3.0.1",
|
||||
"react-native-unimodules": "~0.13.3",
|
||||
"react-query": "^3.16.0",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-timeago": "^5.2.0",
|
||||
"redux-persist": "^6.0.0",
|
||||
"rn-placeholder": "^3.0.3",
|
||||
"sentry-expo": "^3.1.3",
|
||||
"tslib": "^2.2.0",
|
||||
"valid-url": "^1.0.9"
|
||||
"react-native-swipe-list-view": "3.2.9",
|
||||
"react-native-tab-view": "3.1.1",
|
||||
"react-native-unimodules": "0.14.8",
|
||||
"react-query": "3.25.1",
|
||||
"react-redux": "7.2.5",
|
||||
"react-timeago": "6.2.1",
|
||||
"redux-persist": "6.0.0",
|
||||
"rn-placeholder": "3.0.3",
|
||||
"sentry-expo": "4.0.1",
|
||||
"tslib": "2.3.1",
|
||||
"valid-url": "1.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.14.3",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.14.2",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@expo/config": "^3.3.43",
|
||||
"@jest/types": "^26.6.2",
|
||||
"@testing-library/jest-native": "^4.0.1",
|
||||
"@testing-library/react-hooks": "^5.1.2",
|
||||
"@testing-library/react-native": "^7.2.0",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/lodash": "^4.14.170",
|
||||
"@types/react": "~17.0.8",
|
||||
"@types/react-dom": "~17.0.5",
|
||||
"@types/react-native": "~0.64.6",
|
||||
"@types/react-navigation": "^3.4.0",
|
||||
"@types/react-redux": "^7.1.16",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
"@types/react-timeago": "^4.1.2",
|
||||
"@types/valid-url": "^1.0.3",
|
||||
"@welldone-software/why-did-you-render": "^6.1.4",
|
||||
"babel-jest": "~26.6.3",
|
||||
"babel-plugin-module-resolver": "^4.1.0",
|
||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||
"chalk": "^4.1.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-expo": "^41.0.0",
|
||||
"nock": "^13.0.11",
|
||||
"react-native-clean-project": "^3.6.4",
|
||||
"react-navigation": "^4.4.4",
|
||||
"react-navigation-stack": "^2.10.4",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"typescript": "~4.2.4"
|
||||
"@babel/core": "7.15.5",
|
||||
"@babel/plugin-proposal-optional-chaining": "7.14.5",
|
||||
"@babel/preset-typescript": "7.15.0",
|
||||
"@expo/config": "6.0.0",
|
||||
"@types/lodash": "4.14.175",
|
||||
"@types/react": "17.0.27",
|
||||
"@types/react-dom": "17.0.9",
|
||||
"@types/react-native": "0.64.13",
|
||||
"@types/react-navigation": "3.4.0",
|
||||
"@types/react-redux": "7.1.18",
|
||||
"@types/react-timeago": "4.1.3",
|
||||
"@types/valid-url": "1.0.3",
|
||||
"@welldone-software/why-did-you-render": "6.2.1",
|
||||
"babel-plugin-module-resolver": "4.1.0",
|
||||
"babel-plugin-transform-remove-console": "6.9.4",
|
||||
"chalk": "4.1.2",
|
||||
"dotenv": "10.0.0",
|
||||
"react-native-clean-project": "3.6.7",
|
||||
"typescript": "4.4.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@ if [ $# -ne 1 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
expo publish --target bare --release-channel=$1
|
||||
expo publish --quiet --target bare --release-channel=$1
|
|
@ -1,152 +0,0 @@
|
|||
declare namespace Nav {
|
||||
type RootStackParamList = {
|
||||
'Screen-Tabs': undefined
|
||||
'Screen-Actions':
|
||||
| {
|
||||
type: 'status'
|
||||
queryKey: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
}
|
||||
| {
|
||||
type: 'account'
|
||||
account: Mastodon.Account
|
||||
}
|
||||
| {
|
||||
type: 'notifications_filter'
|
||||
}
|
||||
'Screen-Announcements': { showAll: boolean }
|
||||
'Screen-Compose':
|
||||
| {
|
||||
type: 'edit'
|
||||
incomingStatus: Mastodon.Status
|
||||
replyToStatus?: Mastodon.Status
|
||||
queryKey?: [
|
||||
'Timeline',
|
||||
{
|
||||
page: App.Pages
|
||||
hashtag?: Mastodon.Tag['name']
|
||||
list?: Mastodon.List['id']
|
||||
toot?: Mastodon.Status['id']
|
||||
account?: Mastodon.Account['id']
|
||||
}
|
||||
]
|
||||
}
|
||||
| {
|
||||
type: 'reply'
|
||||
incomingStatus: Mastodon.Status
|
||||
accts: Mastodon.Account['acct'][]
|
||||
queryKey?: [
|
||||
'Timeline',
|
||||
{
|
||||
page: App.Pages
|
||||
hashtag?: Mastodon.Tag['name']
|
||||
list?: Mastodon.List['id']
|
||||
toot?: Mastodon.Status['id']
|
||||
account?: Mastodon.Account['id']
|
||||
}
|
||||
]
|
||||
}
|
||||
| {
|
||||
type: 'conversation'
|
||||
accts: Mastodon.Account['acct'][]
|
||||
}
|
||||
| undefined
|
||||
'Screen-ImagesViewer': {
|
||||
imageUrls: {
|
||||
id: Mastodon.Attachment['id']
|
||||
preview_url: Mastodon.AttachmentImage['preview_url']
|
||||
url: Mastodon.AttachmentImage['url']
|
||||
remote_url?: Mastodon.AttachmentImage['remote_url']
|
||||
blurhash: Mastodon.AttachmentImage['blurhash']
|
||||
width?: number
|
||||
height?: number
|
||||
}[]
|
||||
id: Mastodon.Attachment['id']
|
||||
}
|
||||
}
|
||||
|
||||
type ScreenComposeStackParamList = {
|
||||
'Screen-Compose-Root': undefined
|
||||
'Screen-Compose-EditAttachment': { index: number }
|
||||
'Screen-Compose-DraftsList': { timestamp: number }
|
||||
}
|
||||
|
||||
type ScreenTabsStackParamList = {
|
||||
'Tab-Local': undefined
|
||||
'Tab-Public': undefined
|
||||
'Tab-Compose': undefined
|
||||
'Tab-Notifications': undefined
|
||||
'Tab-Me': undefined
|
||||
}
|
||||
|
||||
type TabSharedStackParamList = {
|
||||
'Tab-Shared-Account': {
|
||||
account: Mastodon.Account | Mastodon.Mention
|
||||
}
|
||||
'Tab-Shared-Attachments': { account: Mastodon.Account }
|
||||
'Tab-Shared-Hashtag': {
|
||||
hashtag: Mastodon.Tag['name']
|
||||
}
|
||||
'Tab-Shared-Search': { text: string | undefined }
|
||||
'Tab-Shared-Toot': {
|
||||
toot: Mastodon.Status
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
}
|
||||
'Tab-Shared-Users':
|
||||
| {
|
||||
reference: 'accounts'
|
||||
id: Mastodon.Account['id']
|
||||
type: 'following' | 'followers'
|
||||
count: number
|
||||
}
|
||||
| {
|
||||
reference: 'statuses'
|
||||
id: Mastodon.Status['id']
|
||||
type: 'reblogged_by' | 'favourited_by'
|
||||
count: number
|
||||
}
|
||||
}
|
||||
|
||||
type TabLocalStackParamList = {
|
||||
'Tab-Local-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
type TabPublicStackParamList = {
|
||||
'Tab-Public-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
type TabNotificationsStackParamList = {
|
||||
'Tab-Notifications-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
type TabMeStackParamList = {
|
||||
'Tab-Me-Root': undefined
|
||||
'Tab-Me-Bookmarks': undefined
|
||||
'Tab-Me-Conversations': undefined
|
||||
'Tab-Me-Favourites': undefined
|
||||
'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
|
||||
'Tab-Me-Settings-Fontsize': undefined
|
||||
'Tab-Me-Switch': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
type TabMeProfileStackParamList = {
|
||||
'Tab-Me-Profile-Root': undefined
|
||||
'Tab-Me-Profile-Name': {
|
||||
display_name: Mastodon.Account['display_name']
|
||||
}
|
||||
'Tab-Me-Profile-Note': {
|
||||
note: Mastodon.Source['note']
|
||||
}
|
||||
'Tab-Me-Profile-Fields': {
|
||||
fields?: Mastodon.Source['fields']
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,15 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { HeaderLeft } from '@components/Header'
|
||||
import { displayMessage, Message, removeMessage } from '@components/Message'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
import { useNetInfo } from '@react-native-community/netinfo'
|
||||
import { NavigationContainer } from '@react-navigation/native'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import ScreenActions from '@screens/Actions'
|
||||
import ScreenAnnouncements from '@screens/Announcements'
|
||||
import ScreenCompose from '@screens/Compose'
|
||||
import ScreenImagesViewer from '@screens/ImagesViewer'
|
||||
import ScreenTabs from '@screens/Tabs'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
import pushUseConnect from '@utils/push/useConnect'
|
||||
import pushUseReceive from '@utils/push/useReceive'
|
||||
import pushUseRespond from '@utils/push/useRespond'
|
||||
|
@ -22,12 +24,11 @@ import { addScreenshotListener } from 'expo-screen-capture'
|
|||
import React, { useCallback, useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Alert, Platform, StatusBar } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import { onlineManager, useQueryClient } from 'react-query'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import * as Sentry from 'sentry-expo'
|
||||
|
||||
const Stack = createNativeStackNavigator<Nav.RootStackParamList>()
|
||||
const Stack = createNativeStackNavigator<RootStackParamList>()
|
||||
|
||||
export interface Props {
|
||||
localCorrupt?: string
|
||||
|
@ -71,9 +72,9 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||
(prev, next) => prev.length === next.length
|
||||
)
|
||||
const queryClient = useQueryClient()
|
||||
pushUseConnect({ navigationRef, mode, t, instances, dispatch })
|
||||
pushUseReceive({ navigationRef, queryClient, instances })
|
||||
pushUseRespond({ navigationRef, queryClient, instances, dispatch })
|
||||
pushUseConnect({ mode, t, instances, dispatch })
|
||||
pushUseReceive({ queryClient, instances })
|
||||
pushUseRespond({ queryClient, instances, dispatch })
|
||||
|
||||
// Prevent screenshot alert
|
||||
useEffect(() => {
|
||||
|
@ -96,7 +97,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||
type: 'error',
|
||||
mode
|
||||
})
|
||||
navigationRef.current?.navigate('Screen-Tabs', {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me'
|
||||
})
|
||||
}
|
||||
|
@ -114,7 +115,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||
|
||||
// Callbacks
|
||||
const navigationContainerOnReady = useCallback(() => {
|
||||
const currentRoute = navigationRef.current?.getCurrentRoute()
|
||||
const currentRoute = navigationRef.getCurrentRoute()
|
||||
routeRef.current = {
|
||||
name: currentRoute?.name,
|
||||
params: currentRoute?.params
|
||||
|
@ -124,7 +125,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||
}, [])
|
||||
const navigationContainerOnStateChange = useCallback(() => {
|
||||
const previousRoute = routeRef.current
|
||||
const currentRoute = navigationRef.current?.getCurrentRoute()
|
||||
const currentRoute = navigationRef.getCurrentRoute()
|
||||
|
||||
const matchTabName = currentRoute?.name?.match(/(Tab-.*)-Root/)
|
||||
if (matchTabName) {
|
||||
|
@ -166,8 +167,8 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||
name='Screen-Actions'
|
||||
component={ScreenActions}
|
||||
options={{
|
||||
stackPresentation: 'transparentModal',
|
||||
stackAnimation: 'fade',
|
||||
presentation: 'transparentModal',
|
||||
animation: 'fade',
|
||||
headerShown: false
|
||||
}}
|
||||
/>
|
||||
|
@ -175,38 +176,33 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||
name='Screen-Announcements'
|
||||
component={ScreenAnnouncements}
|
||||
options={({ navigation }) => ({
|
||||
stackPresentation: 'transparentModal',
|
||||
stackAnimation: 'fade',
|
||||
presentation: 'transparentModal',
|
||||
animation: 'fade',
|
||||
headerShown: true,
|
||||
headerHideShadow: true,
|
||||
headerTopInsetEnabled: false,
|
||||
headerShadowVisible: false,
|
||||
headerTransparent: true,
|
||||
headerStyle: { backgroundColor: 'transparent' },
|
||||
headerLeft: () => (
|
||||
<HeaderLeft content='X' onPress={() => navigation.goBack()} />
|
||||
),
|
||||
headerTitle: t('screenAnnouncements:heading'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('screenAnnouncements:heading')} />
|
||||
)
|
||||
})
|
||||
headerTitle: t('screenAnnouncements:heading')
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose'
|
||||
component={ScreenCompose}
|
||||
options={{
|
||||
stackPresentation: 'fullScreenModal',
|
||||
...(Platform.OS === 'android' && { headerShown: false })
|
||||
headerShown: false,
|
||||
presentation: 'fullScreenModal'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-ImagesViewer'
|
||||
component={ScreenImagesViewer}
|
||||
options={{
|
||||
stackPresentation: 'fullScreenModal',
|
||||
stackAnimation: 'fade',
|
||||
...(Platform.OS === 'android' && { headerShown: false })
|
||||
headerShown: false,
|
||||
presentation: 'fullScreenModal',
|
||||
animation: 'fade'
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
|
|
|
@ -46,7 +46,7 @@ const apiGeneral = async <T = unknown>({
|
|||
params,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': `tooot/${Constants.manifest.version}`,
|
||||
'User-Agent': `tooot/${Constants.manifest?.version}`,
|
||||
Accept: '*/*',
|
||||
...headers
|
||||
},
|
||||
|
|
|
@ -68,7 +68,7 @@ const apiInstance = async <T = unknown>({
|
|||
params,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': `tooot/${Constants.manifest.version}`,
|
||||
'User-Agent': `tooot/${Constants.manifest?.version}`,
|
||||
Accept: '*/*',
|
||||
...headers,
|
||||
...(token && {
|
||||
|
|
|
@ -28,7 +28,7 @@ const apiTooot = async <T = unknown>({
|
|||
body,
|
||||
sentry = false
|
||||
}: Params): Promise<{ body: T }> => {
|
||||
const key = Constants.manifest.extra?.toootApiKey
|
||||
const key = Constants.manifest?.extra?.toootApiKey
|
||||
|
||||
console.log(
|
||||
ctx.bgGreen.bold(' API tooot ') +
|
||||
|
@ -49,7 +49,7 @@ const apiTooot = async <T = unknown>({
|
|||
headers: {
|
||||
...(key && { 'x-tooot-key': key }),
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': `tooot/${Constants.manifest.version}`,
|
||||
'User-Agent': `tooot/${Constants.manifest?.version}`,
|
||||
Accept: '*/*',
|
||||
...headers
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { ParseEmojis } from '@components/Parse'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback } from 'react'
|
||||
|
@ -21,7 +22,7 @@ const ComponentAccount: React.FC<Props> = ({
|
|||
}) => {
|
||||
const { theme } = useTheme()
|
||||
const navigation = useNavigation<
|
||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
StackNavigationProp<TabLocalStackParamList>
|
||||
>()
|
||||
|
||||
const onPress = useCallback(() => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { useNavigation } from '@react-navigation/native'
|
||||
import { TabMeStackNavigationProp } from '@utils/navigation/navigators'
|
||||
import addInstance from '@utils/slices/instances/add'
|
||||
import { Instance } from '@utils/slices/instancesSlice'
|
||||
import * as AuthSession from 'expo-auth-session'
|
||||
|
@ -21,7 +22,9 @@ const InstanceAuth = React.memo(
|
|||
useProxy: false
|
||||
})
|
||||
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<
|
||||
TabMeStackNavigationProp<'Tab-Me-Root' | 'Tab-Me-Switch'>
|
||||
>()
|
||||
const queryClient = useQueryClient()
|
||||
const dispatch = useDispatch()
|
||||
|
||||
|
|
|
@ -10,10 +10,9 @@ import TimelinePoll from '@components/Timeline/Shared/Poll'
|
|||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { getInstance, getInstanceAccount } from '@utils/slices/instancesSlice'
|
||||
import { getInstanceAccount } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import htmlparser2 from 'htmlparser2-without-node-native'
|
||||
import { uniqBy } from 'lodash'
|
||||
import React, { useCallback } from 'react'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
|
|
|
@ -6,6 +6,7 @@ import AttachmentImage from '@components/Timeline/Shared/Attachment/Image'
|
|||
import AttachmentUnsupported from '@components/Timeline/Shared/Attachment/Unsupported'
|
||||
import AttachmentVideo from '@components/Timeline/Shared/Attachment/Video'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react'
|
||||
|
@ -35,7 +36,7 @@ const TimelineAttachment = React.memo(
|
|||
}, [])
|
||||
|
||||
const imageUrls = useRef<
|
||||
Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls']
|
||||
RootStackParamList['Screen-ImagesViewer']['imageUrls']
|
||||
>([])
|
||||
const navigation = useNavigation()
|
||||
useEffect(() => {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import Button from '@components/Button'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { Video } from 'expo-av'
|
||||
import React, { useCallback, useRef, useState } from 'react'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
AppState,
|
||||
AppStateStatus,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
View
|
||||
} from 'react-native'
|
||||
import { Blurhash } from 'react-native-blurhash'
|
||||
import attachmentAspectRatio from './aspectRatio'
|
||||
import analytics from '@components/analytics'
|
||||
|
@ -45,15 +51,43 @@ const AttachmentVideo: React.FC<Props> = ({
|
|||
videoPlayer.current?.setOnPlaybackStatusUpdate(props => {
|
||||
if (props.isLoaded) {
|
||||
setVideoLoaded(true)
|
||||
}
|
||||
// @ts-ignore
|
||||
if (props.positionMillis) {
|
||||
// @ts-ignore
|
||||
setVideoPosition(props.positionMillis)
|
||||
if (props.positionMillis) {
|
||||
setVideoPosition(props.positionMillis)
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [videoLoaded, videoPosition])
|
||||
|
||||
const appState = useRef(AppState.currentState)
|
||||
useEffect(() => {
|
||||
AppState.addEventListener('change', _handleAppStateChange)
|
||||
|
||||
return () => {
|
||||
AppState.removeEventListener('change', _handleAppStateChange)
|
||||
}
|
||||
}, [])
|
||||
const _handleAppStateChange = async (nextAppState: AppStateStatus) => {
|
||||
if (appState.current.match(/active/) && nextAppState.match(/inactive/)) {
|
||||
await videoPlayer.current?.pauseAsync()
|
||||
} else if (
|
||||
gifv &&
|
||||
appState.current.match(/background/) &&
|
||||
nextAppState.match(/active/)
|
||||
) {
|
||||
await videoPlayer.current?.setIsMutedAsync(true)
|
||||
await videoPlayer.current?.playAsync()
|
||||
}
|
||||
|
||||
appState.current = nextAppState
|
||||
}
|
||||
|
||||
const playerStatus = useRef<any>(null)
|
||||
useEffect(() => {
|
||||
videoPlayer.current?.setOnPlaybackStatusUpdate(playbackStatus => {
|
||||
playerStatus.current = playbackStatus
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
|
@ -83,16 +117,15 @@ const AttachmentVideo: React.FC<Props> = ({
|
|||
posterStyle: { resizeMode: 'cover' }
|
||||
})}
|
||||
useNativeControls={false}
|
||||
onFullscreenUpdate={event => {
|
||||
onFullscreenUpdate={async event => {
|
||||
if (
|
||||
event.fullscreenUpdate ===
|
||||
Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS
|
||||
) {
|
||||
if (gifv) {
|
||||
videoPlayer.current?.setIsLoopingAsync(true)
|
||||
videoPlayer.current?.playAsync()
|
||||
await videoPlayer.current?.pauseAsync()
|
||||
} else {
|
||||
videoPlayer.current?.pauseAsync()
|
||||
await videoPlayer.current?.pauseAsync()
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
@ -108,7 +141,7 @@ const AttachmentVideo: React.FC<Props> = ({
|
|||
}}
|
||||
/>
|
||||
) : null
|
||||
) : !gifv ? (
|
||||
) : !gifv || (gifv && playerStatus.current === false) ? (
|
||||
<Button
|
||||
round
|
||||
overlay
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import apiInstance from '@api/instance'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
import { NavigationProp, ParamListBase } from '@react-navigation/native'
|
||||
import { store } from '@root/store'
|
||||
import { SearchResult } from '@utils/queryHooks/search'
|
||||
import { getInstanceUrl } from '@utils/slices/instancesSlice'
|
||||
|
@ -22,24 +21,7 @@ const matcherAccount = new RegExp(
|
|||
|
||||
export let loadingLink = false
|
||||
|
||||
const openLink = async (
|
||||
url: string,
|
||||
navigation?: NavigationProp<
|
||||
ParamListBase,
|
||||
string,
|
||||
Readonly<{
|
||||
key: string
|
||||
index: number
|
||||
routeNames: string[]
|
||||
history?: unknown[] | undefined
|
||||
routes: any[]
|
||||
type: string
|
||||
stale: false
|
||||
}>,
|
||||
{},
|
||||
{}
|
||||
>
|
||||
) => {
|
||||
const openLink = async (url: string, navigation?: any) => {
|
||||
if (loadingLink) {
|
||||
return
|
||||
}
|
||||
|
@ -52,7 +34,7 @@ const openLink = async (
|
|||
// @ts-ignore
|
||||
navigation.push(page, options)
|
||||
} else {
|
||||
navigationRef.current?.navigate(page, options)
|
||||
navigationRef.navigate(page, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { NavigationContainerRef } from '@react-navigation/native'
|
||||
import { createRef } from 'react'
|
||||
import { createNavigationContainerRef } from '@react-navigation/native'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
|
||||
const navigationRef = createRef<NavigationContainerRef>()
|
||||
const navigationRef = createNavigationContainerRef<RootStackParamList>()
|
||||
|
||||
export default navigationRef
|
||||
|
|
|
@ -1,22 +1,244 @@
|
|||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import React from 'react'
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context'
|
||||
import ScreenActionsRoot from './Actions/Root'
|
||||
|
||||
export type ScreenAccountProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
'Screen-Actions'
|
||||
>
|
||||
import analytics from '@components/analytics'
|
||||
import Button from '@components/Button'
|
||||
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
||||
import {
|
||||
getInstanceAccount,
|
||||
getInstanceUrl
|
||||
} from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||
import {
|
||||
PanGestureHandler,
|
||||
State,
|
||||
TapGestureHandler
|
||||
} from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
Extrapolate,
|
||||
interpolate,
|
||||
runOnJS,
|
||||
useAnimatedGestureHandler,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withTiming
|
||||
} from 'react-native-reanimated'
|
||||
import {
|
||||
SafeAreaProvider,
|
||||
useSafeAreaInsets
|
||||
} from 'react-native-safe-area-context'
|
||||
import { useSelector } from 'react-redux'
|
||||
import ActionsAccount from './Actions/Account'
|
||||
import ActionsDomain from './Actions/Domain'
|
||||
import ActionsNotificationsFilter from './Actions/NotificationsFilter'
|
||||
import ActionsShare from './Actions/Share'
|
||||
import ActionsStatus from './Actions/Status'
|
||||
|
||||
const ScreenActions = React.memo(
|
||||
(props: ScreenAccountProp) => {
|
||||
({
|
||||
route: { params },
|
||||
navigation
|
||||
}: RootStackScreenProps<'Screen-Actions'>) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const instanceAccount = useSelector(
|
||||
getInstanceAccount,
|
||||
(prev, next) => prev?.id === next?.id
|
||||
)
|
||||
let sameAccount = false
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
sameAccount = instanceAccount?.id === params.status.account.id
|
||||
break
|
||||
case 'account':
|
||||
sameAccount = instanceAccount?.id === params.account.id
|
||||
break
|
||||
}
|
||||
|
||||
const instanceDomain = useSelector(getInstanceUrl)
|
||||
let sameDomain = true
|
||||
let statusDomain: string
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
statusDomain = params.status.uri
|
||||
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
||||
: ''
|
||||
sameDomain = instanceDomain === statusDomain
|
||||
break
|
||||
}
|
||||
|
||||
const { theme } = useTheme()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const DEFAULT_VALUE = 350
|
||||
const screenHeight = Dimensions.get('screen').height
|
||||
const panY = useSharedValue(DEFAULT_VALUE)
|
||||
useEffect(() => {
|
||||
panY.value = withTiming(0)
|
||||
}, [])
|
||||
const styleTop = useAnimatedStyle(() => {
|
||||
return {
|
||||
bottom: interpolate(
|
||||
panY.value,
|
||||
[0, screenHeight],
|
||||
[0, -screenHeight],
|
||||
Extrapolate.CLAMP
|
||||
)
|
||||
}
|
||||
})
|
||||
const dismiss = useCallback(() => {
|
||||
navigation.goBack()
|
||||
}, [])
|
||||
const onGestureEvent = useAnimatedGestureHandler({
|
||||
onActive: ({ translationY }) => {
|
||||
panY.value = translationY
|
||||
},
|
||||
onEnd: ({ velocityY }) => {
|
||||
if (velocityY > 500) {
|
||||
runOnJS(dismiss)()
|
||||
} else {
|
||||
panY.value = withTiming(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const actions = useMemo(() => {
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount ? (
|
||||
<ActionsAccount
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
account={params.status.account}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{sameAccount && params.status ? (
|
||||
<ActionsStatus
|
||||
navigation={navigation}
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
status={params.status}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{!sameDomain && statusDomain ? (
|
||||
<ActionsDomain
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
domain={statusDomain}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{params.status.visibility !== 'direct' ? (
|
||||
<ActionsShare
|
||||
url={params.status.url || params.status.uri}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.cancel')}
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_acknowledge')
|
||||
}}
|
||||
style={styles.button}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'account':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount ? (
|
||||
<ActionsAccount account={params.account} dismiss={dismiss} />
|
||||
) : null}
|
||||
<ActionsShare
|
||||
url={params.account.url}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.cancel')}
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_acknowledge')
|
||||
}}
|
||||
style={styles.button}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'notifications_filter':
|
||||
return <ActionsNotificationsFilter />
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<SafeAreaProvider>
|
||||
<ScreenActionsRoot {...props} />
|
||||
<Animated.View style={{ flex: 1 }}>
|
||||
<TapGestureHandler
|
||||
onHandlerStateChange={({ nativeEvent }) => {
|
||||
if (nativeEvent.state === State.ACTIVE) {
|
||||
dismiss()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.overlay,
|
||||
{ backgroundColor: theme.backgroundOverlayInvert }
|
||||
]}
|
||||
>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.container,
|
||||
styleTop,
|
||||
{
|
||||
backgroundColor: theme.backgroundDefault,
|
||||
paddingBottom: insets.bottom || StyleConstants.Spacing.L
|
||||
}
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.handle,
|
||||
{ backgroundColor: theme.primaryOverlay }
|
||||
]}
|
||||
/>
|
||||
{actions}
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
</Animated.View>
|
||||
</TapGestureHandler>
|
||||
</Animated.View>
|
||||
</SafeAreaProvider>
|
||||
)
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
container: {
|
||||
paddingTop: StyleConstants.Spacing.M
|
||||
},
|
||||
handle: {
|
||||
alignSelf: 'center',
|
||||
width: StyleConstants.Spacing.S * 8,
|
||||
height: StyleConstants.Spacing.S / 2,
|
||||
borderRadius: 100,
|
||||
top: -StyleConstants.Spacing.M * 2
|
||||
},
|
||||
button: {
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}
|
||||
})
|
||||
|
||||
export default ScreenActions
|
||||
|
|
|
@ -1,241 +0,0 @@
|
|||
import analytics from '@components/analytics'
|
||||
import Button from '@components/Button'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import {
|
||||
getInstanceAccount,
|
||||
getInstanceUrl
|
||||
} from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||
import {
|
||||
PanGestureHandler,
|
||||
State,
|
||||
TapGestureHandler
|
||||
} from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
Extrapolate,
|
||||
interpolate,
|
||||
runOnJS,
|
||||
useAnimatedGestureHandler,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
withTiming
|
||||
} from 'react-native-reanimated'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { useSelector } from 'react-redux'
|
||||
import ActionsAccount from './Account'
|
||||
import ActionsDomain from './Domain'
|
||||
import ActionsNotificationsFilter from './NotificationsFilter'
|
||||
import ActionsShare from './Share'
|
||||
import ActionsStatus from './Status'
|
||||
|
||||
export type ScreenAccountProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
'Screen-Actions'
|
||||
>
|
||||
|
||||
const ScreenActionsRoot = React.memo(
|
||||
({ route: { params }, navigation }: ScreenAccountProp) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const instanceAccount = useSelector(
|
||||
getInstanceAccount,
|
||||
(prev, next) => prev?.id === next?.id
|
||||
)
|
||||
let sameAccount = false
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
sameAccount = instanceAccount?.id === params.status.account.id
|
||||
break
|
||||
case 'account':
|
||||
sameAccount = instanceAccount?.id === params.account.id
|
||||
break
|
||||
}
|
||||
|
||||
const instanceDomain = useSelector(getInstanceUrl)
|
||||
let sameDomain = true
|
||||
let statusDomain: string
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
statusDomain = params.status.uri
|
||||
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
||||
: ''
|
||||
sameDomain = instanceDomain === statusDomain
|
||||
break
|
||||
}
|
||||
|
||||
const { theme } = useTheme()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const DEFAULT_VALUE = 350
|
||||
const screenHeight = Dimensions.get('screen').height
|
||||
const panY = useSharedValue(DEFAULT_VALUE)
|
||||
useEffect(() => {
|
||||
panY.value = withTiming(0)
|
||||
}, [])
|
||||
const styleTop = useAnimatedStyle(() => {
|
||||
return {
|
||||
bottom: interpolate(
|
||||
panY.value,
|
||||
[0, screenHeight],
|
||||
[0, -screenHeight],
|
||||
Extrapolate.CLAMP
|
||||
)
|
||||
}
|
||||
})
|
||||
const dismiss = useCallback(() => {
|
||||
navigation.goBack()
|
||||
}, [])
|
||||
const onGestureEvent = useAnimatedGestureHandler({
|
||||
onActive: ({ translationY }) => {
|
||||
panY.value = translationY
|
||||
},
|
||||
onEnd: ({ velocityY }) => {
|
||||
if (velocityY > 500) {
|
||||
runOnJS(dismiss)()
|
||||
} else {
|
||||
panY.value = withTiming(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const actions = useMemo(() => {
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount ? (
|
||||
<ActionsAccount
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
account={params.status.account}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{sameAccount && params.status ? (
|
||||
<ActionsStatus
|
||||
navigation={navigation}
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
status={params.status}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{!sameDomain && statusDomain ? (
|
||||
<ActionsDomain
|
||||
queryKey={params.queryKey}
|
||||
rootQueryKey={params.rootQueryKey}
|
||||
domain={statusDomain}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
{params.status.visibility !== 'direct' ? (
|
||||
<ActionsShare
|
||||
url={params.status.url || params.status.uri}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
) : null}
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.cancel')}
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_acknowledge')
|
||||
}}
|
||||
style={styles.button}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'account':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount ? (
|
||||
<ActionsAccount account={params.account} dismiss={dismiss} />
|
||||
) : null}
|
||||
<ActionsShare
|
||||
url={params.account.url}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={t('common:buttons.cancel')}
|
||||
onPress={() => {
|
||||
analytics('bottomsheet_acknowledge')
|
||||
}}
|
||||
style={styles.button}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'notifications_filter':
|
||||
return <ActionsNotificationsFilter />
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Animated.View style={{ flex: 1 }}>
|
||||
<TapGestureHandler
|
||||
onHandlerStateChange={({ nativeEvent }) => {
|
||||
if (nativeEvent.state === State.ACTIVE) {
|
||||
dismiss()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.overlay,
|
||||
{ backgroundColor: theme.backgroundOverlayInvert }
|
||||
]}
|
||||
>
|
||||
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.container,
|
||||
styleTop,
|
||||
{
|
||||
backgroundColor: theme.backgroundDefault,
|
||||
paddingBottom: insets.bottom || StyleConstants.Spacing.L
|
||||
}
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.handle,
|
||||
{ backgroundColor: theme.primaryOverlay }
|
||||
]}
|
||||
/>
|
||||
{actions}
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
</Animated.View>
|
||||
</TapGestureHandler>
|
||||
</Animated.View>
|
||||
)
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-end'
|
||||
},
|
||||
container: {
|
||||
paddingTop: StyleConstants.Spacing.M
|
||||
},
|
||||
handle: {
|
||||
alignSelf: 'center',
|
||||
width: StyleConstants.Spacing.S * 8,
|
||||
height: StyleConstants.Spacing.S / 2,
|
||||
borderRadius: 100,
|
||||
top: -StyleConstants.Spacing.M * 2
|
||||
},
|
||||
button: {
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}
|
||||
})
|
||||
|
||||
export default ScreenActionsRoot
|
|
@ -9,13 +9,14 @@ import {
|
|||
useTimelineMutation
|
||||
} from '@utils/queryHooks/timeline'
|
||||
import analytics from '@components/analytics'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import apiInstance from '@api/instance'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
|
||||
export interface Props {
|
||||
navigation: StackNavigationProp<Nav.RootStackParamList, 'Screen-Actions'>
|
||||
navigation: NativeStackNavigationProp<RootStackParamList, 'Screen-Actions'>
|
||||
queryKey: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
|
|
|
@ -4,8 +4,8 @@ import haptics from '@components/haptics'
|
|||
import { ParseHTML } from '@components/Parse'
|
||||
import RelativeTime from '@components/RelativeTime'
|
||||
import { BlurView } from '@react-native-community/blur'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
||||
import {
|
||||
useAnnouncementMutation,
|
||||
useAnnouncementQuery
|
||||
|
@ -20,12 +20,9 @@ import FastImage from 'react-native-fast-image'
|
|||
import { FlatList, ScrollView } from 'react-native-gesture-handler'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
|
||||
export type ScreenAnnouncementsProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
const ScreenAnnouncements: React.FC<RootStackScreenProps<
|
||||
'Screen-Announcements'
|
||||
>
|
||||
|
||||
const ScreenAnnouncements: React.FC<ScreenAnnouncementsProp> = ({
|
||||
>> = ({
|
||||
route: {
|
||||
params: { showAll = false }
|
||||
},
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import analytics from '@components/analytics'
|
||||
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import haptics from '@root/components/haptics'
|
||||
import formatText from '@screens/Compose/formatText'
|
||||
import ComposeRoot from '@screens/Compose/Root'
|
||||
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { updateStoreReview } from '@utils/slices/contextsSlice'
|
||||
import {
|
||||
|
@ -31,7 +32,6 @@ import {
|
|||
StyleSheet
|
||||
} from 'react-native'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import { useQueryClient } from 'react-query'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import * as Sentry from 'sentry-expo'
|
||||
|
@ -43,14 +43,9 @@ import composeParseState from './Compose/utils/parseState'
|
|||
import composePost from './Compose/utils/post'
|
||||
import composeReducer from './Compose/utils/reducer'
|
||||
|
||||
export type ScreenComposeProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
'Screen-Compose'
|
||||
>
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
||||
const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
||||
route: { params },
|
||||
navigation
|
||||
}) => {
|
||||
|
@ -371,10 +366,7 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||
edges={hasKeyboard ? ['top'] : ['top', 'bottom']}
|
||||
>
|
||||
<ComposeContext.Provider value={{ composeState, composeDispatch }}>
|
||||
<Stack.Navigator
|
||||
screenOptions={{ headerTopInsetEnabled: false }}
|
||||
initialRouteName='Screen-Compose-Root'
|
||||
>
|
||||
<Stack.Navigator initialRouteName='Screen-Compose-Root'>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-Root'
|
||||
component={ComposeRoot}
|
||||
|
@ -405,18 +397,12 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||
<Stack.Screen
|
||||
name='Screen-Compose-DraftsList'
|
||||
component={ComposeDraftsList}
|
||||
options={{
|
||||
stackPresentation: 'modal',
|
||||
...(Platform.OS === 'android' && { headerShown: false })
|
||||
}}
|
||||
options={{ headerShown: false, presentation: 'modal' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment'
|
||||
component={ComposeEditAttachment}
|
||||
options={{
|
||||
stackPresentation: 'modal',
|
||||
...(Platform.OS === 'android' && { headerShown: false })
|
||||
}}
|
||||
options={{ headerShown: false, presentation: 'modal' }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</ComposeContext.Provider>
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import ComposeDraftsListRoot from './DraftsList/Root'
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
export type ScreenComposeEditAttachmentProp = StackScreenProps<
|
||||
Nav.ScreenComposeStackParamList,
|
||||
const ComposeDraftsList: React.FC<ScreenComposeStackScreenProps<
|
||||
'Screen-Compose-DraftsList'
|
||||
>
|
||||
|
||||
const ComposeDraftsList: React.FC<ScreenComposeEditAttachmentProp> = ({
|
||||
>> = ({
|
||||
route: {
|
||||
params: { timestamp }
|
||||
},
|
||||
|
@ -37,7 +34,7 @@ const ComposeDraftsList: React.FC<ScreenComposeEditAttachmentProp> = ({
|
|||
)
|
||||
|
||||
return (
|
||||
<Stack.Navigator screenOptions={{ headerTopInsetEnabled: false }}>
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment-Root'
|
||||
children={children}
|
||||
|
@ -49,7 +46,7 @@ const ComposeDraftsList: React.FC<ScreenComposeEditAttachmentProp> = ({
|
|||
<HeaderCenter content={t('content.draftsList.header.title')} />
|
||||
)
|
||||
}),
|
||||
headerHideShadow: true
|
||||
headerShadowVisible: false
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { HeaderLeft } from '@components/Header'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import ComposeEditAttachmentRoot from './EditAttachment/Root'
|
||||
import ComposeEditAttachmentSubmit from './EditAttachment/Submit'
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
export type ScreenComposeEditAttachmentProp = StackScreenProps<
|
||||
Nav.ScreenComposeStackParamList,
|
||||
const ComposeEditAttachment: React.FC<ScreenComposeStackScreenProps<
|
||||
'Screen-Compose-EditAttachment'
|
||||
>
|
||||
|
||||
const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
||||
>> = ({
|
||||
route: {
|
||||
params: { index }
|
||||
},
|
||||
|
@ -45,21 +42,14 @@ const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
|||
style={{ flex: 1 }}
|
||||
>
|
||||
<SafeAreaView style={{ flex: 1 }} edges={['left', 'right', 'bottom']}>
|
||||
<Stack.Navigator screenOptions={{ headerTopInsetEnabled: false }}>
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen
|
||||
name='Screen-Compose-EditAttachment-Root'
|
||||
children={children}
|
||||
options={{
|
||||
headerLeft,
|
||||
headerRight: () => <ComposeEditAttachmentSubmit index={index} />,
|
||||
headerTitle: t('content.editAttachment.header.title'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter
|
||||
content={t('content.editAttachment.header.title')}
|
||||
/>
|
||||
)
|
||||
})
|
||||
headerTitle: t('content.editAttachment.header.title')
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
|
|
|
@ -15,7 +15,7 @@ export interface Props {
|
|||
|
||||
const ComposeDrafts: React.FC<Props> = ({ accessibleRefDrafts }) => {
|
||||
const { t } = useTranslation('screenCompose')
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
const { composeState } = useContext(ComposeContext)
|
||||
const instanceDrafts = useSelector(getInstanceDrafts)?.filter(
|
||||
draft => draft.timestamp !== composeState.timestamp
|
||||
|
|
|
@ -40,7 +40,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
|||
const { composeState, composeDispatch } = useContext(ComposeContext)
|
||||
const { t } = useTranslation('screenCompose')
|
||||
const { theme } = useTheme()
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
|
||||
const flatListRef = useRef<FlatList>(null)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { store } from '@root/store'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
import { getInstanceAccount } from '@utils/slices/instancesSlice'
|
||||
import composeInitialState from './initialState'
|
||||
import { ComposeState } from './types'
|
||||
|
@ -34,7 +35,7 @@ const assignVisibility = (
|
|||
}
|
||||
|
||||
const composeParseState = (
|
||||
params: NonNullable<Nav.RootStackParamList['Screen-Compose']>
|
||||
params: NonNullable<RootStackParamList['Screen-Compose']>
|
||||
): ComposeState => {
|
||||
switch (params.type) {
|
||||
case 'edit':
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import apiInstance from '@api/instance'
|
||||
import { ComposeState } from '@screens/Compose/utils/types'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
import * as Crypto from 'expo-crypto'
|
||||
|
||||
const composePost = async (
|
||||
params: Nav.RootStackParamList['Screen-Compose'],
|
||||
params: RootStackParamList['Screen-Compose'],
|
||||
composeState: ComposeState
|
||||
) => {
|
||||
const formData = new FormData()
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
import React, { ComponentType, useCallback, useEffect } from 'react'
|
||||
import {
|
||||
Animated,
|
||||
|
@ -20,11 +21,11 @@ import useImageIndexChange from './hooks/useImageIndexChange'
|
|||
import useRequestClose from './hooks/useRequestClose'
|
||||
|
||||
type Props = {
|
||||
images: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls']
|
||||
images: RootStackParamList['Screen-ImagesViewer']['imageUrls']
|
||||
imageIndex: number
|
||||
onRequestClose: () => void
|
||||
onLongPress?: (
|
||||
image: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
||||
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
||||
) => void
|
||||
onImageIndexChange?: (imageIndex: number) => void
|
||||
backgroundColor?: string
|
||||
|
@ -50,9 +51,7 @@ function ImageViewer ({
|
|||
HeaderComponent
|
||||
}: Props) {
|
||||
const imageList = React.createRef<
|
||||
VirtualizedList<
|
||||
Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
||||
>
|
||||
VirtualizedList<RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]>
|
||||
>()
|
||||
const [opacity, onRequestCloseEnhanced] = useRequestClose(onRequestClose)
|
||||
const [currentImageIndex, onScroll] = useImageIndexChange(imageIndex, SCREEN)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import haptics from '@components/haptics'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import CameraRoll from '@react-native-community/cameraroll'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
import i18next from 'i18next'
|
||||
import { RefObject } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
|
@ -10,7 +11,7 @@ import { FileSystem, Permissions } from 'react-native-unimodules'
|
|||
type CommonProps = {
|
||||
messageRef: RefObject<FlashMessage>
|
||||
mode: 'light' | 'dark'
|
||||
image: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
||||
image: RootStackParamList['Screen-ImagesViewer']['imageUrls'][0]
|
||||
}
|
||||
|
||||
const saveIos = async ({ messageRef, mode, image }: CommonProps) => {
|
||||
|
|
|
@ -2,7 +2,11 @@ import analytics from '@components/analytics'
|
|||
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import { Message } from '@components/Message'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import {
|
||||
RootStackParamList,
|
||||
RootStackScreenProps
|
||||
} from '@utils/navigation/navigators'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { findIndex } from 'lodash'
|
||||
import React, { RefObject, useCallback, useRef, useState } from 'react'
|
||||
|
@ -24,9 +28,12 @@ const HeaderComponent = React.memo(
|
|||
imageUrls
|
||||
}: {
|
||||
messageRef: RefObject<FlashMessage>
|
||||
navigation: ScreenImagesViewerProp['navigation']
|
||||
navigation: NativeStackNavigationProp<
|
||||
RootStackParamList,
|
||||
'Screen-ImagesViewer'
|
||||
>
|
||||
currentIndex: number
|
||||
imageUrls: Nav.RootStackParamList['Screen-ImagesViewer']['imageUrls']
|
||||
imageUrls: RootStackParamList['Screen-ImagesViewer']['imageUrls']
|
||||
}) => {
|
||||
const insets = useSafeAreaInsets()
|
||||
const { mode } = useTheme()
|
||||
|
@ -98,17 +105,12 @@ const HeaderComponent = React.memo(
|
|||
(prev, next) => prev.currentIndex === next.currentIndex
|
||||
)
|
||||
|
||||
export type ScreenImagesViewerProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
'Screen-ImagesViewer'
|
||||
>
|
||||
|
||||
const ScreenImagesViewer = ({
|
||||
route: {
|
||||
params: { imageUrls, id }
|
||||
},
|
||||
navigation
|
||||
}: ScreenImagesViewerProp) => {
|
||||
}: RootStackScreenProps<'Screen-ImagesViewer'>) => {
|
||||
if (imageUrls.length === 0) {
|
||||
navigation.goBack()
|
||||
return null
|
||||
|
|
|
@ -5,8 +5,10 @@ import {
|
|||
BottomTabNavigationOptions,
|
||||
createBottomTabNavigator
|
||||
} from '@react-navigation/bottom-tabs'
|
||||
import { NavigatorScreenParams } from '@react-navigation/native'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import {
|
||||
RootStackScreenProps,
|
||||
ScreenTabsStackParamList
|
||||
} from '@utils/navigation/navigators'
|
||||
import { getPreviousTab } from '@utils/slices/contextsSlice'
|
||||
import {
|
||||
getInstanceAccount,
|
||||
|
@ -25,23 +27,10 @@ import TabMe from './Tabs/Me'
|
|||
import TabNotifications from './Tabs/Notifications'
|
||||
import TabPublic from './Tabs/Public'
|
||||
|
||||
export type ScreenTabsParamList = {
|
||||
'Tab-Local': NavigatorScreenParams<Nav.TabLocalStackParamList>
|
||||
'Tab-Public': NavigatorScreenParams<Nav.TabPublicStackParamList>
|
||||
'Tab-Compose': NavigatorScreenParams<Nav.ScreenComposeStackParamList>
|
||||
'Tab-Notifications': NavigatorScreenParams<Nav.TabNotificationsStackParamList>
|
||||
'Tab-Me': NavigatorScreenParams<Nav.TabMeStackParamList>
|
||||
}
|
||||
|
||||
export type ScreenTabsProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
'Screen-Tabs'
|
||||
>
|
||||
|
||||
const Tab = createBottomTabNavigator<Nav.ScreenTabsStackParamList>()
|
||||
const Tab = createBottomTabNavigator<ScreenTabsStackParamList>()
|
||||
|
||||
const ScreenTabs = React.memo(
|
||||
({ navigation }: ScreenTabsProp) => {
|
||||
({ navigation }: RootStackScreenProps<'Screen-Tabs'>) => {
|
||||
const { mode, theme } = useTheme()
|
||||
|
||||
const instanceActive = useSelector(getInstanceActive)
|
||||
|
@ -52,7 +41,12 @@ const ScreenTabs = React.memo(
|
|||
|
||||
const screenOptions = useCallback(
|
||||
({ route }): BottomTabNavigationOptions => ({
|
||||
tabBarVisible: instanceActive !== -1,
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: theme.primaryDefault,
|
||||
tabBarInactiveTintColor: theme.secondary,
|
||||
tabBarShowLabel: false,
|
||||
...(Platform.OS === 'android' && { tabBarHideOnKeyboard: true }),
|
||||
tabBarStyle: { display: instanceActive !== -1 ? 'flex' : 'none' },
|
||||
tabBarIcon: ({
|
||||
focused,
|
||||
color,
|
||||
|
@ -95,15 +89,7 @@ const ScreenTabs = React.memo(
|
|||
}),
|
||||
[instanceAccount?.avatarStatic, instanceActive]
|
||||
)
|
||||
const tabBarOptions = useMemo(
|
||||
() => ({
|
||||
activeTintColor: theme.primaryDefault,
|
||||
inactiveTintColor: theme.secondary,
|
||||
showLabel: false,
|
||||
...(Platform.OS === 'android' && { keyboardHidesTabBar: true })
|
||||
}),
|
||||
[mode]
|
||||
)
|
||||
|
||||
const composeListeners = useMemo(
|
||||
() => ({
|
||||
tabPress: (e: any) => {
|
||||
|
@ -133,7 +119,6 @@ const ScreenTabs = React.memo(
|
|||
<Tab.Navigator
|
||||
initialRouteName={instanceActive !== -1 ? previousTab : 'Tab-Me'}
|
||||
screenOptions={screenOptions}
|
||||
tabBarOptions={tabBarOptions}
|
||||
>
|
||||
<Tab.Screen name='Tab-Local' component={TabLocal} />
|
||||
<Tab.Screen name='Tab-Public' component={TabPublic} />
|
||||
|
|
|
@ -2,33 +2,23 @@ import analytics from '@components/analytics'
|
|||
import { HeaderCenter, HeaderRight } from '@components/Header'
|
||||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
|
||||
import { ScreenTabsParamList } from '@screens/Tabs'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import {
|
||||
ScreenTabsScreenProps,
|
||||
TabLocalStackParamList
|
||||
} from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import sharedScreens from './Shared/sharedScreens'
|
||||
import TabSharedRoot from './Shared/Root'
|
||||
|
||||
export type TabLocalProp = BottomTabScreenProps<
|
||||
ScreenTabsParamList,
|
||||
'Tab-Local'
|
||||
>
|
||||
|
||||
const Stack = createNativeStackNavigator<Nav.TabLocalStackParamList>()
|
||||
const Stack = createNativeStackNavigator<TabLocalStackParamList>()
|
||||
|
||||
const TabLocal = React.memo(
|
||||
({ navigation }: TabLocalProp) => {
|
||||
({ navigation }: ScreenTabsScreenProps<'Tab-Local'>) => {
|
||||
const { t, i18n } = useTranslation('screenTabs')
|
||||
|
||||
const screenOptions = useMemo(
|
||||
() => ({
|
||||
headerHideShadow: true,
|
||||
headerTopInsetEnabled: false
|
||||
}),
|
||||
[]
|
||||
)
|
||||
const screenOptionsRoot = useMemo(
|
||||
() => ({
|
||||
headerTitle: t('tabs.local.name'),
|
||||
|
@ -64,13 +54,13 @@ const TabLocal = React.memo(
|
|||
)
|
||||
|
||||
return (
|
||||
<Stack.Navigator screenOptions={screenOptions}>
|
||||
<Stack.Navigator screenOptions={{ headerShadowVisible: false }}>
|
||||
<Stack.Screen
|
||||
name='Tab-Local-Root'
|
||||
options={screenOptionsRoot}
|
||||
children={children}
|
||||
/>
|
||||
{sharedScreens(Stack as any)}
|
||||
{TabSharedRoot({ Stack })}
|
||||
</Stack.Navigator>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { TabMeStackParamList } from '@utils/navigation/navigators'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import TabMeBookmarks from './Me/Bookmarks'
|
||||
import TabMeConversations from './Me/Cconversations'
|
||||
import TabMeFavourites from './Me/Favourites'
|
||||
|
@ -14,25 +15,23 @@ import TabMeRoot from './Me/Root'
|
|||
import TabMeSettings from './Me/Settings'
|
||||
import TabMeSettingsFontsize from './Me/SettingsFontsize'
|
||||
import TabMeSwitch from './Me/Switch'
|
||||
import sharedScreens from './Shared/sharedScreens'
|
||||
import TabSharedRoot from './Shared/Root'
|
||||
|
||||
const Stack = createNativeStackNavigator<Nav.TabMeStackParamList>()
|
||||
const Stack = createNativeStackNavigator<TabMeStackParamList>()
|
||||
|
||||
const TabMe = React.memo(
|
||||
() => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}
|
||||
>
|
||||
<Stack.Navigator screenOptions={{ headerShadowVisible: false }}>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Root'
|
||||
component={TabMeRoot}
|
||||
options={{
|
||||
headerTranslucent: true,
|
||||
headerShadowVisible: false,
|
||||
headerStyle: { backgroundColor: 'rgba(255, 255, 255, 0)' },
|
||||
headerCenter: () => null
|
||||
headerShown: false
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
|
@ -108,15 +107,15 @@ const TabMe = React.memo(
|
|||
name='Tab-Me-Profile'
|
||||
component={TabMeProfile}
|
||||
options={{
|
||||
stackPresentation: 'modal',
|
||||
...(Platform.OS === 'android' && { headerShown: false })
|
||||
headerShown: false,
|
||||
presentation: 'modal'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Push'
|
||||
component={TabMePush}
|
||||
options={({ navigation }) => ({
|
||||
stackPresentation: 'modal',
|
||||
presentation: 'modal',
|
||||
headerShown: true,
|
||||
headerTitle: t('me.stacks.push.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
|
@ -162,7 +161,7 @@ const TabMe = React.memo(
|
|||
name='Tab-Me-Switch'
|
||||
component={TabMeSwitch}
|
||||
options={({ navigation }) => ({
|
||||
stackPresentation: 'modal',
|
||||
presentation: 'modal',
|
||||
headerShown: true,
|
||||
headerTitle: t('me.stacks.switch.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
|
@ -179,7 +178,7 @@ const TabMe = React.memo(
|
|||
})}
|
||||
/>
|
||||
|
||||
{sharedScreens(Stack as any)}
|
||||
{TabSharedRoot({ Stack })}
|
||||
</Stack.Navigator>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useListsQuery } from '@utils/queryHooks/lists'
|
||||
import React from 'react'
|
||||
|
||||
const TabMeLists: React.FC<StackScreenProps<
|
||||
Nav.TabMeStackParamList,
|
||||
'Tab-Me-Lists'
|
||||
>> = ({ navigation }) => {
|
||||
const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({
|
||||
navigation
|
||||
}) => {
|
||||
const { data } = useListsQuery({})
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React, { useCallback } from 'react'
|
||||
|
||||
const TabMeListsList: React.FC<StackScreenProps<
|
||||
Nav.TabMeStackParamList,
|
||||
'Tab-Me-Lists-List'
|
||||
>> = ({
|
||||
const TabMeListsList: React.FC<TabMeStackScreenProps<'Tab-Me-Lists-List'>> = ({
|
||||
route: {
|
||||
params: { list }
|
||||
}
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { Message } from '@components/Message'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import {
|
||||
TabMeProfileStackParamList,
|
||||
TabMeStackScreenProps
|
||||
} from '@utils/navigation/navigators'
|
||||
import React, { useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { KeyboardAvoidingView, Platform } from 'react-native'
|
||||
import FlashMessage from 'react-native-flash-message'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import TabMeProfileFields from './Profile/Fields'
|
||||
import TabMeProfileName from './Profile/Name'
|
||||
import TabMeProfileNote from './Profile/Note'
|
||||
import TabMeProfileRoot from './Profile/Root'
|
||||
|
||||
const Stack = createNativeStackNavigator<Nav.TabMeProfileStackParamList>()
|
||||
const Stack = createNativeStackNavigator<TabMeProfileStackParamList>()
|
||||
|
||||
const TabMeProfile: React.FC<StackScreenProps<
|
||||
Nav.TabMeStackParamList,
|
||||
'Tab-Me-Switch'
|
||||
>> = ({ navigation }) => {
|
||||
const TabMeProfile: React.FC<TabMeStackScreenProps<'Tab-Me-Switch'>> = ({
|
||||
navigation
|
||||
}) => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const messageRef = useRef<FlashMessage>(null)
|
||||
|
||||
|
@ -25,9 +27,7 @@ const TabMeProfile: React.FC<StackScreenProps<
|
|||
style={{ flex: 1 }}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
>
|
||||
<Stack.Navigator
|
||||
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}
|
||||
>
|
||||
<Stack.Navigator screenOptions={{ headerShadowVisible: false }}>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Profile-Root'
|
||||
options={{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import Input from '@components/Input'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useProfileMutation } from '@utils/queryHooks/profile'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
|
@ -23,8 +23,7 @@ const prepareFields = (
|
|||
})
|
||||
}
|
||||
|
||||
const TabMeProfileFields: React.FC<StackScreenProps<
|
||||
Nav.TabMeProfileStackParamList,
|
||||
const TabMeProfileFields: React.FC<TabMeProfileStackScreenProps<
|
||||
'Tab-Me-Profile-Fields'
|
||||
> & { messageRef: RefObject<FlashMessage> }> = ({
|
||||
messageRef,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import Input from '@components/Input'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useProfileMutation } from '@utils/queryHooks/profile'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
|
@ -10,8 +10,7 @@ import { Alert, StyleSheet } from 'react-native'
|
|||
import FlashMessage from 'react-native-flash-message'
|
||||
import { ScrollView } from 'react-native-gesture-handler'
|
||||
|
||||
const TabMeProfileName: React.FC<StackScreenProps<
|
||||
Nav.TabMeProfileStackParamList,
|
||||
const TabMeProfileName: React.FC<TabMeProfileStackScreenProps<
|
||||
'Tab-Me-Profile-Name'
|
||||
> & { messageRef: RefObject<FlashMessage> }> = ({
|
||||
messageRef,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import Input from '@components/Input'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useProfileMutation } from '@utils/queryHooks/profile'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
|
@ -10,8 +10,7 @@ import { Alert, StyleSheet, View } from 'react-native'
|
|||
import FlashMessage from 'react-native-flash-message'
|
||||
import { ScrollView } from 'react-native-gesture-handler'
|
||||
|
||||
const TabMeProfileNote: React.FC<StackScreenProps<
|
||||
Nav.TabMeProfileStackParamList,
|
||||
const TabMeProfileNote: React.FC<TabMeProfileStackScreenProps<
|
||||
'Tab-Me-Profile-Note'
|
||||
> & { messageRef: RefObject<FlashMessage> }> = ({
|
||||
messageRef,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import analytics from '@components/analytics'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
|
||||
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
|
@ -12,8 +12,7 @@ import { ScrollView } from 'react-native-gesture-handler'
|
|||
import { useDispatch } from 'react-redux'
|
||||
import ProfileAvatarHeader from './Root/AvatarHeader'
|
||||
|
||||
const TabMeProfileRoot: React.FC<StackScreenProps<
|
||||
Nav.TabMeProfileStackParamList,
|
||||
const TabMeProfileRoot: React.FC<TabMeProfileStackScreenProps<
|
||||
'Tab-Me-Profile-Root'
|
||||
> & { messageRef: RefObject<FlashMessage> }> = ({ messageRef, navigation }) => {
|
||||
const { mode } = useTheme()
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
const Collections: React.FC = () => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
|
||||
const listsQuery = useListsQuery({
|
||||
options: {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
const Settings: React.FC = () => {
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
|
|
|
@ -5,7 +5,7 @@ import React from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const AccountInformationSwitch: React.FC = () => {
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
return (
|
||||
|
|
|
@ -29,7 +29,7 @@ const SettingsAnalytics: React.FC = () => {
|
|||
}
|
||||
/>
|
||||
<Text style={[styles.version, { color: theme.secondary }]}>
|
||||
{t('me.settings.version', { version: Constants.manifest.version })}
|
||||
{t('me.settings.version', { version: Constants.manifest?.version })}
|
||||
</Text>
|
||||
</MenuContainer>
|
||||
)
|
||||
|
|
|
@ -23,7 +23,7 @@ import { useDispatch, useSelector } from 'react-redux'
|
|||
import { mapFontsizeToName } from '../SettingsFontsize'
|
||||
|
||||
const SettingsApp: React.FC = () => {
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
const dispatch = useDispatch()
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const { setTheme } = useTheme()
|
||||
|
|
|
@ -15,7 +15,7 @@ import { getInstanceActive } from '@utils/slices/instancesSlice'
|
|||
|
||||
const SettingsTooot: React.FC = () => {
|
||||
const instanceActive = useSelector(getInstanceActive)
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import Button from '@components/Button'
|
|||
import haptics from '@components/haptics'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import {
|
||||
changeFontsize,
|
||||
getSettingsFontsize,
|
||||
|
@ -32,8 +32,7 @@ export const mapFontsizeToName = (size: SettingsState['fontsize']) => {
|
|||
}
|
||||
}
|
||||
|
||||
const TabMeSettingsFontsize: React.FC<StackScreenProps<
|
||||
Nav.TabMeStackParamList,
|
||||
const TabMeSettingsFontsize: React.FC<TabMeStackScreenProps<
|
||||
'Tab-Me-Settings-Fontsize'
|
||||
>> = () => {
|
||||
const { mode, theme } = useTheme()
|
||||
|
@ -129,6 +128,7 @@ const TabMeSettingsFontsize: React.FC<StackScreenProps<
|
|||
onPress={() => {
|
||||
if (initialSize > -1) {
|
||||
haptics('Light')
|
||||
// @ts-ignore
|
||||
dispatch(changeFontsize(initialSize - 1))
|
||||
}
|
||||
}}
|
||||
|
@ -142,6 +142,7 @@ const TabMeSettingsFontsize: React.FC<StackScreenProps<
|
|||
onPress={() => {
|
||||
if (initialSize < 3) {
|
||||
haptics('Light')
|
||||
// @ts-ignore
|
||||
dispatch(changeFontsize(initialSize + 1))
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -2,28 +2,21 @@ import analytics from '@components/analytics'
|
|||
import { HeaderCenter, HeaderRight } from '@components/Header'
|
||||
import Timeline from '@components/Timeline'
|
||||
import TimelineNotifications from '@components/Timeline/Notifications'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import sharedScreens from '@screens/Tabs/Shared/sharedScreens'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import { TabNotificationsStackParamList } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import TabSharedRoot from './Shared/Root'
|
||||
|
||||
const Stack = createNativeStackNavigator<Nav.TabNotificationsStackParamList>()
|
||||
const Stack = createNativeStackNavigator<TabNotificationsStackParamList>()
|
||||
|
||||
const TabNotifications = React.memo(
|
||||
() => {
|
||||
const navigation = useNavigation()
|
||||
const { t, i18n } = useTranslation('screenTabs')
|
||||
|
||||
const screenOptions = useMemo(
|
||||
() => ({
|
||||
headerHideShadow: true,
|
||||
headerTopInsetEnabled: false
|
||||
}),
|
||||
[]
|
||||
)
|
||||
const screenOptionsRoot = useMemo(
|
||||
() => ({
|
||||
headerTitle: t('tabs.notifications.name'),
|
||||
|
@ -39,7 +32,7 @@ const TabNotifications = React.memo(
|
|||
content='Filter'
|
||||
onPress={() => {
|
||||
analytics('notificationsfilter_tap')
|
||||
navigation.navigate('Screen-Actions', {
|
||||
navigationRef.navigate('Screen-Actions', {
|
||||
type: 'notifications_filter'
|
||||
})
|
||||
}}
|
||||
|
@ -62,13 +55,13 @@ const TabNotifications = React.memo(
|
|||
)
|
||||
|
||||
return (
|
||||
<Stack.Navigator screenOptions={screenOptions}>
|
||||
<Stack.Navigator screenOptions={{ headerShadowVisible: false }}>
|
||||
<Stack.Screen
|
||||
name='Tab-Notifications-Root'
|
||||
children={children}
|
||||
options={screenOptionsRoot}
|
||||
/>
|
||||
{sharedScreens(Stack as any)}
|
||||
{TabSharedRoot({ Stack })}
|
||||
</Stack.Navigator>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -3,26 +3,23 @@ import { HeaderRight } from '@components/Header'
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import SegmentedControl from '@react-native-community/segmented-control'
|
||||
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
|
||||
import { ScreenTabsParamList } from '@screens/Tabs'
|
||||
import sharedScreens from '@screens/Tabs/Shared/sharedScreens'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import {
|
||||
ScreenTabsScreenProps,
|
||||
TabPublicStackParamList
|
||||
} from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dimensions, StyleSheet } from 'react-native'
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import { TabView } from 'react-native-tab-view'
|
||||
import TabSharedRoot from './Shared/Root'
|
||||
|
||||
export type TabPublicProps = BottomTabScreenProps<
|
||||
ScreenTabsParamList,
|
||||
'Tab-Public'
|
||||
>
|
||||
|
||||
const Stack = createNativeStackNavigator<Nav.TabPublicStackParamList>()
|
||||
const Stack = createNativeStackNavigator<TabPublicStackParamList>()
|
||||
|
||||
const TabPublic = React.memo(
|
||||
({ navigation }: TabPublicProps) => {
|
||||
({ navigation }: ScreenTabsScreenProps<'Tab-Public'>) => {
|
||||
const { t, i18n } = useTranslation('screenTabs')
|
||||
const { mode } = useTheme()
|
||||
|
||||
|
@ -40,16 +37,9 @@ const TabPublic = React.memo(
|
|||
key: 'Local'
|
||||
}
|
||||
]
|
||||
const screenOptions = useMemo(
|
||||
() => ({
|
||||
headerHideShadow: true,
|
||||
headerTopInsetEnabled: false
|
||||
}),
|
||||
[]
|
||||
)
|
||||
const screenOptionsRoot = useMemo(
|
||||
() => ({
|
||||
headerCenter: () => (
|
||||
headerTitle: () => (
|
||||
<SegmentedControl
|
||||
appearance={mode}
|
||||
values={pages.map(p => p.title)}
|
||||
|
@ -113,13 +103,13 @@ const TabPublic = React.memo(
|
|||
)
|
||||
|
||||
return (
|
||||
<Stack.Navigator screenOptions={screenOptions}>
|
||||
<Stack.Navigator screenOptions={{ headerShadowVisible: false }}>
|
||||
<Stack.Screen
|
||||
name='Tab-Public-Root'
|
||||
options={screenOptionsRoot}
|
||||
children={children}
|
||||
/>
|
||||
{sharedScreens(Stack as any)}
|
||||
{TabSharedRoot({ Stack })}
|
||||
</Stack.Navigator>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ import { HeaderRight } from '@components/Header'
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import SegmentedControl from '@react-native-community/segmented-control'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useAccountQuery } from '@utils/queryHooks/account'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
|
@ -16,9 +17,10 @@ import AccountAttachments from './Account/Attachments'
|
|||
import AccountHeader from './Account/Header'
|
||||
import AccountInformation from './Account/Information'
|
||||
import AccountNav from './Account/Nav'
|
||||
import { SharedAccountProp } from './sharedScreens'
|
||||
|
||||
const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
||||
const TabSharedAccount: React.FC<TabSharedStackScreenProps<
|
||||
'Tab-Shared-Account'
|
||||
>> = ({
|
||||
route: {
|
||||
params: { account }
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ import GracefullyImage from '@components/GracefullyImage'
|
|||
import Icon from '@components/Icon'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
|
@ -24,7 +25,7 @@ export interface Props {
|
|||
const AccountAttachments = React.memo(
|
||||
({ account }: Props) => {
|
||||
const navigation = useNavigation<
|
||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
StackNavigationProp<TabLocalStackParamList>
|
||||
>()
|
||||
const { theme } = useTheme()
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface Props {
|
|||
}
|
||||
|
||||
const Conversation = ({ account }: { account: Mastodon.Account }) => {
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
const query = useRelationshipQuery({ id: account.id })
|
||||
|
||||
return query.data && !query.data.blocked_by ? (
|
||||
|
@ -45,7 +45,7 @@ const AccountInformationActions: React.FC<Props> = ({ account, myInfo }) => {
|
|||
}
|
||||
|
||||
const { t } = useTranslation('screenTabs')
|
||||
const navigation = useNavigation()
|
||||
const navigation = useNavigation<any>()
|
||||
|
||||
if (account?.moved) {
|
||||
const accountMoved = account.moved
|
||||
|
|
|
@ -4,6 +4,7 @@ import GracefullyImage from '@components/GracefullyImage'
|
|||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import React from 'react'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
|
@ -20,7 +21,7 @@ const AccountInformationAvatar: React.FC<Props> = ({
|
|||
edit
|
||||
}) => {
|
||||
const navigation = useNavigation<
|
||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
StackNavigationProp<TabLocalStackParamList>
|
||||
>()
|
||||
const { reduceMotionEnabled } = useAccessibility()
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useNavigation } from '@react-navigation/native'
|
|||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { StyleConstants } from '@root/utils/styles/constants'
|
||||
import { useTheme } from '@root/utils/styles/ThemeManager'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
|
@ -15,7 +16,7 @@ export interface Props {
|
|||
|
||||
const AccountInformationStats: React.FC<Props> = ({ account, myInfo }) => {
|
||||
const navigation = useNavigation<
|
||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
StackNavigationProp<TabLocalStackParamList>
|
||||
>()
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React, { useCallback } from 'react'
|
||||
import { SharedAttachmentsProp } from './sharedScreens'
|
||||
|
||||
const TabSharedAttachments: React.FC<SharedAttachmentsProp> = ({
|
||||
const TabSharedAttachments: React.FC<TabSharedStackScreenProps<
|
||||
'Tab-Shared-Attachments'
|
||||
>> = ({
|
||||
route: {
|
||||
params: { account }
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import React, { useCallback } from 'react'
|
||||
import { SharedHashtagProp } from './sharedScreens'
|
||||
|
||||
const TabSharedHashtag: React.FC<SharedHashtagProp> = ({
|
||||
const TabSharedHashtag: React.FC<TabSharedStackScreenProps<
|
||||
'Tab-Shared-Hashtag'
|
||||
>> = ({
|
||||
route: {
|
||||
params: { hashtag }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { ParseEmojis } from '@components/Parse'
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||
import TabSharedAccount from '@screens/Tabs/Shared/Account'
|
||||
import TabSharedAttachments from '@screens/Tabs/Shared/Attachments'
|
||||
import TabSharedHashtag from '@screens/Tabs/Shared/Hashtag'
|
||||
import TabSharedSearch from '@screens/Tabs/Shared/Search'
|
||||
import TabSharedToot from '@screens/Tabs/Shared/Toot'
|
||||
import TabSharedUsers from '@screens/Tabs/Shared/Users'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { debounce } from 'lodash'
|
||||
import React from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { Platform, StyleSheet, Text, TextInput, View } from 'react-native'
|
||||
|
||||
const TabSharedRoot = ({
|
||||
Stack
|
||||
}: {
|
||||
Stack: ReturnType<typeof createNativeStackNavigator>
|
||||
}) => {
|
||||
const { mode, theme } = useTheme()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
return (
|
||||
<Stack.Group
|
||||
screenOptions={({ navigation }) => ({
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||
})}
|
||||
>
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Account'
|
||||
name='Tab-Shared-Account'
|
||||
component={TabSharedAccount}
|
||||
options={({
|
||||
navigation
|
||||
}: TabSharedStackScreenProps<'Tab-Shared-Account'>) => {
|
||||
return {
|
||||
headerTransparent: true,
|
||||
headerStyle: {
|
||||
backgroundColor: `rgba(255, 255, 255, 0)`
|
||||
},
|
||||
headerTitle: '',
|
||||
headerLeft: () => (
|
||||
<HeaderLeft onPress={() => navigation.goBack()} background />
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Attachments'
|
||||
name='Tab-Shared-Attachments'
|
||||
component={TabSharedAttachments}
|
||||
options={({
|
||||
route: {
|
||||
params: { account }
|
||||
}
|
||||
}: TabSharedStackScreenProps<'Tab-Shared-Attachments'>) => {
|
||||
return {
|
||||
headerTitle: () => (
|
||||
<Text numberOfLines={1}>
|
||||
<Trans
|
||||
i18nKey='screenTabs:shared.attachments.name'
|
||||
components={[
|
||||
<ParseEmojis
|
||||
content={account.display_name || account.username}
|
||||
emojis={account.emojis}
|
||||
fontBold
|
||||
/>,
|
||||
<Text
|
||||
style={{
|
||||
...StyleConstants.FontStyle.M,
|
||||
color: theme.primaryDefault,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold
|
||||
}}
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Hashtag'
|
||||
name='Tab-Shared-Hashtag'
|
||||
component={TabSharedHashtag}
|
||||
options={({
|
||||
route
|
||||
}: TabSharedStackScreenProps<'Tab-Shared-Hashtag'>) => ({
|
||||
headerTitle: `#${decodeURIComponent(route.params.hashtag)}`,
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter
|
||||
content={`#${decodeURIComponent(route.params.hashtag)}`}
|
||||
/>
|
||||
)
|
||||
})
|
||||
})}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Search'
|
||||
name='Tab-Shared-Search'
|
||||
component={TabSharedSearch}
|
||||
options={({
|
||||
navigation
|
||||
}: TabSharedStackScreenProps<'Tab-Shared-Search'>) => ({
|
||||
headerTitle: () => {
|
||||
const onChangeText = debounce(
|
||||
(text: string) => navigation.setParams({ text }),
|
||||
1000,
|
||||
{
|
||||
trailing: true
|
||||
}
|
||||
)
|
||||
return (
|
||||
<View style={styles.searchBar}>
|
||||
<TextInput
|
||||
editable={false}
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
color: theme.primaryDefault
|
||||
}
|
||||
]}
|
||||
defaultValue={t('shared.search.header.prefix')}
|
||||
/>
|
||||
<TextInput
|
||||
accessibilityRole='search'
|
||||
keyboardAppearance={mode}
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
flex: 1,
|
||||
color: theme.primaryDefault,
|
||||
paddingLeft: StyleConstants.Spacing.XS
|
||||
}
|
||||
]}
|
||||
autoFocus
|
||||
onChangeText={onChangeText}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
clearButtonMode='never'
|
||||
keyboardType='web-search'
|
||||
onSubmitEditing={({ nativeEvent: { text } }) =>
|
||||
navigation.setParams({ text })
|
||||
}
|
||||
placeholder={t('shared.search.header.placeholder')}
|
||||
placeholderTextColor={theme.secondary}
|
||||
returnKeyType='go'
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Toot'
|
||||
name='Tab-Shared-Toot'
|
||||
component={TabSharedToot}
|
||||
options={{
|
||||
headerTitle: t('shared.toot.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => <HeaderCenter content={t('shared.toot.name')} />
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Users'
|
||||
name='Tab-Shared-Users'
|
||||
component={TabSharedUsers}
|
||||
options={({
|
||||
route: {
|
||||
params: { reference, type, count }
|
||||
}
|
||||
}: TabSharedStackScreenProps<'Tab-Shared-Users'>) => ({
|
||||
headerTitle: t(`shared.users.${reference}.${type}`, { count }),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter
|
||||
content={t(`shared.users.${reference}.${type}`, { count })}
|
||||
/>
|
||||
)
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</Stack.Group>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
searchBar: {
|
||||
flexBasis: '80%',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
textInput: {
|
||||
fontSize: StyleConstants.Font.Size.M
|
||||
}
|
||||
})
|
||||
|
||||
export default TabSharedRoot
|
|
@ -2,6 +2,7 @@ import ComponentAccount from '@components/Account'
|
|||
import ComponentHashtag from '@components/Hashtag'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useSearchQuery } from '@utils/queryHooks/search'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
|
@ -16,9 +17,10 @@ import {
|
|||
View
|
||||
} from 'react-native'
|
||||
import { Circle } from 'react-native-animated-spinkit'
|
||||
import { SharedSearchProp } from './sharedScreens'
|
||||
|
||||
const TabSharedSearch: React.FC<SharedSearchProp> = ({
|
||||
const TabSharedSearch: React.FC<TabSharedStackScreenProps<
|
||||
'Tab-Shared-Search'
|
||||
>> = ({
|
||||
route: {
|
||||
params: { text }
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import Timeline from '@components/Timeline'
|
||||
import TimelineDefault from '@components/Timeline/Default'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { findIndex } from 'lodash'
|
||||
import React, { useCallback, useEffect, useRef } from 'react'
|
||||
import { FlatList } from 'react-native'
|
||||
import { InfiniteQueryObserver, useQueryClient } from 'react-query'
|
||||
import { SharedTootProp } from './sharedScreens'
|
||||
|
||||
const TabSharedToot: React.FC<SharedTootProp> = ({
|
||||
const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||
route: {
|
||||
params: { toot, rootQueryKey }
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import ComponentAccount from '@components/Account'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { QueryKeyUsers, useUsersQuery } from '@utils/queryHooks/users'
|
||||
import React, { useCallback } from 'react'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { FlatList } from 'react-native-gesture-handler'
|
||||
import { SharedUsersProp } from './sharedScreens'
|
||||
|
||||
const TabSharedUsers = React.memo(
|
||||
({ route: { params } }: SharedUsersProp) => {
|
||||
({ route: { params } }: TabSharedStackScreenProps<'Tab-Shared-Users'>) => {
|
||||
const queryKey: QueryKeyUsers = ['Users', params]
|
||||
const {
|
||||
data,
|
||||
|
|
|
@ -1,237 +0,0 @@
|
|||
import { HeaderCenter, HeaderLeft } from '@components/Header'
|
||||
import { ParseEmojis } from '@components/Parse'
|
||||
import { StackNavigationState, TypedNavigator } from '@react-navigation/native'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import TabSharedAccount from '@screens/Tabs/Shared/Account'
|
||||
import TabSharedAttachments from '@screens/Tabs/Shared/Attachments'
|
||||
import TabSharedHashtag from '@screens/Tabs/Shared/Hashtag'
|
||||
import TabSharedSearch from '@screens/Tabs/Shared/Search'
|
||||
import TabSharedToot from '@screens/Tabs/Shared/Toot'
|
||||
import TabSharedUsers from '@screens/Tabs/Shared/Users'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { debounce } from 'lodash'
|
||||
import React from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { Platform, StyleSheet, Text, TextInput, View } from 'react-native'
|
||||
import { NativeStackNavigationOptions } from 'react-native-screens/lib/typescript/native-stack'
|
||||
import {
|
||||
NativeStackNavigationEventMap,
|
||||
NativeStackNavigatorProps
|
||||
} from 'react-native-screens/lib/typescript/native-stack/types'
|
||||
|
||||
export type BaseScreens =
|
||||
| Nav.TabLocalStackParamList
|
||||
| Nav.TabPublicStackParamList
|
||||
| Nav.TabNotificationsStackParamList
|
||||
| Nav.TabMeStackParamList
|
||||
|
||||
export type SharedAccountProp = StackScreenProps<
|
||||
BaseScreens,
|
||||
'Tab-Shared-Account'
|
||||
>
|
||||
|
||||
export type SharedAttachmentsProp = StackScreenProps<
|
||||
BaseScreens,
|
||||
'Tab-Shared-Attachments'
|
||||
>
|
||||
|
||||
export type SharedHashtagProp = StackScreenProps<
|
||||
BaseScreens,
|
||||
'Tab-Shared-Hashtag'
|
||||
>
|
||||
|
||||
export type SharedSearchProp = StackScreenProps<
|
||||
BaseScreens,
|
||||
'Tab-Shared-Search'
|
||||
>
|
||||
|
||||
export type SharedTootProp = StackScreenProps<BaseScreens, 'Tab-Shared-Toot'>
|
||||
|
||||
export type SharedUsersProp = StackScreenProps<BaseScreens, 'Tab-Shared-Users'>
|
||||
|
||||
const sharedScreens = (
|
||||
Stack: TypedNavigator<
|
||||
BaseScreens,
|
||||
StackNavigationState<Record<string, object | undefined>>,
|
||||
NativeStackNavigationOptions,
|
||||
NativeStackNavigationEventMap,
|
||||
({ ...rest }: NativeStackNavigatorProps) => JSX.Element
|
||||
>
|
||||
) => {
|
||||
const { mode, theme } = useTheme()
|
||||
const { t } = useTranslation('screenTabs')
|
||||
|
||||
return [
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Account'
|
||||
name='Tab-Shared-Account'
|
||||
component={TabSharedAccount}
|
||||
options={({ navigation }: SharedAccountProp) => {
|
||||
return {
|
||||
headerTranslucent: true,
|
||||
headerStyle: {
|
||||
backgroundColor: `rgba(255, 255, 255, 0)`
|
||||
},
|
||||
headerCenter: () => null,
|
||||
headerLeft: () => (
|
||||
<HeaderLeft onPress={() => navigation.goBack()} background />
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Attachments'
|
||||
name='Tab-Shared-Attachments'
|
||||
component={TabSharedAttachments}
|
||||
options={({
|
||||
route: {
|
||||
params: { account }
|
||||
},
|
||||
navigation
|
||||
}: SharedAttachmentsProp) => {
|
||||
return {
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />,
|
||||
headerCenter: () => (
|
||||
<Text numberOfLines={1}>
|
||||
<Trans
|
||||
i18nKey='screenTabs:shared.attachments.name'
|
||||
components={[
|
||||
<ParseEmojis
|
||||
content={account.display_name || account.username}
|
||||
emojis={account.emojis}
|
||||
fontBold
|
||||
/>,
|
||||
<Text
|
||||
style={{
|
||||
...StyleConstants.FontStyle.M,
|
||||
color: theme.primaryDefault,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold
|
||||
}}
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Hashtag'
|
||||
name='Tab-Shared-Hashtag'
|
||||
component={TabSharedHashtag}
|
||||
options={({ route, navigation }: SharedHashtagProp) => ({
|
||||
headerTitle: `#${decodeURIComponent(route.params.hashtag)}`,
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter
|
||||
content={`#${decodeURIComponent(route.params.hashtag)}`}
|
||||
/>
|
||||
)
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||
})}
|
||||
/>,
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Search'
|
||||
name='Tab-Shared-Search'
|
||||
component={TabSharedSearch}
|
||||
options={({ navigation }: SharedSearchProp) => ({
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />,
|
||||
headerCenter: () => {
|
||||
const onChangeText = debounce(
|
||||
(text: string) => navigation.setParams({ text }),
|
||||
1000,
|
||||
{
|
||||
trailing: true
|
||||
}
|
||||
)
|
||||
return (
|
||||
<View style={styles.searchBar}>
|
||||
<TextInput
|
||||
editable={false}
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
color: theme.primaryDefault
|
||||
}
|
||||
]}
|
||||
defaultValue={t('shared.search.header.prefix')}
|
||||
/>
|
||||
<TextInput
|
||||
accessibilityRole='search'
|
||||
keyboardAppearance={mode}
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
flex: 1,
|
||||
color: theme.primaryDefault,
|
||||
paddingLeft: StyleConstants.Spacing.XS
|
||||
}
|
||||
]}
|
||||
autoFocus
|
||||
onChangeText={onChangeText}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
clearButtonMode='never'
|
||||
keyboardType='web-search'
|
||||
onSubmitEditing={({ nativeEvent: { text } }) =>
|
||||
navigation.setParams({ text })
|
||||
}
|
||||
placeholder={t('shared.search.header.placeholder')}
|
||||
placeholderTextColor={theme.secondary}
|
||||
returnKeyType='go'
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
})}
|
||||
/>,
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Toot'
|
||||
name='Tab-Shared-Toot'
|
||||
component={TabSharedToot}
|
||||
options={({ navigation }: SharedTootProp) => ({
|
||||
headerTitle: t('shared.toot.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => <HeaderCenter content={t('shared.toot.name')} />
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||
})}
|
||||
/>,
|
||||
<Stack.Screen
|
||||
key='Tab-Shared-Users'
|
||||
name='Tab-Shared-Users'
|
||||
component={TabSharedUsers}
|
||||
options={({
|
||||
navigation,
|
||||
route: {
|
||||
params: { reference, type, count }
|
||||
}
|
||||
}: SharedUsersProp) => ({
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />,
|
||||
headerTitle: t(`shared.users.${reference}.${type}`, { count }),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter
|
||||
content={t(`shared.users.${reference}.${type}`, { count })}
|
||||
/>
|
||||
)
|
||||
})
|
||||
})}
|
||||
/>
|
||||
]
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
searchBar: {
|
||||
flexBasis: '80%',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
textInput: {
|
||||
fontSize: StyleConstants.Font.Size.M
|
||||
}
|
||||
})
|
||||
|
||||
export default sharedScreens
|
|
@ -5,9 +5,8 @@ const audio = () => {
|
|||
log('log', 'audio', 'setting audio playback default options')
|
||||
Audio.setAudioModeAsync({
|
||||
playsInSilentModeIOS: true,
|
||||
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
|
||||
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
|
||||
shouldDuckAndroid: true
|
||||
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DUCK_OTHERS,
|
||||
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS
|
||||
})
|
||||
}
|
||||
|
||||
|
|
34
src/store.ts
34
src/store.ts
|
@ -1,10 +1,10 @@
|
|||
import createSecureStore from '@neverdull-agency/expo-unlimited-secure-store'
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
|
||||
import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
|
||||
import instancesMigration from '@utils/migrations/instances/migration'
|
||||
import contextsSlice from '@utils/slices/contextsSlice'
|
||||
import instancesSlice from '@utils/slices/instancesSlice'
|
||||
import settingsSlice from '@utils/slices/settingsSlice'
|
||||
import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice'
|
||||
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
|
||||
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
|
||||
import versionSlice from '@utils/slices/versionSlice'
|
||||
import { createMigrate, persistReducer, persistStore } from 'redux-persist'
|
||||
|
||||
|
@ -35,16 +35,26 @@ const settingsPersistConfig = {
|
|||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
contexts: persistReducer(contextsPersistConfig, contextsSlice),
|
||||
instances: persistReducer(instancesPersistConfig, instancesSlice),
|
||||
settings: persistReducer(settingsPersistConfig, settingsSlice),
|
||||
contexts: persistReducer(contextsPersistConfig, contextsSlice) as Reducer<
|
||||
ContextsState,
|
||||
AnyAction
|
||||
>,
|
||||
instances: persistReducer(
|
||||
instancesPersistConfig,
|
||||
instancesSlice
|
||||
) as Reducer<InstancesState, AnyAction>,
|
||||
settings: persistReducer(settingsPersistConfig, settingsSlice) as Reducer<
|
||||
SettingsState,
|
||||
AnyAction
|
||||
>,
|
||||
version: versionSlice
|
||||
},
|
||||
middleware: getDefaultMiddleware({
|
||||
serializableCheck: {
|
||||
ignoredActions: ['persist/PERSIST']
|
||||
}
|
||||
})
|
||||
middleware: getDefaultMiddleware =>
|
||||
getDefaultMiddleware({
|
||||
serializableCheck: {
|
||||
ignoredActions: ['persist/PERSIST']
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let persistor = persistStore(store)
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
|
||||
import { NavigatorScreenParams } from '@react-navigation/native'
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
|
||||
export type RootStackParamList = {
|
||||
'Screen-Tabs': NavigatorScreenParams<ScreenTabsStackParamList>
|
||||
'Screen-Actions':
|
||||
| {
|
||||
type: 'status'
|
||||
queryKey: QueryKeyTimeline
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
}
|
||||
| {
|
||||
type: 'account'
|
||||
account: Mastodon.Account
|
||||
}
|
||||
| {
|
||||
type: 'notifications_filter'
|
||||
}
|
||||
'Screen-Announcements': { showAll: boolean }
|
||||
'Screen-Compose':
|
||||
| {
|
||||
type: 'edit'
|
||||
incomingStatus: Mastodon.Status
|
||||
replyToStatus?: Mastodon.Status
|
||||
queryKey?: [
|
||||
'Timeline',
|
||||
{
|
||||
page: App.Pages
|
||||
hashtag?: Mastodon.Tag['name']
|
||||
list?: Mastodon.List['id']
|
||||
toot?: Mastodon.Status['id']
|
||||
account?: Mastodon.Account['id']
|
||||
}
|
||||
]
|
||||
}
|
||||
| {
|
||||
type: 'reply'
|
||||
incomingStatus: Mastodon.Status
|
||||
accts: Mastodon.Account['acct'][]
|
||||
queryKey?: [
|
||||
'Timeline',
|
||||
{
|
||||
page: App.Pages
|
||||
hashtag?: Mastodon.Tag['name']
|
||||
list?: Mastodon.List['id']
|
||||
toot?: Mastodon.Status['id']
|
||||
account?: Mastodon.Account['id']
|
||||
}
|
||||
]
|
||||
}
|
||||
| {
|
||||
type: 'conversation'
|
||||
accts: Mastodon.Account['acct'][]
|
||||
}
|
||||
| undefined
|
||||
'Screen-ImagesViewer': {
|
||||
imageUrls: {
|
||||
id: Mastodon.Attachment['id']
|
||||
preview_url: Mastodon.AttachmentImage['preview_url']
|
||||
url: Mastodon.AttachmentImage['url']
|
||||
remote_url?: Mastodon.AttachmentImage['remote_url']
|
||||
blurhash: Mastodon.AttachmentImage['blurhash']
|
||||
width?: number
|
||||
height?: number
|
||||
}[]
|
||||
id: Mastodon.Attachment['id']
|
||||
}
|
||||
}
|
||||
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 ScreenTabsStackParamList = {
|
||||
'Tab-Local': NavigatorScreenParams<TabLocalStackParamList>
|
||||
'Tab-Public': NavigatorScreenParams<TabPublicStackParamList>
|
||||
'Tab-Compose': undefined
|
||||
'Tab-Notifications': NavigatorScreenParams<TabNotificationsStackParamList>
|
||||
'Tab-Me': NavigatorScreenParams<TabMeStackParamList>
|
||||
}
|
||||
export type ScreenTabsScreenProps<
|
||||
T extends keyof ScreenTabsStackParamList
|
||||
> = BottomTabScreenProps<ScreenTabsStackParamList, T>
|
||||
|
||||
export type TabSharedStackParamList = {
|
||||
'Tab-Shared-Account': {
|
||||
account: Mastodon.Account | Mastodon.Mention
|
||||
}
|
||||
'Tab-Shared-Attachments': { account: Mastodon.Account }
|
||||
'Tab-Shared-Hashtag': {
|
||||
hashtag: Mastodon.Tag['name']
|
||||
}
|
||||
'Tab-Shared-Search': { text: string | undefined }
|
||||
'Tab-Shared-Toot': {
|
||||
toot: Mastodon.Status
|
||||
rootQueryKey?: QueryKeyTimeline
|
||||
}
|
||||
'Tab-Shared-Users':
|
||||
| {
|
||||
reference: 'accounts'
|
||||
id: Mastodon.Account['id']
|
||||
type: 'following' | 'followers'
|
||||
count: number
|
||||
}
|
||||
| {
|
||||
reference: 'statuses'
|
||||
id: Mastodon.Status['id']
|
||||
type: 'reblogged_by' | 'favourited_by'
|
||||
count: number
|
||||
}
|
||||
}
|
||||
export type TabSharedStackScreenProps<
|
||||
T extends keyof TabSharedStackParamList
|
||||
> = NativeStackScreenProps<TabSharedStackParamList, T>
|
||||
|
||||
export type TabLocalStackParamList = {
|
||||
'Tab-Local-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
export type TabPublicStackParamList = {
|
||||
'Tab-Public-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
export type TabNotificationsStackParamList = {
|
||||
'Tab-Notifications-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
export type TabMeStackParamList = {
|
||||
'Tab-Me-Root': undefined
|
||||
'Tab-Me-Bookmarks': undefined
|
||||
'Tab-Me-Conversations': undefined
|
||||
'Tab-Me-Favourites': undefined
|
||||
'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
|
||||
'Tab-Me-Settings-Fontsize': 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 TabMeProfileStackParamList = {
|
||||
'Tab-Me-Profile-Root': undefined
|
||||
'Tab-Me-Profile-Name': {
|
||||
display_name: Mastodon.Account['display_name']
|
||||
}
|
||||
'Tab-Me-Profile-Note': {
|
||||
note: Mastodon.Source['note']
|
||||
}
|
||||
'Tab-Me-Profile-Fields': {
|
||||
fields?: Mastodon.Source['fields']
|
||||
}
|
||||
}
|
||||
export type TabMeProfileStackScreenProps<
|
||||
T extends keyof TabMeProfileStackParamList
|
||||
> = NativeStackScreenProps<TabMeProfileStackParamList, T>
|
|
@ -1,7 +1,7 @@
|
|||
import apiGeneral from '@api/general'
|
||||
import apiTooot from '@api/tooot'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import { NavigationContainerRef } from '@react-navigation/native'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
import { Dispatch } from '@reduxjs/toolkit'
|
||||
import { disableAllPushes, Instance } from '@utils/slices/instancesSlice'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
|
@ -9,20 +9,13 @@ import { useEffect } from 'react'
|
|||
import { TFunction } from 'react-i18next'
|
||||
|
||||
export interface Params {
|
||||
navigationRef: React.RefObject<NavigationContainerRef>
|
||||
mode: 'light' | 'dark'
|
||||
t: TFunction<'screens'>
|
||||
instances: Instance[]
|
||||
dispatch: Dispatch<any>
|
||||
}
|
||||
|
||||
const pushUseConnect = ({
|
||||
navigationRef,
|
||||
mode,
|
||||
t,
|
||||
instances,
|
||||
dispatch
|
||||
}: Params) => {
|
||||
const pushUseConnect = ({ mode, t, instances, dispatch }: Params) => {
|
||||
return useEffect(() => {
|
||||
const connect = async () => {
|
||||
const expoToken = (
|
||||
|
@ -48,13 +41,13 @@ const pushUseConnect = ({
|
|||
message: t('pushError.message'),
|
||||
description: t('pushError.description'),
|
||||
onPress: () => {
|
||||
navigationRef.current?.navigate('Screen-Tabs', {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me',
|
||||
params: {
|
||||
screen: 'Tab-Me-Root'
|
||||
}
|
||||
})
|
||||
navigationRef.current?.navigate('Screen-Tabs', {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Me',
|
||||
params: {
|
||||
screen: 'Tab-Me-Settings'
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import apiInstance from '@api/instance'
|
||||
import { NavigationContainerRef } from '@react-navigation/native'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
|
||||
const pushUseNavigate = (
|
||||
navigationRef: React.RefObject<NavigationContainerRef>,
|
||||
id?: Mastodon.Notification['id']
|
||||
) => {
|
||||
navigationRef.current?.navigate('Screen-Tabs', {
|
||||
const pushUseNavigate = (id?: Mastodon.Notification['id']) => {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Notifications',
|
||||
params: {
|
||||
screen: 'Tab-Notifications-Root'
|
||||
|
@ -21,7 +18,7 @@ const pushUseNavigate = (
|
|||
url: `notifications/${id}`
|
||||
}).then(({ body }) => {
|
||||
if (body.status) {
|
||||
navigationRef.current?.navigate('Screen-Tabs', {
|
||||
navigationRef.navigate('Screen-Tabs', {
|
||||
screen: 'Tab-Notifications',
|
||||
params: {
|
||||
screen: 'Tab-Shared-Toot',
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { displayMessage } from '@components/Message'
|
||||
import { NavigationContainerRef } from '@react-navigation/native'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { Instance, updateInstanceActive } from '@utils/slices/instancesSlice'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
|
@ -10,12 +9,11 @@ import { useDispatch } from 'react-redux'
|
|||
import pushUseNavigate from './useNavigate'
|
||||
|
||||
export interface Params {
|
||||
navigationRef: React.RefObject<NavigationContainerRef>
|
||||
queryClient: QueryClient
|
||||
instances: Instance[]
|
||||
}
|
||||
|
||||
const pushUseReceive = ({ navigationRef, queryClient, instances }: Params) => {
|
||||
const pushUseReceive = ({ queryClient, instances }: Params) => {
|
||||
const dispatch = useDispatch()
|
||||
|
||||
return useEffect(() => {
|
||||
|
@ -46,7 +44,7 @@ const pushUseReceive = ({ navigationRef, queryClient, instances }: Params) => {
|
|||
if (notificationIndex !== -1) {
|
||||
dispatch(updateInstanceActive(instances[notificationIndex]))
|
||||
}
|
||||
pushUseNavigate(navigationRef, payloadData.notification_id)
|
||||
pushUseNavigate(payloadData.notification_id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { NavigationContainerRef } from '@react-navigation/native'
|
||||
import { Dispatch } from '@reduxjs/toolkit'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { Instance, updateInstanceActive } from '@utils/slices/instancesSlice'
|
||||
|
@ -9,18 +8,12 @@ import { QueryClient } from 'react-query'
|
|||
import pushUseNavigate from './useNavigate'
|
||||
|
||||
export interface Params {
|
||||
navigationRef: React.RefObject<NavigationContainerRef>
|
||||
queryClient: QueryClient
|
||||
instances: Instance[]
|
||||
dispatch: Dispatch<any>
|
||||
}
|
||||
|
||||
const pushUseRespond = ({
|
||||
navigationRef,
|
||||
queryClient,
|
||||
instances,
|
||||
dispatch
|
||||
}: Params) => {
|
||||
const pushUseRespond = ({ queryClient, instances, dispatch }: Params) => {
|
||||
return useEffect(() => {
|
||||
const subscription = Notifications.addNotificationResponseReceivedListener(
|
||||
({ notification }) => {
|
||||
|
@ -44,7 +37,7 @@ const pushUseRespond = ({
|
|||
if (notificationIndex !== -1) {
|
||||
dispatch(updateInstanceActive(instances[notificationIndex]))
|
||||
}
|
||||
pushUseNavigate(navigationRef, payloadData.notification_id)
|
||||
pushUseNavigate(payloadData.notification_id)
|
||||
}
|
||||
)
|
||||
return () => subscription.remove()
|
||||
|
|
|
@ -87,7 +87,9 @@ const queryFunction = async ({
|
|||
}
|
||||
})
|
||||
} else {
|
||||
const res1 = await apiInstance<(Mastodon.Status & { _pinned: boolean} )[]>({
|
||||
const res1 = await apiInstance<
|
||||
(Mastodon.Status & { _pinned: boolean })[]
|
||||
>({
|
||||
method: 'get',
|
||||
url: `accounts/${account}/statuses`,
|
||||
params: {
|
||||
|
@ -105,7 +107,7 @@ const queryFunction = async ({
|
|||
exclude_replies: 'true'
|
||||
}
|
||||
})
|
||||
return await {
|
||||
return {
|
||||
body: uniqBy([...res1.body, ...res2.body], 'id'),
|
||||
...(res2.links.next && { links: { next: res2.links.next } })
|
||||
}
|
||||
|
@ -175,8 +177,12 @@ const queryFunction = async ({
|
|||
method: 'get',
|
||||
url: `statuses/${toot}/context`
|
||||
})
|
||||
return await {
|
||||
body: [...res2_1.body.ancestors, res1_1.body, ...res2_1.body.descendants]
|
||||
return {
|
||||
body: [
|
||||
...res2_1.body.ancestors,
|
||||
res1_1.body,
|
||||
...res2_1.body.descendants
|
||||
]
|
||||
}
|
||||
default:
|
||||
return Promise.reject()
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import apiTooot from '@api/tooot'
|
||||
import haptics from '@components/haptics'
|
||||
import { AxiosError } from 'axios'
|
||||
import { Buffer } from 'buffer'
|
||||
import Constants from 'expo-constants'
|
||||
import * as Crypto from 'expo-crypto'
|
||||
import { useQuery, UseQueryOptions } from 'react-query'
|
||||
|
||||
type Translations = {
|
||||
|
@ -24,13 +23,15 @@ export type QueryKeyTranslate = [
|
|||
const queryFunction = async ({ queryKey }: { queryKey: QueryKeyTranslate }) => {
|
||||
const { uri, source, target, text } = queryKey[1]
|
||||
|
||||
const uriEncoded = Buffer.from(uri.replace(/https?:\/\//, ''))
|
||||
.toString('base64')
|
||||
.replace('+', '-')
|
||||
.replace('/', '_')
|
||||
.replace(/=+$/, '')
|
||||
const original = Buffer.from(JSON.stringify({ source, text })).toString(
|
||||
'base64'
|
||||
const uriEncoded = await Crypto.digestStringAsync(
|
||||
Crypto.CryptoDigestAlgorithm.SHA256,
|
||||
uri.replace(/https?:\/\//, ''),
|
||||
{ encoding: Crypto.CryptoEncoding.HEX }
|
||||
)
|
||||
const original = await Crypto.digestStringAsync(
|
||||
Crypto.CryptoDigestAlgorithm.SHA256,
|
||||
JSON.stringify({ source, text }),
|
||||
{ encoding: Crypto.CryptoEncoding.HEX }
|
||||
)
|
||||
|
||||
const res = await apiTooot<Translations>({
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import apiInstance from '@api/instance'
|
||||
import { TabSharedStackParamList } from '@utils/navigation/navigators'
|
||||
import { AxiosError } from 'axios'
|
||||
import { useInfiniteQuery, UseInfiniteQueryOptions } from 'react-query'
|
||||
|
||||
export type QueryKeyUsers = [
|
||||
'Users',
|
||||
Nav.TabSharedStackParamList['Tab-Shared-Users']
|
||||
TabSharedStackParamList['Tab-Shared-Users']
|
||||
]
|
||||
|
||||
const queryFunction = ({
|
||||
|
|
|
@ -54,6 +54,13 @@ const addInstance = createAsyncThunk(
|
|||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
|
||||
const { body: filters } = await apiGeneral<Mastodon.Filter[]>({
|
||||
method: 'get',
|
||||
domain,
|
||||
url: `api/v1/filters`,
|
||||
headers: { Authorization: `Bearer ${token}` }
|
||||
})
|
||||
|
||||
return Promise.resolve({
|
||||
type,
|
||||
data: {
|
||||
|
@ -70,6 +77,7 @@ const addInstance = createAsyncThunk(
|
|||
avatarStatic: avatar_static,
|
||||
preferences
|
||||
},
|
||||
filters,
|
||||
notifications_filter: {
|
||||
follow: true,
|
||||
favourite: true,
|
||||
|
|
|
@ -12,7 +12,7 @@ export const updateInstancePushDecode = createAsyncThunk(
|
|||
async (
|
||||
disable: boolean,
|
||||
{ getState }
|
||||
): Promise<Instance['push']['decode']['value']> => {
|
||||
): Promise<{ disable: Instance['push']['decode']['value'] }> => {
|
||||
const state = getState() as RootState
|
||||
const instance = getInstance(state)
|
||||
if (!instance?.url || !instance.account.id || !instance.push.keys) {
|
||||
|
@ -89,6 +89,6 @@ export const updateInstancePushDecode = createAsyncThunk(
|
|||
}
|
||||
}
|
||||
|
||||
return Promise.resolve(disable)
|
||||
return Promise.resolve({ disable })
|
||||
}
|
||||
)
|
||||
|
|
|
@ -274,7 +274,7 @@ const instancesSlice = createSlice({
|
|||
.addCase(updateInstancePushDecode.fulfilled, (state, action) => {
|
||||
const activeIndex = findInstanceActive(state.instances)
|
||||
state.instances[activeIndex].push.decode.loading = false
|
||||
state.instances[activeIndex].push.decode.value = action.payload
|
||||
state.instances[activeIndex].push.decode.value = action.payload.disable
|
||||
})
|
||||
.addCase(updateInstancePushDecode.rejected, state => {
|
||||
const activeIndex = findInstanceActive(state.instances)
|
||||
|
|
|
@ -13,7 +13,7 @@ export const changeAnalytics = createAsyncThunk(
|
|||
'settings/changeAnalytics',
|
||||
async (newValue: SettingsState['analytics']) => {
|
||||
await Analytics.setAnalyticsCollectionEnabled(newValue)
|
||||
return newValue
|
||||
return { newValue }
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -75,7 +75,7 @@ const settingsSlice = createSlice({
|
|||
},
|
||||
extraReducers: builder => {
|
||||
builder.addCase(changeAnalytics.fulfilled, (state, action) => {
|
||||
state.analytics = action.payload
|
||||
state.analytics = action.payload.newValue
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -29,7 +29,7 @@ const versionSlice = createSlice({
|
|||
reducers: {},
|
||||
extraReducers: builder => {
|
||||
builder.addCase(retriveVersionLatest.fulfilled, (state, action) => {
|
||||
if (action.payload && Constants.manifest.version) {
|
||||
if (action.payload && Constants.manifest?.version) {
|
||||
if (parseInt(action.payload) > parseInt(Constants.manifest.version)) {
|
||||
state.update = true
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue