mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -100,6 +100,7 @@ jobs:
|
|||||||
uses: expo/expo-github-action@v7
|
uses: expo/expo-github-action@v7
|
||||||
with:
|
with:
|
||||||
expo-version: latest
|
expo-version: latest
|
||||||
|
eas-version: latest
|
||||||
token: ${{ secrets.EXPO_TOKEN }}
|
token: ${{ secrets.EXPO_TOKEN }}
|
||||||
- name: -- Step 5 -- Install node dependencies
|
- name: -- Step 5 -- Install node dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
@ -120,3 +121,6 @@ jobs:
|
|||||||
GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }}
|
GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }}
|
||||||
FL_GITHUB_RELEASE_API_BEARER: ${{ secrets.GITHUB_TOKEN }}
|
FL_GITHUB_RELEASE_API_BEARER: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: yarn app:build release
|
run: yarn app:build release
|
||||||
|
- name: -- Step 8 -- Publish expo update
|
||||||
|
run: eas update --auto
|
||||||
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,6 +31,7 @@ DerivedData
|
|||||||
*.ipa
|
*.ipa
|
||||||
*.xcuserstate
|
*.xcuserstate
|
||||||
project.xcworkspace
|
project.xcworkspace
|
||||||
|
ios/.xcode.env.local
|
||||||
|
|
||||||
# Android/IntelliJ
|
# Android/IntelliJ
|
||||||
#
|
#
|
||||||
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"javascript.inlayHints.functionLikeReturnTypes.enabled": false
|
||||||
|
}
|
50
Gemfile.lock
50
Gemfile.lock
@ -17,20 +17,20 @@ GEM
|
|||||||
artifactory (3.0.15)
|
artifactory (3.0.15)
|
||||||
atomos (0.1.3)
|
atomos (0.1.3)
|
||||||
aws-eventstream (1.2.0)
|
aws-eventstream (1.2.0)
|
||||||
aws-partitions (1.598.0)
|
aws-partitions (1.618.0)
|
||||||
aws-sdk-core (3.131.1)
|
aws-sdk-core (3.132.0)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
aws-partitions (~> 1, >= 1.525.0)
|
aws-partitions (~> 1, >= 1.525.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
aws-sdk-kms (1.57.0)
|
aws-sdk-kms (1.58.0)
|
||||||
aws-sdk-core (~> 3, >= 3.127.0)
|
aws-sdk-core (~> 3, >= 3.127.0)
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sdk-s3 (1.114.0)
|
aws-sdk-s3 (1.114.0)
|
||||||
aws-sdk-core (~> 3, >= 3.127.0)
|
aws-sdk-core (~> 3, >= 3.127.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.4)
|
aws-sigv4 (~> 1.4)
|
||||||
aws-sigv4 (1.5.0)
|
aws-sigv4 (1.5.1)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
babosa (1.0.4)
|
babosa (1.0.4)
|
||||||
claide (1.1.0)
|
claide (1.1.0)
|
||||||
@ -81,13 +81,13 @@ GEM
|
|||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
dotenv (2.7.6)
|
dotenv (2.8.1)
|
||||||
emoji_regex (3.2.3)
|
emoji_regex (3.2.3)
|
||||||
escape (0.0.4)
|
escape (0.0.4)
|
||||||
ethon (0.15.0)
|
ethon (0.15.0)
|
||||||
ffi (>= 1.15.0)
|
ffi (>= 1.15.0)
|
||||||
excon (0.92.3)
|
excon (0.92.4)
|
||||||
faraday (1.10.0)
|
faraday (1.10.1)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
faraday-em_synchrony (~> 1.0)
|
faraday-em_synchrony (~> 1.0)
|
||||||
faraday-excon (~> 1.1)
|
faraday-excon (~> 1.1)
|
||||||
@ -116,7 +116,7 @@ GEM
|
|||||||
faraday_middleware (1.2.0)
|
faraday_middleware (1.2.0)
|
||||||
faraday (~> 1.0)
|
faraday (~> 1.0)
|
||||||
fastimage (2.2.6)
|
fastimage (2.2.6)
|
||||||
fastlane (2.206.2)
|
fastlane (2.209.0)
|
||||||
CFPropertyList (>= 2.3, < 4.0.0)
|
CFPropertyList (>= 2.3, < 4.0.0)
|
||||||
addressable (>= 2.8, < 3.0.0)
|
addressable (>= 2.8, < 3.0.0)
|
||||||
artifactory (~> 3.0)
|
artifactory (~> 3.0)
|
||||||
@ -156,16 +156,16 @@ GEM
|
|||||||
xcpretty (~> 0.3.0)
|
xcpretty (~> 0.3.0)
|
||||||
xcpretty-travis-formatter (>= 0.0.3)
|
xcpretty-travis-formatter (>= 0.0.3)
|
||||||
fastlane-plugin-json (1.1.0)
|
fastlane-plugin-json (1.1.0)
|
||||||
fastlane-plugin-sentry (1.12.0)
|
fastlane-plugin-sentry (1.12.2)
|
||||||
fastlane-plugin-versioning_android (0.1.0)
|
fastlane-plugin-versioning_android (0.1.0)
|
||||||
fastlane-plugin-yarn (1.2)
|
fastlane-plugin-yarn (1.2)
|
||||||
ffi (1.15.5)
|
ffi (1.15.5)
|
||||||
fourflusher (2.3.1)
|
fourflusher (2.3.1)
|
||||||
fuzzy_match (2.0.4)
|
fuzzy_match (2.0.4)
|
||||||
gh_inspector (1.1.3)
|
gh_inspector (1.1.3)
|
||||||
google-apis-androidpublisher_v3 (0.21.0)
|
google-apis-androidpublisher_v3 (0.25.0)
|
||||||
google-apis-core (>= 0.4, < 2.a)
|
google-apis-core (>= 0.7, < 2.a)
|
||||||
google-apis-core (0.5.0)
|
google-apis-core (0.7.0)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
googleauth (>= 0.16.2, < 2.a)
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
httpclient (>= 2.8.1, < 3.a)
|
httpclient (>= 2.8.1, < 3.a)
|
||||||
@ -174,27 +174,27 @@ GEM
|
|||||||
retriable (>= 2.0, < 4.a)
|
retriable (>= 2.0, < 4.a)
|
||||||
rexml
|
rexml
|
||||||
webrick
|
webrick
|
||||||
google-apis-iamcredentials_v1 (0.10.0)
|
google-apis-iamcredentials_v1 (0.13.0)
|
||||||
google-apis-core (>= 0.4, < 2.a)
|
google-apis-core (>= 0.7, < 2.a)
|
||||||
google-apis-playcustomapp_v1 (0.7.0)
|
google-apis-playcustomapp_v1 (0.10.0)
|
||||||
google-apis-core (>= 0.4, < 2.a)
|
google-apis-core (>= 0.7, < 2.a)
|
||||||
google-apis-storage_v1 (0.14.0)
|
google-apis-storage_v1 (0.17.0)
|
||||||
google-apis-core (>= 0.4, < 2.a)
|
google-apis-core (>= 0.7, < 2.a)
|
||||||
google-cloud-core (1.6.0)
|
google-cloud-core (1.6.0)
|
||||||
google-cloud-env (~> 1.0)
|
google-cloud-env (~> 1.0)
|
||||||
google-cloud-errors (~> 1.0)
|
google-cloud-errors (~> 1.0)
|
||||||
google-cloud-env (1.6.0)
|
google-cloud-env (1.6.0)
|
||||||
faraday (>= 0.17.3, < 3.0)
|
faraday (>= 0.17.3, < 3.0)
|
||||||
google-cloud-errors (1.2.0)
|
google-cloud-errors (1.2.0)
|
||||||
google-cloud-storage (1.36.2)
|
google-cloud-storage (1.38.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
digest-crc (~> 0.4)
|
digest-crc (~> 0.4)
|
||||||
google-apis-iamcredentials_v1 (~> 0.1)
|
google-apis-iamcredentials_v1 (~> 0.1)
|
||||||
google-apis-storage_v1 (~> 0.1)
|
google-apis-storage_v1 (~> 0.17.0)
|
||||||
google-cloud-core (~> 1.6)
|
google-cloud-core (~> 1.6)
|
||||||
googleauth (>= 0.16.2, < 2.a)
|
googleauth (>= 0.16.2, < 2.a)
|
||||||
mini_mime (~> 1.0)
|
mini_mime (~> 1.0)
|
||||||
googleauth (1.1.3)
|
googleauth (1.2.0)
|
||||||
faraday (>= 0.17.3, < 3.a)
|
faraday (>= 0.17.3, < 3.a)
|
||||||
jwt (>= 1.4, < 3.0)
|
jwt (>= 1.4, < 3.0)
|
||||||
memoist (~> 0.16)
|
memoist (~> 0.16)
|
||||||
@ -237,9 +237,9 @@ GEM
|
|||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
security (0.1.3)
|
security (0.1.3)
|
||||||
signet (0.16.1)
|
signet (0.17.0)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
faraday (>= 0.17.5, < 3.0)
|
faraday (>= 0.17.5, < 3.a)
|
||||||
jwt (>= 1.5, < 3.0)
|
jwt (>= 1.5, < 3.0)
|
||||||
multi_json (~> 1.10)
|
multi_json (~> 1.10)
|
||||||
simctl (1.6.8)
|
simctl (1.6.8)
|
||||||
@ -264,7 +264,7 @@ GEM
|
|||||||
unicode-display_width (1.8.0)
|
unicode-display_width (1.8.0)
|
||||||
webrick (1.7.0)
|
webrick (1.7.0)
|
||||||
word_wrap (1.0.0)
|
word_wrap (1.0.0)
|
||||||
xcodeproj (1.21.0)
|
xcodeproj (1.22.0)
|
||||||
CFPropertyList (>= 2.3.3, < 4.0)
|
CFPropertyList (>= 2.3.3, < 4.0)
|
||||||
atomos (~> 0.1.3)
|
atomos (~> 0.1.3)
|
||||||
claide (>= 1.0.2, < 2.0)
|
claide (>= 1.0.2, < 2.0)
|
||||||
@ -290,4 +290,4 @@ DEPENDENCIES
|
|||||||
fastlane-plugin-yarn
|
fastlane-plugin-yarn
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.2.17
|
2.3.20
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
apply plugin: "com.android.application"
|
apply plugin: "com.android.application"
|
||||||
|
|
||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
import org.apache.tools.ant.taskdefs.condition.Os
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||||
@ -157,16 +156,12 @@ android {
|
|||||||
"PROJECT_BUILD_DIR=$buildDir",
|
"PROJECT_BUILD_DIR=$buildDir",
|
||||||
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
|
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
|
||||||
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
|
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
|
||||||
|
"NODE_MODULES_DIR=$rootDir/../node_modules"
|
||||||
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
|
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
|
||||||
cppFlags "-std=c++17"
|
cppFlags "-std=c++17"
|
||||||
// Make sure this target name is the same you specify inside the
|
// Make sure this target name is the same you specify inside the
|
||||||
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
|
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
|
||||||
targets "tooot_appmodules"
|
targets "tooot_appmodules"
|
||||||
// Fix for windows limit on number of character in file paths and in command lines
|
|
||||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
|
||||||
arguments "NDK_OUT=${rootProject.projectDir.getParent()}\\.cxx",
|
|
||||||
"NDK_APP_SHORT_COMMANDS=true"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!enableSeparateBuildPerCPUArchitecture) {
|
if (!enableSeparateBuildPerCPUArchitecture) {
|
||||||
@ -176,7 +171,7 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
expoSDK: project.hasProperty('expoSDK') ? project.property('expoSDK') : "",
|
runtimeVersion: project.hasProperty('runtimeVersion') ? project.property('runtimeVersion') : "",
|
||||||
releaseChannel: project.hasProperty('releaseChannel') ? project.property('releaseChannel') : "default"
|
releaseChannel: project.hasProperty('releaseChannel') ? project.property('releaseChannel') : "default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -311,8 +306,10 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enableHermes) {
|
if (enableHermes) {
|
||||||
debugImplementation files(new File(["node", "--print", "require.resolve('hermes-engine/package.json')"].execute().text.trim(), "../android/hermes-debug.aar"))
|
//noinspection GradleDynamicVersion
|
||||||
releaseImplementation files(new File(["node", "--print", "require.resolve('hermes-engine/package.json')"].execute().text.trim(), "../android/hermes-release.aar"))
|
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
|
||||||
|
exclude group:'com.facebook.fbjni'
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
implementation jscFlavor
|
implementation jscFlavor
|
||||||
}
|
}
|
||||||
@ -325,7 +322,11 @@ if (isNewArchitectureEnabled()) {
|
|||||||
configurations.all {
|
configurations.all {
|
||||||
resolutionStrategy.dependencySubstitution {
|
resolutionStrategy.dependencySubstitution {
|
||||||
substitute(module("com.facebook.react:react-native"))
|
substitute(module("com.facebook.react:react-native"))
|
||||||
.using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source")
|
.using(project(":ReactAndroid"))
|
||||||
|
.because("On New Architecture we're building React Native from source")
|
||||||
|
substitute(module("com.facebook.react:hermes-engine"))
|
||||||
|
.using(project(":ReactAndroid:hermes-engine"))
|
||||||
|
.because("On New Architecture we're building Hermes from source")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
<!-- [Custom] Expo Notifications -->
|
<!-- [Custom] Expo Notifications -->
|
||||||
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/ic_stat_notifications" />
|
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/ic_stat_notifications" />
|
||||||
<!-- [Custom] End Expo Notifications -->
|
<!-- [Custom] End Expo Notifications -->
|
||||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@xmflsct/tooot"/>
|
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://u.expo.dev/3288313f-3ff0-496a-a5a9-d8985e7cad5f"/>
|
||||||
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="${expoSDK}"/>
|
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="${runtimeVersion}"/>
|
||||||
<meta-data android:name="expo.modules.updates.EXPO_RELEASE_CHANNEL" android:value="${releaseChannel}"/>
|
<meta-data android:name="expo.modules.updates.EXPO_RELEASE_CHANNEL" android:value="${releaseChannel}"/>
|
||||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
|
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
|
||||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
|
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="WIFI_ONLY"/>
|
||||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
|
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
|
||||||
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait" android:documentLaunchMode="never">
|
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait" android:documentLaunchMode="never">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -24,7 +24,8 @@ public class MainActivity extends ReactActivity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
|
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
|
||||||
* you can specify the rendered you wish to use (Fabric or the older renderer).
|
* you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
|
||||||
|
* (Paper).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected ReactActivityDelegate createReactActivityDelegate() {
|
protected ReactActivityDelegate createReactActivityDelegate() {
|
||||||
@ -41,5 +42,12 @@ public class MainActivity extends ReactActivity {
|
|||||||
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
|
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
|
||||||
return reactRootView;
|
return reactRootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isConcurrentRootEnabled() {
|
||||||
|
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
|
||||||
|
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||||
|
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@ buildscript {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.google.gms:google-services:4.3.3'
|
classpath 'com.google.gms:google-services:4.3.3'
|
||||||
classpath("com.android.tools.build:gradle:7.0.4")
|
classpath("com.android.tools.build:gradle:7.1.1")
|
||||||
classpath("com.facebook.react:react-native-gradle-plugin")
|
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||||
classpath("de.undercouch:gradle-download-task:4.1.2")
|
classpath("de.undercouch:gradle-download-task:5.0.1")
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
@ -12,4 +12,6 @@ includeBuild('../node_modules/react-native-gradle-plugin')
|
|||||||
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
|
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
|
||||||
include(":ReactAndroid")
|
include(":ReactAndroid")
|
||||||
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
|
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
|
||||||
|
include(":ReactAndroid:hermes-engine")
|
||||||
|
project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@ import 'dotenv/config'
|
|||||||
const toootVersion = `${versions.major}.${versions.minor}.${versions.patch}`
|
const toootVersion = `${versions.major}.${versions.minor}.${versions.patch}`
|
||||||
|
|
||||||
export default (): ExpoConfig => ({
|
export default (): ExpoConfig => ({
|
||||||
|
updates: {
|
||||||
|
url: "https://u.expo.dev/3288313f-3ff0-496a-a5a9-d8985e7cad5f"
|
||||||
|
},
|
||||||
|
runtimeVersion: `${versions.major}.${versions.minor}`,
|
||||||
name: 'tooot',
|
name: 'tooot',
|
||||||
description: 'tooot for Mastodon',
|
description: 'tooot for Mastodon',
|
||||||
slug: 'tooot',
|
slug: 'tooot',
|
||||||
|
@ -31,8 +31,8 @@ private_lane :build_ios do
|
|||||||
IPA_FILE = "#{BUILD_DIRECTORY}/tooot.ipa"
|
IPA_FILE = "#{BUILD_DIRECTORY}/tooot.ipa"
|
||||||
DSYM_FILE = "#{BUILD_DIRECTORY}/tooot.app.dSYM.zip"
|
DSYM_FILE = "#{BUILD_DIRECTORY}/tooot.app.dSYM.zip"
|
||||||
|
|
||||||
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesSDKVersion", value: VERSIONS[:expo] )
|
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesRuntimeVersion", value: VERSION )
|
||||||
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesReleaseChannel", value: RELEASE_CHANNEL )
|
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesReleaseChannel", value: ENVIRONMENT )
|
||||||
|
|
||||||
setup_ci
|
setup_ci
|
||||||
set_info_plist_value( path: INFO_PLIST, key: "CFBundleShortVersionString", value: VERSION )
|
set_info_plist_value( path: INFO_PLIST, key: "CFBundleShortVersionString", value: VERSION )
|
||||||
@ -97,8 +97,8 @@ private_lane :build_android do
|
|||||||
print_command: true,
|
print_command: true,
|
||||||
print_command_output: true,
|
print_command_output: true,
|
||||||
properties: {
|
properties: {
|
||||||
"expoSDK" => VERSIONS[:expo],
|
"runtimeVersion" => VERSION,
|
||||||
"releaseChannel" => RELEASE_CHANNEL,
|
"releaseChannel" => ENVIRONMENT,
|
||||||
"android.injected.signing.store.file" => "#{File.expand_path('..', Dir.pwd)}/android/tooot.jks",
|
"android.injected.signing.store.file" => "#{File.expand_path('..', Dir.pwd)}/android/tooot.jks",
|
||||||
"android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
|
"android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
|
||||||
"android.injected.signing.key.alias" => ENV["ANDROID_KEYSTORE_ALIAS"],
|
"android.injected.signing.key.alias" => ENV["ANDROID_KEYSTORE_ALIAS"],
|
||||||
@ -136,8 +136,8 @@ private_lane :build_android_apk do
|
|||||||
print_command: true,
|
print_command: true,
|
||||||
print_command_output: true,
|
print_command_output: true,
|
||||||
properties: {
|
properties: {
|
||||||
"expoSDK" => VERSIONS[:expo],
|
"runtimeVersion" => VERSION,
|
||||||
"releaseChannel" => RELEASE_CHANNEL,
|
"releaseChannel" => ENVIRONMENT,
|
||||||
"android.injected.signing.store.file" => "#{File.expand_path('..', Dir.pwd)}/android/tooot.jks",
|
"android.injected.signing.store.file" => "#{File.expand_path('..', Dir.pwd)}/android/tooot.jks",
|
||||||
"android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
|
"android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
|
||||||
"android.injected.signing.key.alias" => ENV["ANDROID_KEYSTORE_ALIAS"],
|
"android.injected.signing.key.alias" => ENV["ANDROID_KEYSTORE_ALIAS"],
|
||||||
@ -185,6 +185,5 @@ lane :release do
|
|||||||
upload_assets: ["#{File.expand_path('..', Dir.pwd)}/tooot-#{GITHUB_RELEASE}.apk"]
|
upload_assets: ["#{File.expand_path('..', Dir.pwd)}/tooot-#{GITHUB_RELEASE}.apk"]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
yarn( package_path: "./package.json", flags: "release", command: RELEASE_CHANNEL )
|
|
||||||
rocket
|
rocket
|
||||||
end
|
end
|
||||||
|
6
index.js
6
index.js
@ -1,8 +1,8 @@
|
|||||||
import { registerRootComponent } from 'expo';
|
import { registerRootComponent } from 'expo'
|
||||||
|
|
||||||
import App from '@root/App';
|
import App from '@root/App'
|
||||||
|
|
||||||
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
|
||||||
// It also ensures that whether you load the app in the Expo client or in a native build,
|
// It also ensures that whether you load the app in the Expo client or in a native build,
|
||||||
// the environment is set up appropriately
|
// the environment is set up appropriately
|
||||||
registerRootComponent(App);
|
registerRootComponent(App)
|
||||||
|
10
ios/.xcode.env
Normal file
10
ios/.xcode.env
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# This `.xcode.env` file is versioned and is used to source the environment
|
||||||
|
# used when running script phases inside Xcode.
|
||||||
|
# To customize your local environment, you can create an `.xcode.env.local`
|
||||||
|
# file that is not versioned.
|
||||||
|
# NODE_BINARY variable contains the PATH to the node executable.
|
||||||
|
#
|
||||||
|
# Customize the NODE_BINARY variable here.
|
||||||
|
# For example, to use nvm with brew, add the following line
|
||||||
|
# . "$(brew --prefix nvm)/nvm.sh" --no-use
|
||||||
|
export NODE_BINARY=$(command -v node)
|
36
ios/Podfile
36
ios/Podfile
@ -2,22 +2,16 @@ require File.join(File.dirname(`node --print "require.resolve('expo/package.json
|
|||||||
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
|
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
|
||||||
require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules")
|
require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules")
|
||||||
|
|
||||||
platform :ios, '12.0'
|
platform :ios, '12.4'
|
||||||
install! 'cocoapods', :deterministic_uuids => false
|
install! 'cocoapods', :deterministic_uuids => false
|
||||||
|
|
||||||
|
production = ENV["PRODUCTION"] == "1"
|
||||||
|
|
||||||
require 'json'
|
require 'json'
|
||||||
podfile_properties = JSON.parse(File.read('./Podfile.properties.json')) rescue {}
|
podfile_properties = JSON.parse(File.read('./Podfile.properties.json')) rescue {}
|
||||||
|
|
||||||
target 'tooot' do
|
target 'tooot' do
|
||||||
use_expo_modules!
|
use_expo_modules!
|
||||||
post_integrate do |installer|
|
|
||||||
begin
|
|
||||||
expo_patch_react_imports!(installer)
|
|
||||||
rescue => e
|
|
||||||
Pod::UI.warn e
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
config = use_native_modules!
|
config = use_native_modules!
|
||||||
|
|
||||||
# Flags change depending on the env values.
|
# Flags change depending on the env values.
|
||||||
@ -25,32 +19,40 @@ target 'tooot' do
|
|||||||
|
|
||||||
use_react_native!(
|
use_react_native!(
|
||||||
:path => config[:reactNativePath],
|
:path => config[:reactNativePath],
|
||||||
|
:production => production,
|
||||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes',
|
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes',
|
||||||
:fabric_enabled => flags[:fabric_enabled],
|
:fabric_enabled => flags[:fabric_enabled],
|
||||||
|
:flipper_configuration => FlipperConfiguration.disabled,
|
||||||
# An absolute path to your application root.
|
# An absolute path to your application root.
|
||||||
:app_path => "#{Pod::Config.instance.installation_root}/.."
|
:app_path => "#{Pod::Config.instance.installation_root}/.."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Enables Flipper.
|
|
||||||
#
|
|
||||||
# Note that if you have use_frameworks! enabled, Flipper will not work and
|
|
||||||
# you should disable the next line.
|
|
||||||
# use_flipper!()
|
|
||||||
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
react_native_post_install(installer)
|
react_native_post_install(installer)
|
||||||
|
__apply_Xcode_12_5_M1_post_install_workaround(installer)
|
||||||
|
|
||||||
|
# For share extension
|
||||||
installer.pods_project.targets.each do |target|
|
installer.pods_project.targets.each do |target|
|
||||||
target.build_configurations.each do |config|
|
target.build_configurations.each do |config|
|
||||||
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'
|
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post_integrate do |installer|
|
||||||
|
begin
|
||||||
|
expo_patch_react_imports!(installer)
|
||||||
|
rescue => e
|
||||||
|
Pod::UI.warn e
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
target 'ShareExtension' do
|
target 'ShareExtension' do
|
||||||
use_react_native!(
|
use_react_native!(
|
||||||
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes'
|
:production => production,
|
||||||
|
:hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes',
|
||||||
|
:flipper_configuration => FlipperConfiguration.disabled
|
||||||
)
|
)
|
||||||
|
|
||||||
pod 'RNShareMenu', :path => '../node_modules/react-native-share-menu'
|
pod 'RNShareMenu', :path => '../node_modules/react-native-share-menu'
|
||||||
|
777
ios/Podfile.lock
777
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
@ -72,7 +72,7 @@
|
|||||||
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = tooot/SplashScreen.storyboard; sourceTree = "<group>"; };
|
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = tooot/SplashScreen.storyboard; sourceTree = "<group>"; };
|
||||||
B96B72E5384D44A7B240B27E /* GoogleService-Info.plist */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "tooot/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
B96B72E5384D44A7B240B27E /* GoogleService-Info.plist */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "tooot/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||||
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
|
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
|
||||||
DF8133F098604A10B0D94952 /* boop.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = boop.mp3; path = tooot/boop.mp3; sourceTree = "<group>"; };
|
DF8133F098604A10B0D94952 /* boop.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = boop.mp3; path = tooot/boop.mp3; sourceTree = "<group>"; };
|
||||||
E613A80A28282A01003C97D6 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = tooot/AppDelegate.mm; sourceTree = "<group>"; };
|
E613A80A28282A01003C97D6 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = tooot/AppDelegate.mm; sourceTree = "<group>"; };
|
||||||
E633A420281EAEAB000E540F /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
E633A420281EAEAB000E540F /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
E633A427281EAEAB000E540F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
E633A427281EAEAB000E540F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
@ -333,13 +333,15 @@
|
|||||||
files = (
|
files = (
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
|
"$(SRCROOT)/.xcode.env.local",
|
||||||
|
"$(SRCROOT)/.xcode.env",
|
||||||
);
|
);
|
||||||
name = "Bundle React Native code and images";
|
name = "Bundle React Native code and images";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n../node_modules/expo-constants/scripts/get-app-config-ios.sh\n";
|
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
|
||||||
};
|
};
|
||||||
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {
|
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
@ -390,17 +392,13 @@
|
|||||||
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-resources.sh",
|
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-resources.sh",
|
||||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
|
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
|
||||||
"${PODS_CONFIGURATION_BUILD_DIR}/EXUpdates/EXUpdates.bundle",
|
"${PODS_CONFIGURATION_BUILD_DIR}/EXUpdates/EXUpdates.bundle",
|
||||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle",
|
|
||||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
|
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
|
||||||
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
|
|
||||||
);
|
);
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
|
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
|
||||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXUpdates.bundle",
|
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXUpdates.bundle",
|
||||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/QBImagePicker.bundle",
|
|
||||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
|
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
|
||||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
@ -524,7 +522,6 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-tooot.debug.xcconfig */;
|
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-tooot.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = tooot/tooot.entitlements;
|
CODE_SIGN_ENTITLEMENTS = tooot/tooot.entitlements;
|
||||||
@ -533,13 +530,12 @@
|
|||||||
CURRENT_PROJECT_VERSION = 2102022230;
|
CURRENT_PROJECT_VERSION = 2102022230;
|
||||||
DEVELOPMENT_TEAM = 8EGBLQ2MA6;
|
DEVELOPMENT_TEAM = 8EGBLQ2MA6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"FB_SONARKIT_ENABLED=1",
|
"FB_SONARKIT_ENABLED=1",
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = tooot/Info.plist;
|
INFOPLIST_FILE = tooot/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -564,7 +560,6 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-tooot.release.xcconfig */;
|
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-tooot.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = tooot/tooot.entitlements;
|
CODE_SIGN_ENTITLEMENTS = tooot/tooot.entitlements;
|
||||||
@ -572,9 +567,8 @@
|
|||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 2102022230;
|
CURRENT_PROJECT_VERSION = 2102022230;
|
||||||
DEVELOPMENT_TEAM = 8EGBLQ2MA6;
|
DEVELOPMENT_TEAM = 8EGBLQ2MA6;
|
||||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
|
||||||
INFOPLIST_FILE = tooot/Info.plist;
|
INFOPLIST_FILE = tooot/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -599,7 +593,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
@ -644,15 +638,12 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = "\"\"";
|
||||||
"$(SDKROOT)/usr/lib/swift",
|
|
||||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
|
|
||||||
"\"$(inherited)\"",
|
|
||||||
);
|
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@ -662,7 +653,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
@ -700,14 +691,12 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = "\"\"";
|
||||||
"$(SDKROOT)/usr/lib/swift",
|
|
||||||
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
|
|
||||||
"\"$(inherited)\"",
|
|
||||||
);
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
ONLY_ACTIVE_ARCH = NO;
|
||||||
|
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
@ -736,7 +725,7 @@
|
|||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
@ -781,7 +770,7 @@
|
|||||||
INFOPLIST_FILE = ShareExtension/Info.plist;
|
INFOPLIST_FILE = ShareExtension/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#import <react/config/ReactNativeConfig.h>
|
#import <react/config/ReactNativeConfig.h>
|
||||||
|
|
||||||
|
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
|
||||||
|
|
||||||
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
|
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
|
||||||
RCTTurboModuleManager *_turboModuleManager;
|
RCTTurboModuleManager *_turboModuleManager;
|
||||||
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
|
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
|
||||||
@ -46,6 +48,9 @@
|
|||||||
|
|
||||||
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
|
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
|
||||||
|
|
||||||
|
// NSDictionary *initProps = [self prepareInitialProps];
|
||||||
|
// UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"tooot", initProps);
|
||||||
|
|
||||||
if (@available(iOS 13.0, *)) {
|
if (@available(iOS 13.0, *)) {
|
||||||
rootView.backgroundColor = [UIColor colorNamed:@"SplashScreenBackgroundColor"];
|
rootView.backgroundColor = [UIColor colorNamed:@"SplashScreenBackgroundColor"];
|
||||||
} else {
|
} else {
|
||||||
@ -61,6 +66,25 @@
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
|
||||||
|
///
|
||||||
|
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||||
|
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
|
||||||
|
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
|
||||||
|
- (BOOL)concurrentRootEnabled
|
||||||
|
{
|
||||||
|
// Switch this bool to turn on and off the concurrent root
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)prepareInitialProps
|
||||||
|
{
|
||||||
|
NSMutableDictionary *initProps = [NSMutableDictionary new];
|
||||||
|
#ifdef RCT_NEW_ARCH_ENABLED
|
||||||
|
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
|
||||||
|
#endif
|
||||||
|
return initProps;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
<key>EXUpdatesLaunchWaitMs</key>
|
<key>EXUpdatesLaunchWaitMs</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
<key>EXUpdatesReleaseChannel</key>
|
<key>EXUpdatesReleaseChannel</key>
|
||||||
<string>0-development</string>
|
<string>development</string>
|
||||||
<key>EXUpdatesSDKVersion</key>
|
<key>EXUpdatesRuntimeVersion</key>
|
||||||
<string>0</string>
|
<string>0</string>
|
||||||
<key>EXUpdatesURL</key>
|
<key>EXUpdatesURL</key>
|
||||||
<string>https://exp.host/@xmflsct/tooot</string>
|
<string>https://u.expo.dev/3288313f-3ff0-496a-a5a9-d8985e7cad5f</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
220
package.json
220
package.json
@ -1,11 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "tooot",
|
"name": "tooot",
|
||||||
"versions": {
|
"versions": {
|
||||||
"native": "220603",
|
|
||||||
"major": 4,
|
"major": 4,
|
||||||
"minor": 1,
|
"minor": 2,
|
||||||
"patch": 6,
|
"patch": 0
|
||||||
"expo": "45.0.0"
|
|
||||||
},
|
},
|
||||||
"description": "tooot app for Mastodon",
|
"description": "tooot app for Mastodon",
|
||||||
"author": "xmflsct <me@xmflsct.com>",
|
"author": "xmflsct <me@xmflsct.com>",
|
||||||
@ -20,138 +18,110 @@
|
|||||||
"iphone": "react-native run-ios",
|
"iphone": "react-native run-ios",
|
||||||
"ipad": "react-native run-ios --simulator 'iPad mini (6th generation)'",
|
"ipad": "react-native run-ios --simulator 'iPad mini (6th generation)'",
|
||||||
"app:build": "bundle exec fastlane",
|
"app:build": "bundle exec fastlane",
|
||||||
"release": "scripts/release.sh",
|
|
||||||
"clean": "react-native-clean-project",
|
"clean": "react-native-clean-project",
|
||||||
"postinstall": "patch-package"
|
"postinstall": "patch-package"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/react-native-action-sheet": "3.13.0",
|
"@expo/react-native-action-sheet": "^3.13.0",
|
||||||
"@formatjs/intl-datetimeformat": "^6.0.2",
|
"@formatjs/intl-datetimeformat": "^6.0.3",
|
||||||
"@formatjs/intl-getcanonicallocales": "^2.0.2",
|
"@formatjs/intl-getcanonicallocales": "^2.0.2",
|
||||||
"@formatjs/intl-locale": "^3.0.2",
|
"@formatjs/intl-locale": "^3.0.3",
|
||||||
"@formatjs/intl-numberformat": "^8.0.2",
|
"@formatjs/intl-numberformat": "^8.0.4",
|
||||||
"@formatjs/intl-pluralrules": "^5.0.2",
|
"@formatjs/intl-pluralrules": "^5.0.3",
|
||||||
"@formatjs/intl-relativetimeformat": "^11.0.2",
|
"@formatjs/intl-relativetimeformat": "^11.0.3",
|
||||||
"@mattermost/react-native-paste-input": "^0.4.2",
|
"@mattermost/react-native-paste-input": "^0.5.0",
|
||||||
"@neverdull-agency/expo-unlimited-secure-store": "1.0.10",
|
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
|
||||||
"@react-native-async-storage/async-storage": "1.17.6",
|
"@react-native-async-storage/async-storage": "^1.17.9",
|
||||||
"@react-native-community/blur": "3.6.0",
|
"@react-native-clipboard/clipboard": "^1.10.0",
|
||||||
"@react-native-community/cameraroll": "4.1.2",
|
"@react-native-community/blur": "^4.2.0",
|
||||||
"@react-native-community/netinfo": "9.0.0",
|
"@react-native-community/cameraroll": "^4.1.2",
|
||||||
"@react-native-community/segmented-control": "2.2.2",
|
"@react-native-community/netinfo": "^9.3.0",
|
||||||
"@react-navigation/bottom-tabs": "6.3.1",
|
"@react-native-community/segmented-control": "^2.2.2",
|
||||||
"@react-navigation/native": "6.0.10",
|
"@react-navigation/bottom-tabs": "^6.3.2",
|
||||||
"@react-navigation/native-stack": "6.6.2",
|
"@react-navigation/native": "^6.0.11",
|
||||||
"@react-navigation/stack": "6.2.1",
|
"@react-navigation/native-stack": "^6.7.0",
|
||||||
"@reduxjs/toolkit": "1.8.2",
|
"@react-navigation/stack": "^6.2.2",
|
||||||
"@sentry/react-native": "3.4.3",
|
"@reduxjs/toolkit": "^1.8.4",
|
||||||
"@sharcoux/slider": "6.0.3",
|
"@sentry/react-native": "^4.2.2",
|
||||||
"axios": "0.27.2",
|
"@sharcoux/slider": "^6.0.3",
|
||||||
"expo": "45.0.5",
|
"axios": "^0.27.2",
|
||||||
"expo-auth-session": "3.6.1",
|
"expo": "^46.0.7",
|
||||||
"expo-av": "11.2.3",
|
"expo-auth-session": "^3.7.1",
|
||||||
"expo-constants": "^13.1.1",
|
"expo-av": "^12.0.4",
|
||||||
"expo-crypto": "10.2.0",
|
"expo-constants": "^13.2.3",
|
||||||
"expo-device": "4.2.0",
|
"expo-crypto": "^11.0.0",
|
||||||
"expo-file-system": "14.0.0",
|
"expo-device": "^4.3.0",
|
||||||
"expo-firebase-analytics": "7.0.0",
|
"expo-file-system": "^14.1.0",
|
||||||
"expo-haptics": "11.2.0",
|
"expo-firebase-analytics": "^7.1.1",
|
||||||
"expo-image-manipulator": "^10.3.1",
|
"expo-haptics": "^11.3.0",
|
||||||
"expo-image-picker": "13.1.1",
|
"expo-linking": "^3.2.2",
|
||||||
"expo-linking": "3.1.0",
|
"expo-localization": "^13.1.0",
|
||||||
"expo-localization": "13.0.0",
|
"expo-notifications": "^0.16.1",
|
||||||
"expo-notifications": "0.15.2",
|
"expo-random": "^12.3.0",
|
||||||
"expo-random": "12.2.0",
|
"expo-screen-capture": "^4.3.0",
|
||||||
"expo-screen-capture": "4.2.0",
|
"expo-secure-store": "^11.3.0",
|
||||||
"expo-secure-store": "11.2.0",
|
"expo-splash-screen": "^0.16.1",
|
||||||
"expo-splash-screen": "0.15.1",
|
"expo-store-review": "^5.3.0",
|
||||||
"expo-store-review": "5.2.0",
|
"expo-updates": "^0.14.4",
|
||||||
"expo-updates": "0.13.2",
|
"expo-video-thumbnails": "^6.4.0",
|
||||||
"expo-video-thumbnails": "6.3.0",
|
"expo-web-browser": "^11.0.0",
|
||||||
"expo-web-browser": "10.2.1",
|
"i18next": "^21.9.0",
|
||||||
"i18next": "21.8.8",
|
"li": "^1.3.0",
|
||||||
"li": "1.3.0",
|
"lodash": "^4.17.21",
|
||||||
"lodash": "4.17.21",
|
"react": "^18.2.0",
|
||||||
"react": "17.0.2",
|
"react-dom": "^18.2.0",
|
||||||
"react-dom": "17.0.2",
|
"react-i18next": "^11.18.3",
|
||||||
"react-i18next": "11.17.0",
|
"react-intl": "^6.0.5",
|
||||||
"react-intl": "^6.0.4",
|
"react-native": "^0.69.4",
|
||||||
"react-native": "0.68.2",
|
"react-native-animated-spinkit": "^1.5.2",
|
||||||
"react-native-animated-spinkit": "1.5.2",
|
|
||||||
"react-native-base64": "^0.2.1",
|
"react-native-base64": "^0.2.1",
|
||||||
"react-native-blurhash": "1.1.10",
|
"react-native-blurhash": "^1.1.10",
|
||||||
"react-native-context-menu-view": "xmflsct/react-native-context-menu-view",
|
"react-native-context-menu-view": "xmflsct/react-native-context-menu-view",
|
||||||
"react-native-fast-image": "8.5.11",
|
"react-native-fast-image": "^8.5.11",
|
||||||
"react-native-feather": "1.1.2",
|
"react-native-feather": "^1.1.2",
|
||||||
"react-native-flash-message": "0.2.1",
|
"react-native-flash-message": "^0.3.1",
|
||||||
"react-native-gesture-handler": "2.4.2",
|
"react-native-gesture-handler": "^2.5.0",
|
||||||
"react-native-htmlview": "0.16.0",
|
"react-native-htmlview": "^0.16.0",
|
||||||
"react-native-image-crop-picker": "^0.37.3",
|
"react-native-image-picker": "^4.8.5",
|
||||||
"react-native-language-detection": "^0.1.0",
|
"react-native-language-detection": "^0.1.0",
|
||||||
"react-native-pager-view": "5.4.11",
|
"react-native-pager-view": "^5.4.25",
|
||||||
"react-native-reanimated": "2.8.0",
|
"react-native-reanimated": "^2.9.1",
|
||||||
"react-native-safe-area-context": "4.3.1",
|
"react-native-safe-area-context": "^4.3.1",
|
||||||
"react-native-screens": "3.13.1",
|
"react-native-screens": "^3.15.0",
|
||||||
"react-native-share-menu": "^5.0.5",
|
"react-native-share-menu": "^6.0.0",
|
||||||
"react-native-svg": "12.3.0",
|
"react-native-svg": "^12.4.4",
|
||||||
"react-native-swipe-list-view": "3.2.9",
|
"react-native-swipe-list-view": "^3.2.9",
|
||||||
"react-native-tab-view": "3.1.1",
|
"react-native-tab-view": "^3.1.1",
|
||||||
"react-query": "3.39.1",
|
"react-query": "^3.39.2",
|
||||||
"react-redux": "8.0.2",
|
"react-redux": "^8.0.2",
|
||||||
"redux-persist": "6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"rn-placeholder": "3.0.3",
|
"rn-placeholder": "^3.0.3",
|
||||||
"sentry-expo": "4.2.0",
|
"sentry-expo": "^5.0.2",
|
||||||
"tslib": "2.4.0",
|
"tslib": "^2.4.0",
|
||||||
"valid-url": "1.0.9"
|
"valid-url": "^1.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.18.2",
|
"@babel/core": "^7.18.10",
|
||||||
"@babel/plugin-proposal-optional-chaining": "7.17.12",
|
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
|
||||||
"@babel/preset-react": "^7.17.12",
|
"@babel/preset-react": "^7.18.6",
|
||||||
"@babel/preset-typescript": "7.17.12",
|
"@babel/preset-typescript": "^7.18.6",
|
||||||
"@expo/config": "6.0.24",
|
"@expo/config": "^7.0.1",
|
||||||
"@types/lodash": "4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/react": "17.0.43",
|
"@types/react": "^18.0.17",
|
||||||
"@types/react-dom": "17.0.14",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/react-native": "0.67.8",
|
"@types/react-native": "^0.69.5",
|
||||||
"@types/react-native-base64": "^0.2.0",
|
"@types/react-native-base64": "^0.2.0",
|
||||||
"@types/react-native-share-menu": "^5.0.2",
|
"@types/react-native-share-menu": "^5.0.2",
|
||||||
"@types/react-timeago": "4.1.3",
|
"@types/react-timeago": "^4.1.3",
|
||||||
"@types/valid-url": "1.0.3",
|
"@types/valid-url": "^1.0.3",
|
||||||
"@welldone-software/why-did-you-render": "7.0.1",
|
"@welldone-software/why-did-you-render": "^7.0.1",
|
||||||
"babel-plugin-module-resolver": "4.1.0",
|
"babel-plugin-module-resolver": "^4.1.0",
|
||||||
"babel-plugin-transform-remove-console": "6.9.4",
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||||
"chalk": "4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"dotenv": "16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"patch-package": "6.4.7",
|
"patch-package": "^6.4.7",
|
||||||
"postinstall-postinstall": "2.1.0",
|
"postinstall-postinstall": "^2.1.0",
|
||||||
"react-native-clean-project": "4.0.1",
|
"react-native-clean-project": "^4.0.1",
|
||||||
"typescript": "4.7.3"
|
"typescript": "^4.7.4"
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"@types/react": "17.0.43",
|
|
||||||
"@types/react-dom": "17.0.14"
|
|
||||||
},
|
|
||||||
"expo": {
|
|
||||||
"autolinking": {
|
|
||||||
"ios": {
|
|
||||||
"exclude": [
|
|
||||||
"expo-application",
|
|
||||||
"expo-font",
|
|
||||||
"expo-keep-awake"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"exclude": [
|
|
||||||
"expo-application",
|
|
||||||
"expo-firebase-analytics",
|
|
||||||
"expo-firebase-core",
|
|
||||||
"expo-font",
|
|
||||||
"expo-keep-awake",
|
|
||||||
"expo-store-review",
|
|
||||||
"react-native-reanimated"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
27
patches/expo-modules-core+0.11.3.patch
Normal file
27
patches/expo-modules-core+0.11.3.patch
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
diff --git a/node_modules/expo-modules-core/android/build.gradle b/node_modules/expo-modules-core/android/build.gradle
|
||||||
|
index a57c367..13b4427 100644
|
||||||
|
--- a/node_modules/expo-modules-core/android/build.gradle
|
||||||
|
+++ b/node_modules/expo-modules-core/android/build.gradle
|
||||||
|
@@ -422,18 +422,16 @@ task prepareFolly(dependsOn: [downloadFolly], type: Copy) {
|
||||||
|
}
|
||||||
|
// END FOLLy
|
||||||
|
|
||||||
|
-task prepareHermes() {
|
||||||
|
+task prepareHermes(dependsOn: createNativeDepsDirectories, type: Copy) {
|
||||||
|
if (!FOR_HERMES) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
def soFiles = zipTree(HERMES_AAR).matching({ it.include "**/*.so" })
|
||||||
|
|
||||||
|
- copy {
|
||||||
|
- from soFiles
|
||||||
|
- from "$REACT_NATIVE_DIR/ReactAndroid/src/main/jni/first-party/hermes/Android.mk"
|
||||||
|
- into "$thirdPartyNdkDir/hermes"
|
||||||
|
- }
|
||||||
|
+ from soFiles
|
||||||
|
+ from "$REACT_NATIVE_DIR/ReactAndroid/src/main/jni/first-party/hermes/Android.mk"
|
||||||
|
+ into "$thirdPartyNdkDir/hermes"
|
||||||
|
}
|
||||||
|
|
||||||
|
task prepareThirdPartyNdkHeaders(dependsOn: [prepareBoost, prepareDoubleConversion, prepareFolly, prepareHermes]) {}
|
@ -1,5 +1,5 @@
|
|||||||
diff --git a/node_modules/react-native-fast-image/RNFastImage.podspec b/node_modules/react-native-fast-image/RNFastImage.podspec
|
diff --git a/node_modules/react-native-fast-image/RNFastImage.podspec b/node_modules/react-native-fast-image/RNFastImage.podspec
|
||||||
index db0fada..54d8d5b 100644
|
index db0fada..9379119 100644
|
||||||
--- a/node_modules/react-native-fast-image/RNFastImage.podspec
|
--- a/node_modules/react-native-fast-image/RNFastImage.podspec
|
||||||
+++ b/node_modules/react-native-fast-image/RNFastImage.podspec
|
+++ b/node_modules/react-native-fast-image/RNFastImage.podspec
|
||||||
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
|
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
|
||||||
@ -7,8 +7,9 @@ index db0fada..54d8d5b 100644
|
|||||||
|
|
||||||
s.dependency 'React-Core'
|
s.dependency 'React-Core'
|
||||||
- s.dependency 'SDWebImage', '~> 5.11.1'
|
- s.dependency 'SDWebImage', '~> 5.11.1'
|
||||||
+ s.dependency 'SDWebImage', '~> 5.12.5'
|
- s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
|
||||||
s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
|
+ s.dependency 'SDWebImage', '~> 5.13.2'
|
||||||
|
+ s.dependency 'SDWebImageWebPCoder', '~> 0.9.0'
|
||||||
end
|
end
|
||||||
diff --git a/node_modules/react-native-fast-image/android/build.gradle b/node_modules/react-native-fast-image/android/build.gradle
|
diff --git a/node_modules/react-native-fast-image/android/build.gradle b/node_modules/react-native-fast-image/android/build.gradle
|
||||||
index 5b21cd5..19d82f8 100644
|
index 5b21cd5..19d82f8 100644
|
||||||
|
22
patches/react-native-htmlview+0.16.0.patch
Normal file
22
patches/react-native-htmlview+0.16.0.patch
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
diff --git a/node_modules/react-native-htmlview/HTMLView.js b/node_modules/react-native-htmlview/HTMLView.js
|
||||||
|
index 43f8b7e..728112b 100644
|
||||||
|
--- a/node_modules/react-native-htmlview/HTMLView.js
|
||||||
|
+++ b/node_modules/react-native-htmlview/HTMLView.js
|
||||||
|
@@ -1,7 +1,7 @@
|
||||||
|
import React, {PureComponent} from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import htmlToElement from './htmlToElement';
|
||||||
|
-import {Linking, Platform, StyleSheet, View, ViewPropTypes} from 'react-native';
|
||||||
|
+import {Linking, Platform, StyleSheet, View} from 'react-native';
|
||||||
|
|
||||||
|
const boldStyle = {fontWeight: 'bold'};
|
||||||
|
const italicStyle = {fontStyle: 'italic'};
|
||||||
|
@@ -146,7 +146,7 @@ HtmlView.propTypes = {
|
||||||
|
renderNode: PropTypes.func,
|
||||||
|
RootComponent: PropTypes.func,
|
||||||
|
rootComponentProps: PropTypes.object,
|
||||||
|
- style: ViewPropTypes.style,
|
||||||
|
+ style: PropTypes.any,
|
||||||
|
stylesheet: PropTypes.object,
|
||||||
|
TextComponent: PropTypes.func,
|
||||||
|
textComponentProps: PropTypes.object,
|
@ -1,501 +0,0 @@
|
|||||||
diff --git a/node_modules/react-native-share-menu/ios/Constants.swift b/node_modules/react-native-share-menu/ios/Constants.swift
|
|
||||||
index 2811008..08385b7 100644
|
|
||||||
--- a/node_modules/react-native-share-menu/ios/Constants.swift
|
|
||||||
+++ b/node_modules/react-native-share-menu/ios/Constants.swift
|
|
||||||
@@ -23,7 +23,7 @@ public let COULD_NOT_PARSE_IMG_ERROR = "Couldn't parse image"
|
|
||||||
public let COULD_NOT_SAVE_FILE_ERROR = "Couldn't save file on disk"
|
|
||||||
public let NO_EXTENSION_CONTEXT_ERROR = "No extension context attached"
|
|
||||||
public let NO_DELEGATE_ERROR = "No ReactShareViewDelegate attached"
|
|
||||||
-public let COULD_NOT_FIND_ITEM_ERROR = "Couldn't find item attached to this share"
|
|
||||||
+public let COULD_NOT_FIND_ITEMS_ERROR = "Couldn't find items attached to this share"
|
|
||||||
|
|
||||||
// MARK: Keys
|
|
||||||
|
|
||||||
diff --git a/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift b/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift
|
|
||||||
index 6c4922a..74badda 100644
|
|
||||||
--- a/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift
|
|
||||||
+++ b/node_modules/react-native-share-menu/ios/Modules/ShareMenu.swift
|
|
||||||
@@ -9,7 +9,7 @@ class ShareMenu: RCTEventEmitter {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- var sharedData: [String:String]?
|
|
||||||
+ var sharedData: [[String:String]?]?
|
|
||||||
|
|
||||||
static var initialShare: (UIApplication, URL, [UIApplication.OpenURLOptionsKey : Any])?
|
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ class ShareMenu: RCTEventEmitter {
|
|
||||||
|
|
||||||
let extraData = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String:Any]
|
|
||||||
|
|
||||||
- if let data = userDefaults.object(forKey: USER_DEFAULTS_KEY) as? [String:String] {
|
|
||||||
+ if let data = userDefaults.object(forKey: USER_DEFAULTS_KEY) as? [[String:String]] {
|
|
||||||
sharedData = data
|
|
||||||
dispatchEvent(with: data, and: extraData)
|
|
||||||
userDefaults.removeObject(forKey: USER_DEFAULTS_KEY)
|
|
||||||
@@ -100,25 +100,22 @@ class ShareMenu: RCTEventEmitter {
|
|
||||||
|
|
||||||
@objc(getSharedText:)
|
|
||||||
func getSharedText(callback: RCTResponseSenderBlock) {
|
|
||||||
- guard var data: [String:Any] = sharedData else {
|
|
||||||
- callback([])
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
+ var data = [DATA_KEY: sharedData] as [String: Any]
|
|
||||||
|
|
||||||
if let bundleId = Bundle.main.bundleIdentifier, let userDefaults = UserDefaults(suiteName: "group.\(bundleId)") {
|
|
||||||
- data[EXTRA_DATA_KEY] = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String:Any]
|
|
||||||
+ data[EXTRA_DATA_KEY] = userDefaults.object(forKey: USER_DEFAULTS_EXTRA_DATA_KEY) as? [String: Any]
|
|
||||||
} else {
|
|
||||||
print("Error: \(NO_APP_GROUP_ERROR)")
|
|
||||||
}
|
|
||||||
|
|
||||||
callback([data as Any])
|
|
||||||
- sharedData = nil
|
|
||||||
+ sharedData = []
|
|
||||||
}
|
|
||||||
|
|
||||||
- func dispatchEvent(with data: [String:String], and extraData: [String:Any]?) {
|
|
||||||
+ func dispatchEvent(with data: [[String:String]], and extraData: [String:Any]?) {
|
|
||||||
guard hasListeners else { return }
|
|
||||||
|
|
||||||
- var finalData = data as [String:Any]
|
|
||||||
+ var finalData = [DATA_KEY: data] as [String: Any]
|
|
||||||
if (extraData != nil) {
|
|
||||||
finalData[EXTRA_DATA_KEY] = extraData
|
|
||||||
}
|
|
||||||
diff --git a/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift b/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift
|
|
||||||
index 5d21773..0c7eaa7 100644
|
|
||||||
--- a/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift
|
|
||||||
+++ b/node_modules/react-native-share-menu/ios/Modules/ShareMenuReactView.swift
|
|
||||||
@@ -3,8 +3,9 @@
|
|
||||||
// RNShareMenu
|
|
||||||
//
|
|
||||||
// Created by Gustavo Parreira on 28/07/2020.
|
|
||||||
-//
|
|
||||||
+// Modified by Veselin Stoyanov on 17/04/2021.
|
|
||||||
|
|
||||||
+import Foundation
|
|
||||||
import MobileCoreServices
|
|
||||||
|
|
||||||
@objc(ShareMenuReactView)
|
|
||||||
@@ -17,8 +18,6 @@ public class ShareMenuReactView: NSObject {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func attachViewDelegate(_ delegate: ReactShareViewDelegate!) {
|
|
||||||
- guard (ShareMenuReactView.viewDelegate == nil) else { return }
|
|
||||||
-
|
|
||||||
ShareMenuReactView.viewDelegate = delegate
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -65,12 +64,12 @@ public class ShareMenuReactView: NSObject {
|
|
||||||
|
|
||||||
let extensionContext = viewDelegate.loadExtensionContext()
|
|
||||||
|
|
||||||
- guard let item = extensionContext.inputItems.first as? NSExtensionItem else {
|
|
||||||
- print("Error: \(COULD_NOT_FIND_ITEM_ERROR)")
|
|
||||||
+ guard let items = extensionContext.inputItems as? [NSExtensionItem] else {
|
|
||||||
+ print("Error: \(COULD_NOT_FIND_ITEMS_ERROR)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
- viewDelegate.continueInApp(with: item, and: extraData)
|
|
||||||
+ viewDelegate.continueInApp(with: items, and: extraData)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc(data:reject:)
|
|
||||||
@@ -82,91 +81,96 @@ public class ShareMenuReactView: NSObject {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
- extractDataFromContext(context: extensionContext) { (data, mimeType, error) in
|
|
||||||
+ extractDataFromContext(context: extensionContext) { (data, error) in
|
|
||||||
guard (error == nil) else {
|
|
||||||
reject("error", error?.description, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
- resolve([MIME_TYPE_KEY: mimeType, DATA_KEY: data])
|
|
||||||
+ resolve([DATA_KEY: data])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- func extractDataFromContext(context: NSExtensionContext, withCallback callback: @escaping (String?, String?, NSException?) -> Void) {
|
|
||||||
- let item:NSExtensionItem! = context.inputItems.first as? NSExtensionItem
|
|
||||||
- let attachments:[AnyObject]! = item.attachments
|
|
||||||
-
|
|
||||||
- var urlProvider:NSItemProvider! = nil
|
|
||||||
- var imageProvider:NSItemProvider! = nil
|
|
||||||
- var textProvider:NSItemProvider! = nil
|
|
||||||
- var dataProvider:NSItemProvider! = nil
|
|
||||||
-
|
|
||||||
- for provider in attachments {
|
|
||||||
- if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
|
|
||||||
- urlProvider = provider as? NSItemProvider
|
|
||||||
- break
|
|
||||||
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
|
|
||||||
- textProvider = provider as? NSItemProvider
|
|
||||||
- break
|
|
||||||
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
|
|
||||||
- imageProvider = provider as? NSItemProvider
|
|
||||||
- break
|
|
||||||
- } else if provider.hasItemConformingToTypeIdentifier(kUTTypeData as String) {
|
|
||||||
- dataProvider = provider as? NSItemProvider
|
|
||||||
- break
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
+ func extractDataFromContext(context: NSExtensionContext, withCallback callback: @escaping ([Any]?, NSException?) -> Void) {
|
|
||||||
+ DispatchQueue.global().async {
|
|
||||||
+ let semaphore = DispatchSemaphore(value: 0)
|
|
||||||
+ let items:[NSExtensionItem]! = context.inputItems as? [NSExtensionItem]
|
|
||||||
+ var results: [[String: String]] = []
|
|
||||||
|
|
||||||
- if (urlProvider != nil) {
|
|
||||||
- urlProvider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (item, error) in
|
|
||||||
- let url: URL! = item as? URL
|
|
||||||
+ for item in items {
|
|
||||||
+ guard let attachments = item.attachments else {
|
|
||||||
+ callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"couldn't find attachments", userInfo:nil))
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- callback(url.absoluteString, "text/plain", nil)
|
|
||||||
- }
|
|
||||||
- } else if (imageProvider != nil) {
|
|
||||||
- imageProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { (item, error) in
|
|
||||||
- let imageUrl: URL! = item as? URL
|
|
||||||
+ for provider in attachments {
|
|
||||||
+ if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
|
|
||||||
+ provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (item, error) in
|
|
||||||
+ let url: URL! = item as? URL
|
|
||||||
|
|
||||||
- if (imageUrl != nil) {
|
|
||||||
- if let imageData = try? Data(contentsOf: imageUrl) {
|
|
||||||
- callback(imageUrl.absoluteString, self.extractMimeType(from: imageUrl), nil)
|
|
||||||
- }
|
|
||||||
- } else {
|
|
||||||
- let image: UIImage! = item as? UIImage
|
|
||||||
+ results.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"])
|
|
||||||
|
|
||||||
- if (image != nil) {
|
|
||||||
- let imageData: Data! = image.pngData();
|
|
||||||
+ semaphore.signal()
|
|
||||||
+ }
|
|
||||||
+ semaphore.wait()
|
|
||||||
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeText as String) {
|
|
||||||
+ provider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (item, error) in
|
|
||||||
+ let text:String! = item as? String
|
|
||||||
+
|
|
||||||
+ results.append([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"])
|
|
||||||
|
|
||||||
- // Creating temporary URL for image data (UIImage)
|
|
||||||
- guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryScreenshot.png") else {
|
|
||||||
- return
|
|
||||||
+ semaphore.signal()
|
|
||||||
+ }
|
|
||||||
+ semaphore.wait()
|
|
||||||
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
|
|
||||||
+ provider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { (item, error) in
|
|
||||||
+ let imageUrl: URL! = item as? URL
|
|
||||||
+
|
|
||||||
+ if (imageUrl != nil) {
|
|
||||||
+ if let imageData = try? Data(contentsOf: imageUrl) {
|
|
||||||
+ results.append([DATA_KEY: imageUrl.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: imageUrl)])
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ let image: UIImage! = item as? UIImage
|
|
||||||
+
|
|
||||||
+ if (image != nil) {
|
|
||||||
+ let imageData: Data! = image.pngData();
|
|
||||||
+
|
|
||||||
+ // Creating temporary URL for image data (UIImage)
|
|
||||||
+ guard let imageURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("TemporaryScreenshot.png") else {
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ do {
|
|
||||||
+ // Writing the image to the URL
|
|
||||||
+ try imageData.write(to: imageURL)
|
|
||||||
+
|
|
||||||
+ results.append([DATA_KEY: imageUrl.absoluteString, MIME_TYPE_KEY: imageURL.extractMimeType()])
|
|
||||||
+ } catch {
|
|
||||||
+ callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't load image", userInfo:nil))
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ semaphore.signal()
|
|
||||||
}
|
|
||||||
+ semaphore.wait()
|
|
||||||
+ } else if provider.hasItemConformingToTypeIdentifier(kUTTypeData as String) {
|
|
||||||
+ provider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (item, error) in
|
|
||||||
+ let url: URL! = item as? URL
|
|
||||||
|
|
||||||
- do {
|
|
||||||
- // Writing the image to the URL
|
|
||||||
- try imageData.write(to: imageURL)
|
|
||||||
+ results.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: self.extractMimeType(from: url)])
|
|
||||||
|
|
||||||
- callback(imageURL.absoluteString, imageURL.extractMimeType(), nil)
|
|
||||||
- } catch {
|
|
||||||
- callback(nil, nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"Can't load image", userInfo:nil))
|
|
||||||
+ semaphore.signal()
|
|
||||||
}
|
|
||||||
+ semaphore.wait()
|
|
||||||
+ } else {
|
|
||||||
+ callback(nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"couldn't find provider", userInfo:nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- } else if (textProvider != nil) {
|
|
||||||
- textProvider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (item, error) in
|
|
||||||
- let text:String! = item as? String
|
|
||||||
|
|
||||||
- callback(text, "text/plain", nil)
|
|
||||||
- }
|
|
||||||
- } else if (dataProvider != nil) {
|
|
||||||
- dataProvider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (item, error) in
|
|
||||||
- let url: URL! = item as? URL
|
|
||||||
-
|
|
||||||
- callback(url.absoluteString, self.extractMimeType(from: url), nil)
|
|
||||||
- }
|
|
||||||
- } else {
|
|
||||||
- callback(nil, nil, NSException(name: NSExceptionName(rawValue: "Error"), reason:"couldn't find provider", userInfo:nil))
|
|
||||||
+ callback(results, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
|
|
||||||
index 0189ef6..f42bce6 100644
|
|
||||||
--- a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
|
|
||||||
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
|
|
||||||
@@ -62,7 +62,7 @@ class ReactShareViewController: ShareViewController, RCTBridgeDelegate, ReactSha
|
|
||||||
self.openHostApp()
|
|
||||||
}
|
|
||||||
|
|
||||||
- func continueInApp(with item: NSExtensionItem, and extraData: [String:Any]?) {
|
|
||||||
- handlePost(item, extraData: extraData)
|
|
||||||
+ func continueInApp(with items: [NSExtensionItem], and extraData: [String:Any]?) {
|
|
||||||
+ handlePost(items, extraData: extraData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift b/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift
|
|
||||||
index 0aa4c58..ad0812c 100644
|
|
||||||
--- a/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift
|
|
||||||
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewDelegate.swift
|
|
||||||
@@ -10,5 +10,5 @@ public protocol ReactShareViewDelegate {
|
|
||||||
|
|
||||||
func openApp()
|
|
||||||
|
|
||||||
- func continueInApp(with item: NSExtensionItem, and extraData: [String:Any]?)
|
|
||||||
+ func continueInApp(with items: [NSExtensionItem], and extraData: [String:Any]?)
|
|
||||||
}
|
|
||||||
diff --git a/node_modules/react-native-share-menu/ios/ShareViewController.swift b/node_modules/react-native-share-menu/ios/ShareViewController.swift
|
|
||||||
index 7faf6e4..f02bde5 100644
|
|
||||||
--- a/node_modules/react-native-share-menu/ios/ShareViewController.swift
|
|
||||||
+++ b/node_modules/react-native-share-menu/ios/ShareViewController.swift
|
|
||||||
@@ -6,15 +6,18 @@
|
|
||||||
//
|
|
||||||
// Created by Gustavo Parreira on 26/07/2020.
|
|
||||||
//
|
|
||||||
+// Modified by Veselin Stoyanov on 17/04/2021.
|
|
||||||
|
|
||||||
+import Foundation
|
|
||||||
import MobileCoreServices
|
|
||||||
import UIKit
|
|
||||||
import Social
|
|
||||||
import RNShareMenu
|
|
||||||
|
|
||||||
-class ShareViewController: SLComposeServiceViewController {
|
|
||||||
+class ShareViewController: UIViewController {
|
|
||||||
var hostAppId: String?
|
|
||||||
var hostAppUrlScheme: String?
|
|
||||||
+ var sharedItems: [Any] = []
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
@@ -30,46 +33,64 @@ class ShareViewController: SLComposeServiceViewController {
|
|
||||||
} else {
|
|
||||||
print("Error: \(NO_INFO_PLIST_URL_SCHEME_ERROR)")
|
|
||||||
}
|
|
||||||
- }
|
|
||||||
|
|
||||||
- override func isContentValid() -> Bool {
|
|
||||||
- // Do validation of contentText and/or NSExtensionContext attachments here
|
|
||||||
- return true
|
|
||||||
+ guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
|
|
||||||
+ cancelRequest()
|
|
||||||
+ return
|
|
||||||
}
|
|
||||||
|
|
||||||
- override func didSelectPost() {
|
|
||||||
- // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
|
|
||||||
- guard let item = extensionContext?.inputItems.first as? NSExtensionItem else {
|
|
||||||
- cancelRequest()
|
|
||||||
+ handlePost(items)
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ override func viewDidAppear(_ animated: Bool) {
|
|
||||||
+ super.viewDidAppear(animated)
|
|
||||||
+
|
|
||||||
+ completeRequest()
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ func handlePost(_ items: [NSExtensionItem], extraData: [String:Any]? = nil) {
|
|
||||||
+ DispatchQueue.global().async {
|
|
||||||
+ guard let hostAppId = self.hostAppId else {
|
|
||||||
+ self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
+ guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
|
|
||||||
+ self.exit(withError: NO_APP_GROUP_ERROR)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
- handlePost(item)
|
|
||||||
- }
|
|
||||||
+ if let data = extraData {
|
|
||||||
+ self.storeExtraData(data)
|
|
||||||
+ } else {
|
|
||||||
+ self.removeExtraData()
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- override func configurationItems() -> [Any]! {
|
|
||||||
- // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
|
|
||||||
- return []
|
|
||||||
- }
|
|
||||||
+ let semaphore = DispatchSemaphore(value: 0)
|
|
||||||
|
|
||||||
- func handlePost(_ item: NSExtensionItem, extraData: [String:Any]? = nil) {
|
|
||||||
- guard let provider = item.attachments?.first else {
|
|
||||||
- cancelRequest()
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
+ for item in items {
|
|
||||||
+ guard let attachments = item.attachments else {
|
|
||||||
+ self.cancelRequest()
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- if let data = extraData {
|
|
||||||
- storeExtraData(data)
|
|
||||||
- } else {
|
|
||||||
- removeExtraData()
|
|
||||||
- }
|
|
||||||
+ for provider in attachments {
|
|
||||||
+ if provider.isText {
|
|
||||||
+ self.storeText(withProvider: provider, semaphore)
|
|
||||||
+ } else if provider.isURL {
|
|
||||||
+ self.storeUrl(withProvider: provider, semaphore)
|
|
||||||
+ } else {
|
|
||||||
+ self.storeFile(withProvider: provider, semaphore)
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- if provider.isText {
|
|
||||||
- storeText(withProvider: provider)
|
|
||||||
- } else if provider.isURL {
|
|
||||||
- storeUrl(withProvider: provider)
|
|
||||||
- } else {
|
|
||||||
- storeFile(withProvider: provider)
|
|
||||||
+ semaphore.wait()
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ userDefaults.set(self.sharedItems,
|
|
||||||
+ forKey: USER_DEFAULTS_KEY)
|
|
||||||
+ userDefaults.synchronize()
|
|
||||||
+
|
|
||||||
+ self.openHostApp()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -99,7 +120,7 @@ class ShareViewController: SLComposeServiceViewController {
|
|
||||||
userDefaults.synchronize()
|
|
||||||
}
|
|
||||||
|
|
||||||
- func storeText(withProvider provider: NSItemProvider) {
|
|
||||||
+ func storeText(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) {
|
|
||||||
provider.loadItem(forTypeIdentifier: kUTTypeText as String, options: nil) { (data, error) in
|
|
||||||
guard (error == nil) else {
|
|
||||||
self.exit(withError: error.debugDescription)
|
|
||||||
@@ -109,24 +130,13 @@ class ShareViewController: SLComposeServiceViewController {
|
|
||||||
self.exit(withError: COULD_NOT_FIND_STRING_ERROR)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
- guard let hostAppId = self.hostAppId else {
|
|
||||||
- self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
- guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
|
|
||||||
- self.exit(withError: NO_APP_GROUP_ERROR)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- userDefaults.set([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"],
|
|
||||||
- forKey: USER_DEFAULTS_KEY)
|
|
||||||
- userDefaults.synchronize()
|
|
||||||
|
|
||||||
- self.openHostApp()
|
|
||||||
+ self.sharedItems.append([DATA_KEY: text, MIME_TYPE_KEY: "text/plain"])
|
|
||||||
+ semaphore.signal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- func storeUrl(withProvider provider: NSItemProvider) {
|
|
||||||
+ func storeUrl(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) {
|
|
||||||
provider.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { (data, error) in
|
|
||||||
guard (error == nil) else {
|
|
||||||
self.exit(withError: error.debugDescription)
|
|
||||||
@@ -136,24 +146,13 @@ class ShareViewController: SLComposeServiceViewController {
|
|
||||||
self.exit(withError: COULD_NOT_FIND_URL_ERROR)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
- guard let hostAppId = self.hostAppId else {
|
|
||||||
- self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
- guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
|
|
||||||
- self.exit(withError: NO_APP_GROUP_ERROR)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- userDefaults.set([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"],
|
|
||||||
- forKey: USER_DEFAULTS_KEY)
|
|
||||||
- userDefaults.synchronize()
|
|
||||||
|
|
||||||
- self.openHostApp()
|
|
||||||
+ self.sharedItems.append([DATA_KEY: url.absoluteString, MIME_TYPE_KEY: "text/plain"])
|
|
||||||
+ semaphore.signal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- func storeFile(withProvider provider: NSItemProvider) {
|
|
||||||
+ func storeFile(withProvider provider: NSItemProvider, _ semaphore: DispatchSemaphore) {
|
|
||||||
provider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { (data, error) in
|
|
||||||
guard (error == nil) else {
|
|
||||||
self.exit(withError: error.debugDescription)
|
|
||||||
@@ -167,10 +166,6 @@ class ShareViewController: SLComposeServiceViewController {
|
|
||||||
self.exit(withError: NO_INFO_PLIST_INDENTIFIER_ERROR)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
- guard let userDefaults = UserDefaults(suiteName: "group.\(hostAppId)") else {
|
|
||||||
- self.exit(withError: NO_APP_GROUP_ERROR)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
guard let groupFileManagerContainer = FileManager.default
|
|
||||||
.containerURL(forSecurityApplicationGroupIdentifier: "group.\(hostAppId)")
|
|
||||||
else {
|
|
||||||
@@ -189,11 +184,8 @@ class ShareViewController: SLComposeServiceViewController {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
- userDefaults.set([DATA_KEY: filePath.absoluteString, MIME_TYPE_KEY: mimeType],
|
|
||||||
- forKey: USER_DEFAULTS_KEY)
|
|
||||||
- userDefaults.synchronize()
|
|
||||||
-
|
|
||||||
- self.openHostApp()
|
|
||||||
+ self.sharedItems.append([DATA_KEY: filePath.absoluteString, MIME_TYPE_KEY: mimeType])
|
|
||||||
+ semaphore.signal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
93
patches/react-native-share-menu+6.0.0.patch
Normal file
93
patches/react-native-share-menu+6.0.0.patch
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
diff --git a/node_modules/react-native-share-menu/android/build.gradle b/node_modules/react-native-share-menu/android/build.gradle
|
||||||
|
index 9557fdb..ebdeb6f 100644
|
||||||
|
--- a/node_modules/react-native-share-menu/android/build.gradle
|
||||||
|
+++ b/node_modules/react-native-share-menu/android/build.gradle
|
||||||
|
@@ -1,12 +1,12 @@
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
- compileSdkVersion 29
|
||||||
|
- buildToolsVersion "29.0.2"
|
||||||
|
+ compileSdkVersion 31
|
||||||
|
+ buildToolsVersion "31.0.0"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
- minSdkVersion 16
|
||||||
|
- targetSdkVersion 29
|
||||||
|
+ minSdkVersion 21
|
||||||
|
+ targetSdkVersion 31
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
ndk {
|
||||||
|
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
|
||||||
|
index f42bce6..ee36062 100644
|
||||||
|
--- a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
|
||||||
|
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
|
||||||
|
@@ -13,7 +13,7 @@ class ReactShareViewController: ShareViewController, RCTBridgeDelegate, ReactSha
|
||||||
|
func sourceURL(for bridge: RCTBridge!) -> URL! {
|
||||||
|
#if DEBUG
|
||||||
|
return RCTBundleURLProvider.sharedSettings()?
|
||||||
|
- .jsBundleURL(forBundleRoot: "index.share", fallbackResource: nil)
|
||||||
|
+ .jsBundleURL(forBundleRoot: "index.share")
|
||||||
|
#else
|
||||||
|
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
|
||||||
|
#endif
|
||||||
|
diff --git a/node_modules/react-native-share-menu/ios/ShareViewController.swift b/node_modules/react-native-share-menu/ios/ShareViewController.swift
|
||||||
|
index 12d8c92..64aa72b 100644
|
||||||
|
--- a/node_modules/react-native-share-menu/ios/ShareViewController.swift
|
||||||
|
+++ b/node_modules/react-native-share-menu/ios/ShareViewController.swift
|
||||||
|
@@ -19,8 +19,8 @@ class ShareViewController: SLComposeServiceViewController {
|
||||||
|
var hostAppUrlScheme: String?
|
||||||
|
var sharedItems: [Any] = []
|
||||||
|
|
||||||
|
- override func viewDidLoad() {
|
||||||
|
- super.viewDidLoad()
|
||||||
|
+ override func viewWillAppear(_ animated: Bool) {
|
||||||
|
+ super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
if let hostAppId = Bundle.main.object(forInfoDictionaryKey: HOST_APP_IDENTIFIER_INFO_PLIST_KEY) as? String {
|
||||||
|
self.hostAppId = hostAppId
|
||||||
|
@@ -33,6 +33,13 @@ class ShareViewController: SLComposeServiceViewController {
|
||||||
|
} else {
|
||||||
|
print("Error: \(NO_INFO_PLIST_URL_SCHEME_ERROR)")
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
|
||||||
|
+ cancelRequest()
|
||||||
|
+ return
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ handlePost(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func isContentValid() -> Bool {
|
||||||
|
@@ -40,16 +47,6 @@ class ShareViewController: SLComposeServiceViewController {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
- override func didSelectPost() {
|
||||||
|
- // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
|
||||||
|
- guard let items = extensionContext?.inputItems as? [NSExtensionItem] else {
|
||||||
|
- cancelRequest()
|
||||||
|
- return
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- handlePost(items)
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
override func configurationItems() -> [Any]! {
|
||||||
|
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
|
||||||
|
return []
|
||||||
|
@@ -238,11 +235,10 @@ class ShareViewController: SLComposeServiceViewController {
|
||||||
|
|
||||||
|
func completeRequest() {
|
||||||
|
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
|
||||||
|
- extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||||
|
+ extensionContext!.completeRequest(returningItems: nil, completionHandler: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cancelRequest() {
|
||||||
|
extensionContext!.cancelRequest(withError: NSError())
|
||||||
|
}
|
||||||
|
-
|
||||||
|
}
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ $# -ne 1 ]; then
|
|
||||||
echo "Arguments incorrect"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
expo publish --quiet --target bare --release-channel=$1
|
|
59
src/App.tsx
59
src/App.tsx
@ -74,37 +74,6 @@ const App: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const children = useCallback(
|
|
||||||
bootstrapped => {
|
|
||||||
log('log', 'App', 'bootstrapped')
|
|
||||||
if (bootstrapped) {
|
|
||||||
log('log', 'App', 'loading actual app :)')
|
|
||||||
const language = getSettingsLanguage(store.getState())
|
|
||||||
if (!language) {
|
|
||||||
store.dispatch(changeLanguage('en'))
|
|
||||||
i18n.changeLanguage('en')
|
|
||||||
} else {
|
|
||||||
i18n.changeLanguage(language)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Sentry.Native.TouchEventBoundary>
|
|
||||||
<ActionSheetProvider>
|
|
||||||
<AccessibilityManager>
|
|
||||||
<ThemeManager>
|
|
||||||
<Screens localCorrupt={localCorrupt} />
|
|
||||||
</ThemeManager>
|
|
||||||
</AccessibilityManager>
|
|
||||||
</ActionSheetProvider>
|
|
||||||
</Sentry.Native.TouchEventBoundary>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[localCorrupt]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GestureHandlerRootView style={{ flex: 1 }}>
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
@ -112,7 +81,33 @@ const App: React.FC = () => {
|
|||||||
<PersistGate
|
<PersistGate
|
||||||
persistor={persistor}
|
persistor={persistor}
|
||||||
onBeforeLift={onBeforeLift}
|
onBeforeLift={onBeforeLift}
|
||||||
children={children}
|
children={bootstrapped => {
|
||||||
|
log('log', 'App', 'bootstrapped')
|
||||||
|
if (bootstrapped) {
|
||||||
|
log('log', 'App', 'loading actual app :)')
|
||||||
|
const language = getSettingsLanguage(store.getState())
|
||||||
|
if (!language) {
|
||||||
|
store.dispatch(changeLanguage('en'))
|
||||||
|
i18n.changeLanguage('en')
|
||||||
|
} else {
|
||||||
|
i18n.changeLanguage(language)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Sentry.Native.TouchEventBoundary>
|
||||||
|
<ActionSheetProvider>
|
||||||
|
<AccessibilityManager>
|
||||||
|
<ThemeManager>
|
||||||
|
<Screens localCorrupt={localCorrupt} />
|
||||||
|
</ThemeManager>
|
||||||
|
</AccessibilityManager>
|
||||||
|
</ActionSheetProvider>
|
||||||
|
</Sentry.Native.TouchEventBoundary>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
@ -4,6 +4,7 @@ import { displayMessage, Message } from '@components/Message'
|
|||||||
import navigationRef from '@helpers/navigationRef'
|
import navigationRef from '@helpers/navigationRef'
|
||||||
import { NavigationContainer } from '@react-navigation/native'
|
import { NavigationContainer } from '@react-navigation/native'
|
||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
||||||
|
import ScreenAccountSelection from '@screens/AccountSelection'
|
||||||
import ScreenActions from '@screens/Actions'
|
import ScreenActions from '@screens/Actions'
|
||||||
import ScreenAnnouncements from '@screens/Announcements'
|
import ScreenAnnouncements from '@screens/Announcements'
|
||||||
import ScreenCompose from '@screens/Compose'
|
import ScreenCompose from '@screens/Compose'
|
||||||
@ -170,6 +171,9 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
}
|
}
|
||||||
| { data: string | string[]; mimeType: string }
|
| { data: string | string[]; mimeType: string }
|
||||||
) => {
|
) => {
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (instanceActive < 0) {
|
if (instanceActive < 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -234,29 +238,34 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'android':
|
// case 'android':
|
||||||
if (!item.mimeType) {
|
// if (!item.mimeType) {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
let tempData: string[]
|
// for (const d of item.data) {
|
||||||
if (!Array.isArray(item.data)) {
|
// filterMedia({ uri: d, mime: item.mimeType })
|
||||||
tempData = [item.data]
|
// }
|
||||||
} else {
|
// break
|
||||||
tempData = item.data
|
|
||||||
}
|
|
||||||
for (const d of item.data) {
|
|
||||||
filterMedia({ uri: d, mime: item.mimeType })
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text && !media.length) {
|
if (!text && !media.length) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
navigationRef.navigate('Screen-Compose', { type: 'share', text, media })
|
console.log('share', text, media)
|
||||||
|
if (instances.length > 1) {
|
||||||
|
navigationRef.navigate('Screen-AccountSelection', {
|
||||||
|
share: { text, media }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
navigationRef.navigate('Screen-Compose', {
|
||||||
|
type: 'share',
|
||||||
|
text,
|
||||||
|
media
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[instanceActive]
|
[]
|
||||||
)
|
)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ShareMenu.getInitialShare(handleShare)
|
ShareMenu.getInitialShare(handleShare)
|
||||||
@ -331,6 +340,23 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
animation: 'fade'
|
animation: 'fade'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name='Screen-AccountSelection'
|
||||||
|
component={ScreenAccountSelection}
|
||||||
|
options={({ navigation }) => ({
|
||||||
|
title: t('screenAccountSelection:heading'),
|
||||||
|
headerShadowVisible: false,
|
||||||
|
presentation: 'modal',
|
||||||
|
gestureEnabled: false,
|
||||||
|
headerLeft: () => (
|
||||||
|
<HeaderLeft
|
||||||
|
type='text'
|
||||||
|
content={t('common:buttons.cancel')}
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
|
|
||||||
<Message />
|
<Message />
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import chalk from 'chalk'
|
|
||||||
import Constants from 'expo-constants'
|
import Constants from 'expo-constants'
|
||||||
|
import handleError, { ctx } from './handleError'
|
||||||
const ctx = new chalk.Instance({ level: 3 })
|
|
||||||
|
|
||||||
export type Params = {
|
export type Params = {
|
||||||
method: 'get' | 'post' | 'put' | 'delete'
|
method: 'get' | 'post' | 'put' | 'delete'
|
||||||
@ -25,13 +23,13 @@ const apiGeneral = async <T = unknown>({
|
|||||||
}: Params): Promise<{ body: T }> => {
|
}: Params): Promise<{ body: T }> => {
|
||||||
console.log(
|
console.log(
|
||||||
ctx.bgGreen.bold(' API general ') +
|
ctx.bgGreen.bold(' API general ') +
|
||||||
' ' +
|
' ' +
|
||||||
domain +
|
domain +
|
||||||
' ' +
|
' ' +
|
||||||
method +
|
method +
|
||||||
ctx.green(' -> ') +
|
ctx.green(' -> ') +
|
||||||
`/${url}` +
|
`/${url}` +
|
||||||
(params ? ctx.green(' -> ') : ''),
|
(params ? ctx.green(' -> ') : ''),
|
||||||
params ? params : ''
|
params ? params : ''
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,7 +44,7 @@ const apiGeneral = async <T = unknown>({
|
|||||||
body && body instanceof FormData
|
body && body instanceof FormData
|
||||||
? 'multipart/form-data'
|
? 'multipart/form-data'
|
||||||
: 'application/json',
|
: 'application/json',
|
||||||
'User-Agent': `tooot/${Constants.manifest?.version}`,
|
'User-Agent': `tooot/${Constants.expoConfig?.version}`,
|
||||||
Accept: '*/*',
|
Accept: '*/*',
|
||||||
...headers
|
...headers
|
||||||
},
|
},
|
||||||
@ -57,40 +55,7 @@ const apiGeneral = async <T = unknown>({
|
|||||||
body: response.data
|
body: response.data
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(handleError)
|
||||||
if (error?.response) {
|
|
||||||
// The request was made and the server responded with a status code
|
|
||||||
// that falls out of the range of 2xx
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API general '),
|
|
||||||
ctx.bold('response'),
|
|
||||||
error.response.status,
|
|
||||||
error.response.data.error
|
|
||||||
)
|
|
||||||
return Promise.reject({
|
|
||||||
status: error?.response.status,
|
|
||||||
message: error?.response.data.error
|
|
||||||
})
|
|
||||||
} else if (error?.request) {
|
|
||||||
// The request was made but no response was received
|
|
||||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
|
||||||
// http.ClientRequest in node.js
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API general '),
|
|
||||||
ctx.bold('request'),
|
|
||||||
error.request
|
|
||||||
)
|
|
||||||
return Promise.reject()
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API general '),
|
|
||||||
ctx.bold('internal'),
|
|
||||||
error?.message,
|
|
||||||
url
|
|
||||||
)
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default apiGeneral
|
export default apiGeneral
|
||||||
|
38
src/api/handleError.ts
Normal file
38
src/api/handleError.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import chalk from 'chalk'
|
||||||
|
|
||||||
|
export const ctx = new chalk.Instance({ level: 3 })
|
||||||
|
|
||||||
|
const handleError = (error: any) => {
|
||||||
|
if (error?.response) {
|
||||||
|
// The request was made and the server responded with a status code
|
||||||
|
// that falls out of the range of 2xx
|
||||||
|
console.error(
|
||||||
|
ctx.bold(' API instance '),
|
||||||
|
ctx.bold('response'),
|
||||||
|
error.response.status,
|
||||||
|
error?.response.data?.error || error?.response.message || 'Unknown error'
|
||||||
|
)
|
||||||
|
return Promise.reject({
|
||||||
|
status: error?.response.status,
|
||||||
|
message:
|
||||||
|
error?.response.data?.error ||
|
||||||
|
error?.response.message ||
|
||||||
|
'Unknown error'
|
||||||
|
})
|
||||||
|
} else if (error?.request) {
|
||||||
|
// The request was made but no response was received
|
||||||
|
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||||
|
// http.ClientRequest in node.js
|
||||||
|
console.error(ctx.bold(' API instance '), ctx.bold('request'), error)
|
||||||
|
return Promise.reject()
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
ctx.bold(' API instance '),
|
||||||
|
ctx.bold('internal'),
|
||||||
|
error?.message
|
||||||
|
)
|
||||||
|
return Promise.reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default handleError
|
@ -1,10 +1,8 @@
|
|||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
import axios, { AxiosRequestConfig } from 'axios'
|
import axios, { AxiosRequestConfig } from 'axios'
|
||||||
import chalk from 'chalk'
|
|
||||||
import Constants from 'expo-constants'
|
import Constants from 'expo-constants'
|
||||||
import li from 'li'
|
import li from 'li'
|
||||||
|
import handleError, { ctx } from './handleError'
|
||||||
const ctx = new chalk.Instance({ level: 3 })
|
|
||||||
|
|
||||||
export type Params = {
|
export type Params = {
|
||||||
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
|
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
|
||||||
@ -76,7 +74,7 @@ const apiInstance = async <T = unknown>({
|
|||||||
body && body instanceof FormData
|
body && body instanceof FormData
|
||||||
? 'multipart/form-data'
|
? 'multipart/form-data'
|
||||||
: 'application/json',
|
: 'application/json',
|
||||||
'User-Agent': `tooot/${Constants.manifest?.version}`,
|
'User-Agent': `tooot/${Constants.expoConfig?.version}`,
|
||||||
Accept: '*/*',
|
Accept: '*/*',
|
||||||
...headers,
|
...headers,
|
||||||
...(token && {
|
...(token && {
|
||||||
@ -99,36 +97,7 @@ const apiInstance = async <T = unknown>({
|
|||||||
links: { prev, next }
|
links: { prev, next }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(handleError)
|
||||||
if (error?.response) {
|
|
||||||
// The request was made and the server responded with a status code
|
|
||||||
// that falls out of the range of 2xx
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API instance '),
|
|
||||||
ctx.bold('response'),
|
|
||||||
error.response.status,
|
|
||||||
error.response.data.error
|
|
||||||
)
|
|
||||||
return Promise.reject({
|
|
||||||
status: error?.response.status,
|
|
||||||
message: error?.response.data.error
|
|
||||||
})
|
|
||||||
} else if (error?.request) {
|
|
||||||
// The request was made but no response was received
|
|
||||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
|
||||||
// http.ClientRequest in node.js
|
|
||||||
console.error(ctx.bold(' API instance '), ctx.bold('request'), error)
|
|
||||||
return Promise.reject()
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API instance '),
|
|
||||||
ctx.bold('internal'),
|
|
||||||
error?.message,
|
|
||||||
url
|
|
||||||
)
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default apiInstance
|
export default apiInstance
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { mapEnvironment } from '@utils/checkEnvironment'
|
import { mapEnvironment } from '@utils/checkEnvironment'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import chalk from 'chalk'
|
|
||||||
import Constants from 'expo-constants'
|
import Constants from 'expo-constants'
|
||||||
import * as Sentry from 'sentry-expo'
|
import * as Sentry from 'sentry-expo'
|
||||||
|
import handleError, { ctx } from './handleError'
|
||||||
const ctx = new chalk.Instance({ level: 3 })
|
|
||||||
|
|
||||||
export type Params = {
|
export type Params = {
|
||||||
method: 'get' | 'post' | 'put' | 'delete'
|
method: 'get' | 'post' | 'put' | 'delete'
|
||||||
@ -52,7 +50,7 @@ const apiTooot = async <T = unknown>({
|
|||||||
body && body instanceof FormData
|
body && body instanceof FormData
|
||||||
? 'multipart/form-data'
|
? 'multipart/form-data'
|
||||||
: 'application/json',
|
: 'application/json',
|
||||||
'User-Agent': `tooot/${Constants.manifest?.version}`,
|
'User-Agent': `tooot/${Constants.expoConfig?.version}`,
|
||||||
Accept: '*/*',
|
Accept: '*/*',
|
||||||
...headers
|
...headers
|
||||||
},
|
},
|
||||||
@ -75,38 +73,7 @@ const apiTooot = async <T = unknown>({
|
|||||||
Sentry.Native.captureException(error)
|
Sentry.Native.captureException(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error?.response) {
|
return handleError(error)
|
||||||
// The request was made and the server responded with a status code
|
|
||||||
// that falls out of the range of 2xx
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API tooot '),
|
|
||||||
ctx.bold('response'),
|
|
||||||
error.response.status,
|
|
||||||
error.response.data.error
|
|
||||||
)
|
|
||||||
return Promise.reject({
|
|
||||||
status: error?.response.status,
|
|
||||||
message: error?.response.data.error
|
|
||||||
})
|
|
||||||
} else if (error?.request) {
|
|
||||||
// The request was made but no response was received
|
|
||||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
|
||||||
// http.ClientRequest in node.js
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API tooot '),
|
|
||||||
ctx.bold('request'),
|
|
||||||
error.request
|
|
||||||
)
|
|
||||||
return Promise.reject()
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
ctx.bold(' API tooot '),
|
|
||||||
ctx.bold('internal'),
|
|
||||||
error?.message,
|
|
||||||
url
|
|
||||||
)
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
src/components/AccountButton.tsx
Normal file
45
src/components/AccountButton.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import initQuery from '@utils/initQuery'
|
||||||
|
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||||
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
import React from 'react'
|
||||||
|
import Button from './Button'
|
||||||
|
import haptics from './haptics'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
instance: InstanceLatest
|
||||||
|
selected?: boolean
|
||||||
|
additionalActions?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccountButton: React.FC<Props> = ({
|
||||||
|
instance,
|
||||||
|
selected = false,
|
||||||
|
additionalActions
|
||||||
|
}) => {
|
||||||
|
const navigation = useNavigation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
type='text'
|
||||||
|
selected={selected}
|
||||||
|
style={{
|
||||||
|
marginBottom: StyleConstants.Spacing.M,
|
||||||
|
marginRight: StyleConstants.Spacing.M
|
||||||
|
}}
|
||||||
|
content={`@${instance.account.acct}@${instance.uri}${
|
||||||
|
selected ? ' ✓' : ''
|
||||||
|
}`}
|
||||||
|
onPress={() => {
|
||||||
|
haptics('Light')
|
||||||
|
initQuery({ instance, prefetch: { enabled: true } })
|
||||||
|
navigation.goBack()
|
||||||
|
if (additionalActions) {
|
||||||
|
additionalActions()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AccountButton
|
@ -41,8 +41,8 @@ const contextMenuAccount = ({
|
|||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('common:message.success.message', {
|
message: t('common:message.success.message', {
|
||||||
function: t(`account.${theParams.payload.property}.action`, {
|
function: t(`account.${theParams.payload.property}.action`, {
|
||||||
...(typeof theParams.payload.currentValue === 'boolean' && {
|
...(theParams.payload.property !== 'reports' && {
|
||||||
context: theParams.payload.currentValue.toString()
|
context: (theParams.payload.currentValue || false).toString()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -55,8 +55,8 @@ const contextMenuAccount = ({
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('common:message.error.message', {
|
message: t('common:message.error.message', {
|
||||||
function: t(`account.${theParams.payload.property}.action`, {
|
function: t(`account.${theParams.payload.property}.action`, {
|
||||||
...(typeof theParams.payload.currentValue === 'boolean' && {
|
...(theParams.payload.property !== 'reports' && {
|
||||||
context: theParams.payload.currentValue.toString()
|
context: (theParams.payload.currentValue || false).toString()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
|
import { displayMessage } from '@components/Message'
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Platform, Share } from 'react-native'
|
import { Platform, Share } from 'react-native'
|
||||||
import { ContextMenuAction } from 'react-native-context-menu-view'
|
import { ContextMenuAction } from 'react-native-context-menu-view'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
copiableContent?: React.MutableRefObject<{
|
||||||
|
content?: string | undefined
|
||||||
|
complete: boolean
|
||||||
|
}>
|
||||||
actions: ContextMenuAction[]
|
actions: ContextMenuAction[]
|
||||||
type: 'status' | 'account'
|
type: 'status' | 'account'
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const contextMenuShare = ({ actions, type, url }: Props) => {
|
const contextMenuShare = ({ copiableContent, actions, type, url }: Props) => {
|
||||||
|
const { theme } = useTheme()
|
||||||
const { t } = useTranslation('componentContextMenu')
|
const { t } = useTranslation('componentContextMenu')
|
||||||
|
|
||||||
actions.push({
|
actions.push({
|
||||||
@ -17,8 +25,24 @@ const contextMenuShare = ({ actions, type, url }: Props) => {
|
|||||||
title: t(`share.${type}.action`),
|
title: t(`share.${type}.action`),
|
||||||
systemIcon: 'square.and.arrow.up'
|
systemIcon: 'square.and.arrow.up'
|
||||||
})
|
})
|
||||||
|
Platform.OS !== 'android' &&
|
||||||
|
actions.push({
|
||||||
|
id: 'copy',
|
||||||
|
title: t(`copy.action`),
|
||||||
|
systemIcon: 'doc.on.doc',
|
||||||
|
disabled: !copiableContent?.current.content?.length
|
||||||
|
})
|
||||||
|
|
||||||
return (index: number) => {
|
return (index: number) => {
|
||||||
|
if (actions[index].id === 'copy') {
|
||||||
|
analytics('timeline_shared_headeractions_copy_press')
|
||||||
|
Clipboard.setString(copiableContent?.current.content || '')
|
||||||
|
displayMessage({
|
||||||
|
theme,
|
||||||
|
type: 'success',
|
||||||
|
message: t(`copy.succeed`)
|
||||||
|
})
|
||||||
|
}
|
||||||
if (actions[index].id === 'share') {
|
if (actions[index].id === 'share') {
|
||||||
analytics('timeline_shared_headeractions_share_press')
|
analytics('timeline_shared_headeractions_share_press')
|
||||||
switch (Platform.OS) {
|
switch (Platform.OS) {
|
||||||
|
@ -7,6 +7,7 @@ import { chunk, forEach, groupBy, sortBy } from 'lodash'
|
|||||||
import React, {
|
import React, {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
MutableRefObject,
|
MutableRefObject,
|
||||||
|
PropsWithChildren,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@ -57,7 +58,7 @@ export interface Props {
|
|||||||
maxLength?: number
|
maxLength?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComponentEmojis: React.FC<Props> = ({
|
const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
|
||||||
enabled = false,
|
enabled = false,
|
||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
|
@ -27,18 +27,6 @@ const EmojisList = React.memo(
|
|||||||
const { emojisState, emojisDispatch } = useContext(EmojisContext)
|
const { emojisState, emojisDispatch } = useContext(EmojisContext)
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
|
|
||||||
const listHeader = useCallback(
|
|
||||||
({ section: { title } }) => (
|
|
||||||
<CustomText
|
|
||||||
fontStyle='S'
|
|
||||||
style={{ position: 'absolute', color: colors.secondary }}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</CustomText>
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
const listItem = useCallback(
|
const listItem = useCallback(
|
||||||
({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
|
({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
|
||||||
return (
|
return (
|
||||||
@ -112,7 +100,14 @@ const EmojisList = React.memo(
|
|||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
sections={emojisState.emojis}
|
sections={emojisState.emojis}
|
||||||
keyExtractor={item => item[0].shortcode}
|
keyExtractor={item => item[0].shortcode}
|
||||||
renderSectionHeader={listHeader}
|
renderSectionHeader={({ section: { title } }) => (
|
||||||
|
<CustomText
|
||||||
|
fontStyle='S'
|
||||||
|
style={{ position: 'absolute', color: colors.secondary }}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</CustomText>
|
||||||
|
)}
|
||||||
renderItem={listItem}
|
renderItem={listItem}
|
||||||
windowSize={4}
|
windowSize={4}
|
||||||
/>
|
/>
|
||||||
|
@ -1,29 +1,54 @@
|
|||||||
|
import Icon from '@components/Icon'
|
||||||
import CustomText from '@components/Text'
|
import CustomText from '@components/Text'
|
||||||
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { View } from 'react-native'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
content: string
|
content?: string
|
||||||
inverted?: boolean
|
inverted?: boolean
|
||||||
|
onPress?: () => void
|
||||||
|
dropdown?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for Android mostly
|
// Used for Android mostly
|
||||||
const HeaderCenter = React.memo(
|
const HeaderCenter: React.FC<Props> = ({
|
||||||
({ content, inverted = false }: Props) => {
|
content,
|
||||||
const { colors } = useTheme()
|
inverted = false,
|
||||||
|
onPress,
|
||||||
|
dropdown = false
|
||||||
|
}) => {
|
||||||
|
const { colors } = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<CustomText
|
<CustomText
|
||||||
style={{
|
style={{
|
||||||
fontSize: 18,
|
|
||||||
color: inverted ? colors.primaryOverlay : colors.primaryDefault
|
color: inverted ? colors.primaryOverlay : colors.primaryDefault
|
||||||
}}
|
}}
|
||||||
|
fontSize='L'
|
||||||
fontWeight='Bold'
|
fontWeight='Bold'
|
||||||
|
numberOfLines={1}
|
||||||
children={content}
|
children={content}
|
||||||
|
{...(onPress && { onPress })}
|
||||||
/>
|
/>
|
||||||
)
|
{dropdown ? (
|
||||||
},
|
<Icon
|
||||||
(prev, next) => prev.content === next.content
|
name='ChevronDown'
|
||||||
)
|
size={StyleConstants.Font.Size.M}
|
||||||
|
color={colors.primaryDefault}
|
||||||
|
style={{ marginLeft: StyleConstants.Spacing.XS }}
|
||||||
|
strokeWidth={3}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default HeaderCenter
|
export default HeaderCenter
|
||||||
|
@ -4,7 +4,6 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
|||||||
import React, {
|
import React, {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
useCallback,
|
|
||||||
useEffect,
|
useEffect,
|
||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
@ -81,10 +80,6 @@ const Input: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
: { start: 0, end: 0 }
|
: { start: 0, end: 0 }
|
||||||
)
|
)
|
||||||
const onSelectionChange = useCallback(
|
|
||||||
({ nativeEvent: { selection } }) => (selectionRange.current = selection),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
const [inputFocused, setInputFocused] = useState(false)
|
const [inputFocused, setInputFocused] = useState(false)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -128,7 +123,9 @@ const Input: React.FC<Props> = ({
|
|||||||
: undefined
|
: undefined
|
||||||
}}
|
}}
|
||||||
onChangeText={setValue}
|
onChangeText={setValue}
|
||||||
onSelectionChange={onSelectionChange}
|
onSelectionChange={({ nativeEvent: { selection } }) =>
|
||||||
|
(selectionRange.current = selection)
|
||||||
|
}
|
||||||
value={value}
|
value={value}
|
||||||
{...(multiline && {
|
{...(multiline && {
|
||||||
multiline,
|
multiline,
|
||||||
|
@ -88,21 +88,6 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
}, [domain])
|
}, [domain])
|
||||||
|
|
||||||
const onSubmitEditing = useCallback(
|
|
||||||
({ nativeEvent: { text } }) => {
|
|
||||||
analytics('instance_textinput_submit', { match: text === domain })
|
|
||||||
if (
|
|
||||||
text === domain &&
|
|
||||||
instanceQuery.isSuccess &&
|
|
||||||
instanceQuery.data &&
|
|
||||||
instanceQuery.data.uri
|
|
||||||
) {
|
|
||||||
processUpdate()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[domain, instanceQuery.isSuccess, instanceQuery.data]
|
|
||||||
)
|
|
||||||
|
|
||||||
const requestAuth = useMemo(() => {
|
const requestAuth = useMemo(() => {
|
||||||
if (
|
if (
|
||||||
domain &&
|
domain &&
|
||||||
@ -180,7 +165,17 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
clearButtonMode='never'
|
clearButtonMode='never'
|
||||||
keyboardType='url'
|
keyboardType='url'
|
||||||
textContentType='URL'
|
textContentType='URL'
|
||||||
onSubmitEditing={onSubmitEditing}
|
onSubmitEditing={({ nativeEvent: { text } }) => {
|
||||||
|
analytics('instance_textinput_submit', { match: text === domain })
|
||||||
|
if (
|
||||||
|
text === domain &&
|
||||||
|
instanceQuery.isSuccess &&
|
||||||
|
instanceQuery.data &&
|
||||||
|
instanceQuery.data.uri
|
||||||
|
) {
|
||||||
|
processUpdate()
|
||||||
|
}
|
||||||
|
}}
|
||||||
placeholder={' ' + t('server.textInput.placeholder')}
|
placeholder={' ' + t('server.textInput.placeholder')}
|
||||||
placeholderTextColor={colors.secondary}
|
placeholderTextColor={colors.secondary}
|
||||||
returnKeyType='go'
|
returnKeyType='go'
|
||||||
|
@ -80,7 +80,7 @@ const displayMessage = ({
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
showMessage({
|
showMessage({
|
||||||
duration: type === 'error' ? 3500 : duration === 'short' ? 1500 : 2500,
|
duration: type === 'error' ? 8000 : duration === 'short' ? 3000 : 5000,
|
||||||
autoHide,
|
autoHide,
|
||||||
message,
|
message,
|
||||||
description,
|
description,
|
||||||
@ -124,7 +124,8 @@ const Message = React.forwardRef<FlashMessage>((_, ref) => {
|
|||||||
shadowColor: colors.primaryDefault,
|
shadowColor: colors.primaryDefault,
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowOpacity: theme === 'light' ? 0.16 : 0.24,
|
shadowOpacity: theme === 'light' ? 0.16 : 0.24,
|
||||||
shadowRadius: 4
|
shadowRadius: 4,
|
||||||
|
paddingRight: StyleConstants.Spacing.M * 2
|
||||||
}}
|
}}
|
||||||
titleStyle={{
|
titleStyle={{
|
||||||
color: colors.primaryDefault,
|
color: colors.primaryDefault,
|
||||||
|
@ -215,7 +215,7 @@ const ParseHTML = React.memo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const renderNodeCallback = useCallback(
|
const renderNodeCallback = useCallback(
|
||||||
(node, index) =>
|
(node: any, index: any) =>
|
||||||
renderNode({
|
renderNode({
|
||||||
routeParams: route.params,
|
routeParams: route.params,
|
||||||
colors,
|
colors,
|
||||||
@ -231,7 +231,7 @@ const ParseHTML = React.memo(
|
|||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
const textComponent = useCallback(({ children }) => {
|
const textComponent = useCallback(({ children }: any) => {
|
||||||
if (children) {
|
if (children) {
|
||||||
return (
|
return (
|
||||||
<ParseEmojis
|
<ParseEmojis
|
||||||
@ -246,42 +246,26 @@ const ParseHTML = React.memo(
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
const rootComponent = useCallback(
|
const rootComponent = useCallback(
|
||||||
({ children }) => {
|
({ children }: any) => {
|
||||||
const { t } = useTranslation('componentParse')
|
const { t } = useTranslation('componentParse')
|
||||||
|
|
||||||
const [expandAllow, setExpandAllow] = useState(false)
|
const [totalLines, setTotalLines] = useState<number>()
|
||||||
const [expanded, setExpanded] = useState(highlighted)
|
const [expanded, setExpanded] = useState(highlighted)
|
||||||
|
|
||||||
const onTextLayout = useCallback(({ nativeEvent }) => {
|
|
||||||
if (
|
|
||||||
numberOfLines === 1 ||
|
|
||||||
nativeEvent.lines.length >= numberOfLines + 5
|
|
||||||
) {
|
|
||||||
setExpandAllow(true)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ overflow: 'hidden' }}>
|
<View style={{ overflow: 'hidden' }}>
|
||||||
<CustomText
|
{typeof totalLines === 'number' ? (
|
||||||
children={children}
|
|
||||||
onTextLayout={onTextLayout}
|
|
||||||
numberOfLines={
|
|
||||||
expandAllow ? (expanded ? 999 : numberOfLines) : undefined
|
|
||||||
}
|
|
||||||
selectable={selectable}
|
|
||||||
/>
|
|
||||||
{expandAllow ? (
|
|
||||||
<Pressable
|
<Pressable
|
||||||
accessibilityLabel=''
|
accessibilityLabel={t('HTML.accessibilityHint')}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
analytics('status_readmore', { allow: expandAllow, expanded })
|
analytics('status_readmore', { totalLines, expanded })
|
||||||
layoutAnimation()
|
layoutAnimation()
|
||||||
setExpanded(!expanded)
|
setExpanded(!expanded)
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginTop: expanded ? 0 : -adaptedLineheight,
|
alignItems: 'center',
|
||||||
minHeight: 44,
|
minHeight: 44,
|
||||||
backgroundColor: colors.backgroundDefault
|
backgroundColor: colors.backgroundDefault
|
||||||
}}
|
}}
|
||||||
@ -290,14 +274,47 @@ const ParseHTML = React.memo(
|
|||||||
style={{
|
style={{
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
...StyleConstants.FontStyle.S,
|
...StyleConstants.FontStyle.S,
|
||||||
color: colors.primaryDefault
|
color: colors.primaryDefault,
|
||||||
|
marginRight: StyleConstants.Spacing.S
|
||||||
}}
|
}}
|
||||||
children={t(`HTML.expanded.${expanded.toString()}`, {
|
children={t('HTML.expanded', {
|
||||||
hint: expandHint
|
hint: expandHint,
|
||||||
|
totalLines:
|
||||||
|
numberOfLines > 1 && typeof totalLines === 'number'
|
||||||
|
? t('HTML.totalLines', { count: totalLines })
|
||||||
|
: ''
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
<Icon
|
||||||
|
name={expanded ? 'Minimize2' : 'Maximize2'}
|
||||||
|
color={colors.primaryDefault}
|
||||||
|
strokeWidth={2}
|
||||||
|
size={StyleConstants.Font.Size[size]}
|
||||||
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
) : null}
|
) : null}
|
||||||
|
<CustomText
|
||||||
|
children={children}
|
||||||
|
onTextLayout={({ nativeEvent }) => {
|
||||||
|
if (
|
||||||
|
numberOfLines === 1 ||
|
||||||
|
nativeEvent.lines.length >= numberOfLines + 5
|
||||||
|
) {
|
||||||
|
setTotalLines(nativeEvent.lines.length)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
height: numberOfLines === 1 && !expanded ? 0 : undefined
|
||||||
|
}}
|
||||||
|
numberOfLines={
|
||||||
|
typeof totalLines === 'number'
|
||||||
|
? expanded
|
||||||
|
? 999
|
||||||
|
: numberOfLines
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
selectable={selectable}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -64,17 +64,6 @@ const Timeline: React.FC<Props> = ({
|
|||||||
? data.pages?.flatMap(page => [...page.body])
|
? data.pages?.flatMap(page => [...page.body])
|
||||||
: []
|
: []
|
||||||
|
|
||||||
const ItemSeparatorComponent = useCallback(
|
|
||||||
({ leadingItem }) =>
|
|
||||||
queryKey[1].page === 'Toot' && queryKey[1].toot === leadingItem.id ? (
|
|
||||||
<ComponentSeparator extraMarginLeft={0} />
|
|
||||||
) : (
|
|
||||||
<ComponentSeparator
|
|
||||||
extraMarginLeft={StyleConstants.Avatar.M + StyleConstants.Spacing.S}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
const onEndReached = useCallback(
|
const onEndReached = useCallback(
|
||||||
() => !disableInfinity && !isFetchingNextPage && fetchNextPage(),
|
() => !disableInfinity && !isFetchingNextPage && fetchNextPage(),
|
||||||
[isFetchingNextPage]
|
[isFetchingNextPage]
|
||||||
@ -151,7 +140,17 @@ const Timeline: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
ListEmptyComponent={<TimelineEmpty queryKey={queryKey} />}
|
ListEmptyComponent={<TimelineEmpty queryKey={queryKey} />}
|
||||||
ItemSeparatorComponent={ItemSeparatorComponent}
|
ItemSeparatorComponent={({ leadingItem }) =>
|
||||||
|
queryKey[1].page === 'Toot' && queryKey[1].toot === leadingItem.id ? (
|
||||||
|
<ComponentSeparator extraMarginLeft={0} />
|
||||||
|
) : (
|
||||||
|
<ComponentSeparator
|
||||||
|
extraMarginLeft={
|
||||||
|
StyleConstants.Avatar.M + StyleConstants.Spacing.S
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
maintainVisibleContentPosition={
|
maintainVisibleContentPosition={
|
||||||
isFetching
|
isFetching
|
||||||
? {
|
? {
|
||||||
|
@ -5,6 +5,7 @@ import TimelineAttachment from '@components/Timeline/Shared/Attachment'
|
|||||||
import TimelineAvatar from '@components/Timeline/Shared/Avatar'
|
import TimelineAvatar from '@components/Timeline/Shared/Avatar'
|
||||||
import TimelineCard from '@components/Timeline/Shared/Card'
|
import TimelineCard from '@components/Timeline/Shared/Card'
|
||||||
import TimelineContent from '@components/Timeline/Shared/Content'
|
import TimelineContent from '@components/Timeline/Shared/Content'
|
||||||
|
// @ts-ignore
|
||||||
import TimelineHeaderDefault from '@components/Timeline/Shared/HeaderDefault'
|
import TimelineHeaderDefault from '@components/Timeline/Shared/HeaderDefault'
|
||||||
import TimelinePoll from '@components/Timeline/Shared/Poll'
|
import TimelinePoll from '@components/Timeline/Shared/Poll'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
@ -15,7 +16,7 @@ import { getInstanceAccount } from '@utils/slices/instancesSlice'
|
|||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { uniqBy } from 'lodash'
|
import { uniqBy } from 'lodash'
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback, useEffect, useRef } from 'react'
|
||||||
import { Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import TimelineContextMenu from './Shared/ContextMenu'
|
import TimelineContextMenu from './Shared/ContextMenu'
|
||||||
@ -53,10 +54,15 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
|
|
||||||
const ownAccount = actualStatus.account?.id === instanceAccount?.id
|
const ownAccount = actualStatus.account?.id === instanceAccount?.id
|
||||||
|
|
||||||
|
const copiableContent = useRef<{ content: string; complete: boolean }>({
|
||||||
|
content: '',
|
||||||
|
complete: false
|
||||||
|
})
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!highlighted &&
|
!highlighted &&
|
||||||
queryKey &&
|
queryKey &&
|
||||||
shouldFilter({ status: actualStatus, queryKey })
|
shouldFilter({ copiableContent, status: actualStatus, queryKey })
|
||||||
) {
|
) {
|
||||||
return <TimelineFiltered />
|
return <TimelineFiltered />
|
||||||
}
|
}
|
||||||
@ -75,10 +81,10 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<TimelineContextMenu
|
<TimelineContextMenu
|
||||||
|
copiableContent={copiableContent}
|
||||||
status={actualStatus}
|
status={actualStatus}
|
||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
rootQueryKey={rootQueryKey}
|
rootQueryKey={rootQueryKey}
|
||||||
disabled={highlighted}
|
|
||||||
>
|
>
|
||||||
<Pressable
|
<Pressable
|
||||||
accessible={highlighted ? false : true}
|
accessible={highlighted ? false : true}
|
||||||
|
@ -5,6 +5,7 @@ import TimelineAttachment from '@components/Timeline/Shared/Attachment'
|
|||||||
import TimelineAvatar from '@components/Timeline/Shared/Avatar'
|
import TimelineAvatar from '@components/Timeline/Shared/Avatar'
|
||||||
import TimelineCard from '@components/Timeline/Shared/Card'
|
import TimelineCard from '@components/Timeline/Shared/Card'
|
||||||
import TimelineContent from '@components/Timeline/Shared/Content'
|
import TimelineContent from '@components/Timeline/Shared/Content'
|
||||||
|
// @ts-ignore
|
||||||
import TimelineHeaderNotification from '@components/Timeline/Shared/HeaderNotification'
|
import TimelineHeaderNotification from '@components/Timeline/Shared/HeaderNotification'
|
||||||
import TimelinePoll from '@components/Timeline/Shared/Poll'
|
import TimelinePoll from '@components/Timeline/Shared/Poll'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
@ -15,7 +16,7 @@ import { getInstanceAccount } from '@utils/slices/instancesSlice'
|
|||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { isEqual, uniqBy } from 'lodash'
|
import { isEqual, uniqBy } from 'lodash'
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback, useRef } from 'react'
|
||||||
import { Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import TimelineContextMenu from './Shared/ContextMenu'
|
import TimelineContextMenu from './Shared/ContextMenu'
|
||||||
@ -30,9 +31,14 @@ export interface Props {
|
|||||||
|
|
||||||
const TimelineNotifications = React.memo(
|
const TimelineNotifications = React.memo(
|
||||||
({ notification, queryKey, highlighted = false }: Props) => {
|
({ notification, queryKey, highlighted = false }: Props) => {
|
||||||
|
const copiableContent = useRef<{ content: string; complete: boolean }>({
|
||||||
|
content: '',
|
||||||
|
complete: false
|
||||||
|
})
|
||||||
|
|
||||||
if (
|
if (
|
||||||
notification.status &&
|
notification.status &&
|
||||||
shouldFilter({ status: notification.status, queryKey })
|
shouldFilter({ copiableContent, status: notification.status, queryKey })
|
||||||
) {
|
) {
|
||||||
return <TimelineFiltered />
|
return <TimelineFiltered />
|
||||||
}
|
}
|
||||||
@ -60,9 +66,9 @@ const TimelineNotifications = React.memo(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<TimelineContextMenu
|
<TimelineContextMenu
|
||||||
|
copiableContent={copiableContent}
|
||||||
status={notification.status}
|
status={notification.status}
|
||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
disabled={highlighted}
|
|
||||||
>
|
>
|
||||||
<Pressable
|
<Pressable
|
||||||
style={{
|
style={{
|
||||||
|
@ -9,7 +9,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { RefObject, useCallback, useRef, useState } from 'react'
|
import React, { RefObject, useCallback, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, Platform, StyleSheet, Text, View } from 'react-native'
|
import { FlatList, LayoutChangeEvent, Platform, StyleSheet, Text, View } from 'react-native'
|
||||||
import { Circle } from 'react-native-animated-spinkit'
|
import { Circle } from 'react-native-animated-spinkit'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
Extrapolate,
|
Extrapolate,
|
||||||
@ -169,7 +169,7 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
|
|
||||||
const arrowStage = useSharedValue(0)
|
const arrowStage = useSharedValue(0)
|
||||||
const onLayout = useCallback(
|
const onLayout = useCallback(
|
||||||
({ nativeEvent }) => {
|
({ nativeEvent }: LayoutChangeEvent) => {
|
||||||
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
|
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
|
||||||
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
|
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
|
||||||
}
|
}
|
||||||
|
@ -47,20 +47,6 @@ const TimelineAttachment = React.memo(
|
|||||||
>([])
|
>([])
|
||||||
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
|
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
|
||||||
const navigateToImagesViewer = (id: string) => {
|
const navigateToImagesViewer = (id: string) => {
|
||||||
status.media_attachments.forEach(attachment => {
|
|
||||||
switch (attachment.type) {
|
|
||||||
case 'image':
|
|
||||||
imageUrls.current.push({
|
|
||||||
id: attachment.id,
|
|
||||||
preview_url: attachment.preview_url,
|
|
||||||
url: attachment.url,
|
|
||||||
remote_url: attachment.remote_url,
|
|
||||||
blurhash: attachment.blurhash,
|
|
||||||
width: attachment.meta?.original?.width,
|
|
||||||
height: attachment.meta?.original?.height
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
navigation.navigate('Screen-ImagesViewer', {
|
navigation.navigate('Screen-ImagesViewer', {
|
||||||
imageUrls: imageUrls.current,
|
imageUrls: imageUrls.current,
|
||||||
id
|
id
|
||||||
@ -82,6 +68,15 @@ const TimelineAttachment = React.memo(
|
|||||||
{status.media_attachments.map((attachment, index) => {
|
{status.media_attachments.map((attachment, index) => {
|
||||||
switch (attachment.type) {
|
switch (attachment.type) {
|
||||||
case 'image':
|
case 'image':
|
||||||
|
imageUrls.current.push({
|
||||||
|
id: attachment.id,
|
||||||
|
preview_url: attachment.preview_url,
|
||||||
|
url: attachment.url,
|
||||||
|
remote_url: attachment.remote_url,
|
||||||
|
blurhash: attachment.blurhash,
|
||||||
|
width: attachment.meta?.original?.width,
|
||||||
|
height: attachment.meta?.original?.height
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<AttachmentImage
|
<AttachmentImage
|
||||||
key={index}
|
key={index}
|
||||||
|
@ -99,6 +99,7 @@ const AttachmentVideo: React.FC<Props> = ({
|
|||||||
opacity: sensitiveShown ? 0 : 1
|
opacity: sensitiveShown ? 0 : 1
|
||||||
}}
|
}}
|
||||||
usePoster
|
usePoster
|
||||||
|
resizeMode={ResizeMode.COVER}
|
||||||
{...(gifv
|
{...(gifv
|
||||||
? {
|
? {
|
||||||
shouldPlay: true,
|
shouldPlay: true,
|
||||||
@ -107,7 +108,6 @@ const AttachmentVideo: React.FC<Props> = ({
|
|||||||
source: { uri: video.url }
|
source: { uri: video.url }
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
resizeMode: ResizeMode.COVER,
|
|
||||||
posterSource: { uri: video.preview_url },
|
posterSource: { uri: video.preview_url },
|
||||||
posterStyle: { resizeMode: ResizeMode.COVER }
|
posterStyle: { resizeMode: ResizeMode.COVER }
|
||||||
})}
|
})}
|
||||||
|
@ -38,7 +38,6 @@ const TimelineContent = React.memo(
|
|||||||
numberOfLines={999}
|
numberOfLines={999}
|
||||||
highlighted={highlighted}
|
highlighted={highlighted}
|
||||||
disableDetails={disableDetails}
|
disableDetails={disableDetails}
|
||||||
selectable={highlighted}
|
|
||||||
/>
|
/>
|
||||||
<ParseHTML
|
<ParseHTML
|
||||||
content={status.content}
|
content={status.content}
|
||||||
@ -53,7 +52,6 @@ const TimelineContent = React.memo(
|
|||||||
expandHint={t('shared.content.expandHint')}
|
expandHint={t('shared.content.expandHint')}
|
||||||
highlighted={highlighted}
|
highlighted={highlighted}
|
||||||
disableDetails={disableDetails}
|
disableDetails={disableDetails}
|
||||||
selectable={highlighted}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -66,7 +64,6 @@ const TimelineContent = React.memo(
|
|||||||
tags={status.tags}
|
tags={status.tags}
|
||||||
numberOfLines={highlighted ? 999 : numberOfLines}
|
numberOfLines={highlighted ? 999 : numberOfLines}
|
||||||
disableDetails={disableDetails}
|
disableDetails={disableDetails}
|
||||||
selectable={highlighted}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -12,23 +12,26 @@ import ContextMenu, {
|
|||||||
} from 'react-native-context-menu-view'
|
} from 'react-native-context-menu-view'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
copiableContent: React.MutableRefObject<{
|
||||||
|
content: string
|
||||||
|
complete: boolean
|
||||||
|
}>
|
||||||
status?: Mastodon.Status
|
status?: Mastodon.Status
|
||||||
queryKey?: QueryKeyTimeline
|
queryKey?: QueryKeyTimeline
|
||||||
rootQueryKey?: QueryKeyTimeline
|
rootQueryKey?: QueryKeyTimeline
|
||||||
disabled?: boolean // Allowing toot to be copied when highlighted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContextMenuContext = createContext<ContextMenuAction[]>([])
|
export const ContextMenuContext = createContext<ContextMenuAction[]>([])
|
||||||
|
|
||||||
const TimelineContextMenu: React.FC<Props & ContextMenuProps> = ({
|
const TimelineContextMenu: React.FC<Props & ContextMenuProps> = ({
|
||||||
children,
|
children,
|
||||||
|
copiableContent,
|
||||||
status,
|
status,
|
||||||
queryKey,
|
queryKey,
|
||||||
rootQueryKey,
|
rootQueryKey,
|
||||||
disabled,
|
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (!status || !queryKey || disabled || Platform.OS === 'android') {
|
if (!status || !queryKey || Platform.OS === 'android') {
|
||||||
return <>{children}</>
|
return <>{children}</>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +40,7 @@ const TimelineContextMenu: React.FC<Props & ContextMenuProps> = ({
|
|||||||
const shareOnPress =
|
const shareOnPress =
|
||||||
status.visibility !== 'direct'
|
status.visibility !== 'direct'
|
||||||
? contextMenuShare({
|
? contextMenuShare({
|
||||||
|
copiableContent,
|
||||||
actions,
|
actions,
|
||||||
type: 'status',
|
type: 'status',
|
||||||
url: status.url || status.uri
|
url: status.url || status.uri
|
||||||
|
@ -34,9 +34,14 @@ const TimelineFiltered = React.memo(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const shouldFilter = ({
|
export const shouldFilter = ({
|
||||||
|
copiableContent,
|
||||||
status,
|
status,
|
||||||
queryKey
|
queryKey
|
||||||
}: {
|
}: {
|
||||||
|
copiableContent: React.MutableRefObject<{
|
||||||
|
content: string
|
||||||
|
complete: boolean
|
||||||
|
}>
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
queryKey: QueryKeyTimeline
|
queryKey: QueryKeyTimeline
|
||||||
}) => {
|
}) => {
|
||||||
@ -48,6 +53,11 @@ export const shouldFilter = ({
|
|||||||
if (!ownAccount) {
|
if (!ownAccount) {
|
||||||
const parser = new htmlparser2.Parser({
|
const parser = new htmlparser2.Parser({
|
||||||
ontext: (text: string) => {
|
ontext: (text: string) => {
|
||||||
|
if (!copiableContent.current.complete) {
|
||||||
|
copiableContent.current.content =
|
||||||
|
copiableContent.current.content + text
|
||||||
|
}
|
||||||
|
|
||||||
const checkFilter = (filter: Mastodon.Filter) => {
|
const checkFilter = (filter: Mastodon.Filter) => {
|
||||||
const escapedPhrase = filter.phrase.replace(
|
const escapedPhrase = filter.phrase.replace(
|
||||||
/[.*+?^${}()|[\]\\]/g,
|
/[.*+?^${}()|[\]\\]/g,
|
||||||
@ -103,6 +113,7 @@ export const shouldFilter = ({
|
|||||||
status.spoiler_text && parser.write(status.spoiler_text)
|
status.spoiler_text && parser.write(status.spoiler_text)
|
||||||
parser.write(status.content)
|
parser.write(status.content)
|
||||||
parser.end()
|
parser.end()
|
||||||
|
copiableContent.current.complete = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldFilter
|
return shouldFilter
|
||||||
|
@ -6,11 +6,10 @@ import Icon from '@components/Icon'
|
|||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useContext } from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Platform, Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import ContextMenu, { ContextMenuAction } from 'react-native-context-menu-view'
|
import ContextMenu, { ContextMenuAction } from 'react-native-context-menu-view'
|
||||||
import { ContextMenuContext } from './ContextMenu'
|
|
||||||
import HeaderSharedAccount from './HeaderShared/Account'
|
import HeaderSharedAccount from './HeaderShared/Account'
|
||||||
import HeaderSharedApplication from './HeaderShared/Application'
|
import HeaderSharedApplication from './HeaderShared/Application'
|
||||||
import HeaderSharedCreated from './HeaderShared/Created'
|
import HeaderSharedCreated from './HeaderShared/Created'
|
||||||
@ -93,7 +92,6 @@ const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => {
|
|||||||
dropdownMenuMode
|
dropdownMenuMode
|
||||||
actions={actions}
|
actions={actions}
|
||||||
onPress={({ nativeEvent: { index } }) => {
|
onPress={({ nativeEvent: { index } }) => {
|
||||||
console.log('index', index)
|
|
||||||
for (const on of [
|
for (const on of [
|
||||||
shareOnPress,
|
shareOnPress,
|
||||||
statusOnPress,
|
statusOnPress,
|
||||||
@ -110,6 +108,7 @@ const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => {
|
|||||||
size={StyleConstants.Font.Size.L}
|
size={StyleConstants.Font.Size.L}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -4,7 +4,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Platform, Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import ContextMenu from 'react-native-context-menu-view'
|
import ContextMenu from 'react-native-context-menu-view'
|
||||||
import { ContextMenuContext } from './ContextMenu'
|
import { ContextMenuContext } from './ContextMenu'
|
||||||
import HeaderSharedAccount from './HeaderShared/Account'
|
import HeaderSharedAccount from './HeaderShared/Account'
|
||||||
@ -48,7 +48,7 @@ const TimelineHeaderDefault = ({ queryKey, status, highlighted }: Props) => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{queryKey && !highlighted ? (
|
{queryKey ? (
|
||||||
<Pressable
|
<Pressable
|
||||||
accessibilityHint={t('accessibilityHint')}
|
accessibilityHint={t('accessibilityHint')}
|
||||||
style={{
|
style={{
|
||||||
|
@ -20,7 +20,7 @@ import HeaderSharedMuted from './HeaderShared/Muted'
|
|||||||
import HeaderSharedVisibility from './HeaderShared/Visibility'
|
import HeaderSharedVisibility from './HeaderShared/Visibility'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
queryKey?: QueryKeyTimeline
|
queryKey: QueryKeyTimeline
|
||||||
notification: Mastodon.Notification
|
notification: Mastodon.Notification
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,18 +39,18 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => {
|
|||||||
: null
|
: null
|
||||||
const statusOnPress = contextMenuStatus({
|
const statusOnPress = contextMenuStatus({
|
||||||
actions: contextMenuActions,
|
actions: contextMenuActions,
|
||||||
status,
|
status: status!,
|
||||||
queryKey
|
queryKey
|
||||||
})
|
})
|
||||||
const accountOnPress = contextMenuAccount({
|
const accountOnPress = contextMenuAccount({
|
||||||
actions: contextMenuActions,
|
actions: contextMenuActions,
|
||||||
type: 'status',
|
type: 'status',
|
||||||
queryKey,
|
queryKey,
|
||||||
id: status?.account.id
|
id: status!.account.id
|
||||||
})
|
})
|
||||||
const instanceOnPress = contextMenuInstance({
|
const instanceOnPress = contextMenuInstance({
|
||||||
actions: contextMenuActions,
|
actions: contextMenuActions,
|
||||||
status,
|
status: status!,
|
||||||
queryKey
|
queryKey
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -91,6 +91,7 @@ const TimelineHeaderNotification = ({ queryKey, notification }: Props) => {
|
|||||||
size={StyleConstants.Font.Size.L}
|
size={StyleConstants.Font.Size.L}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -141,13 +141,7 @@ const TimelineTranslate = React.memo(
|
|||||||
</Pressable>
|
</Pressable>
|
||||||
{data && data.error === undefined
|
{data && data.error === undefined
|
||||||
? data.text.map((d, i) => (
|
? data.text.map((d, i) => (
|
||||||
<ParseHTML
|
<ParseHTML key={i} content={d} size={'M'} numberOfLines={999} />
|
||||||
key={i}
|
|
||||||
content={d}
|
|
||||||
size={'M'}
|
|
||||||
numberOfLines={999}
|
|
||||||
selectable
|
|
||||||
/>
|
|
||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
</>
|
</>
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import analytics from '@components/analytics'
|
|
||||||
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
|
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
|
||||||
import { store } from '@root/store'
|
import { store } from '@root/store'
|
||||||
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
|
import { getInstanceConfigurationStatusMaxAttachments } from '@utils/slices/instancesSlice'
|
||||||
import { manipulateAsync, SaveFormat } from 'expo-image-manipulator'
|
|
||||||
import * as ExpoImagePicker from 'expo-image-picker'
|
|
||||||
import i18next from 'i18next'
|
import i18next from 'i18next'
|
||||||
import { Alert, Linking, Platform } from 'react-native'
|
import { Asset, launchImageLibrary } from 'react-native-image-picker'
|
||||||
import ImagePicker, {
|
|
||||||
Image,
|
|
||||||
ImageOrVideo
|
|
||||||
} from 'react-native-image-crop-picker'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
mediaType?: 'photo' | 'video'
|
mediaType?: 'photo' | 'video'
|
||||||
@ -28,43 +21,7 @@ const mediaSelector = async ({
|
|||||||
maximum,
|
maximum,
|
||||||
indicateMaximum = false,
|
indicateMaximum = false,
|
||||||
showActionSheetWithOptions
|
showActionSheetWithOptions
|
||||||
}: Props): Promise<({ uri: string } & Omit<ImageOrVideo, 'path'>)[]> => {
|
}: Props): Promise<Asset[]> => {
|
||||||
const checkLibraryPermission = async (): Promise<boolean> => {
|
|
||||||
const { status } =
|
|
||||||
await ExpoImagePicker.requestMediaLibraryPermissionsAsync()
|
|
||||||
if (status !== 'granted') {
|
|
||||||
Alert.alert(
|
|
||||||
i18next.t('componentMediaSelector:library.alert.title'),
|
|
||||||
i18next.t('componentMediaSelector:library.alert.message'),
|
|
||||||
[
|
|
||||||
{
|
|
||||||
text: i18next.t('common:buttons.cancel'),
|
|
||||||
style: 'cancel',
|
|
||||||
onPress: () =>
|
|
||||||
analytics('mediaSelector_nopermission', {
|
|
||||||
action: 'cancel'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: i18next.t(
|
|
||||||
'componentMediaSelector:library.alert.buttons.settings'
|
|
||||||
),
|
|
||||||
style: 'default',
|
|
||||||
onPress: () => {
|
|
||||||
analytics('mediaSelector_nopermission', {
|
|
||||||
action: 'settings'
|
|
||||||
})
|
|
||||||
Linking.openURL('app-settings:')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _maximum =
|
const _maximum =
|
||||||
maximum ||
|
maximum ||
|
||||||
getInstanceConfigurationStatusMaxAttachments(store.getState()) ||
|
getInstanceConfigurationStatusMaxAttachments(store.getState()) ||
|
||||||
@ -105,79 +62,30 @@ const mediaSelector = async ({
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const selectImage = async () => {
|
const selectImage = async () => {
|
||||||
const images = await ImagePicker.openPicker({
|
const images = await launchImageLibrary({
|
||||||
mediaType: 'photo',
|
mediaType: 'photo',
|
||||||
includeExif: false,
|
...(resize && { maxWidth: resize.width, maxHeight: resize.height }),
|
||||||
multiple: true,
|
includeBase64: false,
|
||||||
minFiles: 1,
|
includeExtra: false,
|
||||||
maxFiles: _maximum,
|
selectionLimit: _maximum
|
||||||
smartAlbums: ['UserLibrary'],
|
})
|
||||||
writeTempFile: false,
|
|
||||||
loadingLabelText: ''
|
|
||||||
}).catch(() => {})
|
|
||||||
|
|
||||||
if (!images) {
|
if (!images.assets) {
|
||||||
return reject()
|
return reject()
|
||||||
}
|
}
|
||||||
|
|
||||||
// react-native-image-crop-picker may return HEIC as JPG that causes upload failure
|
return resolve(images.assets)
|
||||||
if (Platform.OS === 'ios') {
|
|
||||||
for (const [index, image] of images.entries()) {
|
|
||||||
if (image.mime === 'image/heic') {
|
|
||||||
const converted = await manipulateAsync(image.sourceURL!, [], {
|
|
||||||
base64: false,
|
|
||||||
compress: 0.8,
|
|
||||||
format: SaveFormat.JPEG
|
|
||||||
})
|
|
||||||
images[index] = {
|
|
||||||
...images[index],
|
|
||||||
sourceURL: converted.uri,
|
|
||||||
mime: 'image/jpeg'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resize) {
|
|
||||||
return resolve(
|
|
||||||
images.map(image => ({
|
|
||||||
...image,
|
|
||||||
uri: image.sourceURL || `file://${image.path}`
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
const croppedImages: Image[] = []
|
|
||||||
for (const image of images) {
|
|
||||||
const croppedImage = await ImagePicker.openCropper({
|
|
||||||
mediaType: 'photo',
|
|
||||||
path: image.sourceURL || image.path,
|
|
||||||
width: resize.width,
|
|
||||||
height: resize.height,
|
|
||||||
cropperChooseText: i18next.t('common:buttons.apply'),
|
|
||||||
cropperCancelText: i18next.t('common:buttons.cancel'),
|
|
||||||
hideBottomControls: true
|
|
||||||
}).catch(() => {})
|
|
||||||
croppedImage && croppedImages.push(croppedImage)
|
|
||||||
}
|
|
||||||
return resolve(
|
|
||||||
croppedImages.map(image => ({
|
|
||||||
...image,
|
|
||||||
uri: `file://${image.path}`
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const selectVideo = async () => {
|
const selectVideo = async () => {
|
||||||
const video = await ImagePicker.openPicker({
|
const video = await launchImageLibrary({
|
||||||
mediaType: 'video',
|
mediaType: 'video',
|
||||||
includeExif: false,
|
includeBase64: false,
|
||||||
loadingLabelText: ''
|
includeExtra: false,
|
||||||
}).catch(() => {})
|
selectionLimit: 1
|
||||||
|
})
|
||||||
|
|
||||||
if (video) {
|
if (video.assets?.[0]) {
|
||||||
return resolve([
|
return resolve(video.assets)
|
||||||
{ ...video, uri: video.sourceURL || `file://${video.path}` }
|
|
||||||
])
|
|
||||||
} else {
|
} else {
|
||||||
return reject()
|
return reject()
|
||||||
}
|
}
|
||||||
@ -189,10 +97,6 @@ const mediaSelector = async ({
|
|||||||
cancelButtonIndex: mediaType ? 1 : 2
|
cancelButtonIndex: mediaType ? 1 : 2
|
||||||
},
|
},
|
||||||
async buttonIndex => {
|
async buttonIndex => {
|
||||||
if (!(await checkLibraryPermission())) {
|
|
||||||
return reject()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mediaType) {
|
switch (mediaType) {
|
||||||
case 'photo':
|
case 'photo':
|
||||||
if (buttonIndex === 0) {
|
if (buttonIndex === 0) {
|
||||||
|
@ -1,149 +0,0 @@
|
|||||||
import { store } from '@root/store'
|
|
||||||
import { getInstanceConfigurationMediaAttachments } from '@utils/slices/instancesSlice'
|
|
||||||
import { Action, manipulateAsync, SaveFormat } from 'expo-image-manipulator'
|
|
||||||
import i18next from 'i18next'
|
|
||||||
import { Platform } from 'react-native'
|
|
||||||
import ImagePicker from 'react-native-image-crop-picker'
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
type: 'image' | 'video'
|
|
||||||
uri: string // This can be pure path or uri starting with file://
|
|
||||||
mime?: string
|
|
||||||
transform: {
|
|
||||||
imageFormat?: SaveFormat.JPEG | SaveFormat.PNG
|
|
||||||
resize?: boolean
|
|
||||||
width?: number
|
|
||||||
height?: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFileExtension = (uri: string) => {
|
|
||||||
const extension = uri.split('.').pop()
|
|
||||||
// Using mime type standard of jpeg
|
|
||||||
return extension === 'jpg' ? 'jpeg' : extension
|
|
||||||
}
|
|
||||||
|
|
||||||
const mediaTransformation = async ({
|
|
||||||
type,
|
|
||||||
uri,
|
|
||||||
mime,
|
|
||||||
transform
|
|
||||||
}: Props): Promise<{
|
|
||||||
uri: string
|
|
||||||
mime: string
|
|
||||||
width: number
|
|
||||||
height: number
|
|
||||||
}> => {
|
|
||||||
const configurationMediaAttachments =
|
|
||||||
getInstanceConfigurationMediaAttachments(store.getState())
|
|
||||||
|
|
||||||
const fileExtension = getFileExtension(uri)
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'image':
|
|
||||||
if (mime === 'image/gif' || fileExtension === 'gif') {
|
|
||||||
return Promise.reject('GIFs should not be transformed')
|
|
||||||
}
|
|
||||||
let targetFormat: SaveFormat.JPEG | SaveFormat.PNG = SaveFormat.JPEG
|
|
||||||
|
|
||||||
const supportedImageTypes =
|
|
||||||
configurationMediaAttachments.supported_mime_types.filter(mime =>
|
|
||||||
mime.startsWith('image/')
|
|
||||||
)
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const transformations: Action[] = [
|
|
||||||
!transform.resize && (transform.width || transform.height)
|
|
||||||
? {
|
|
||||||
resize: { width: transform.width, height: transform.height }
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
].filter(t => !!t)
|
|
||||||
|
|
||||||
if (mime) {
|
|
||||||
if (
|
|
||||||
mime !== `image/${fileExtension}` ||
|
|
||||||
!supportedImageTypes.includes(mime)
|
|
||||||
) {
|
|
||||||
targetFormat = transform.imageFormat || SaveFormat.JPEG
|
|
||||||
} else {
|
|
||||||
targetFormat = mime.split('/').pop() as any
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!fileExtension) {
|
|
||||||
return Promise.reject('Unable to get file extension')
|
|
||||||
}
|
|
||||||
if (!supportedImageTypes.includes(`image/${fileExtension}`)) {
|
|
||||||
targetFormat = transform.imageFormat || SaveFormat.JPEG
|
|
||||||
} else {
|
|
||||||
targetFormat = fileExtension as any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const converted = await manipulateAsync(uri, transformations, {
|
|
||||||
base64: false,
|
|
||||||
compress: Platform.OS === 'ios' ? 0.8 : 1,
|
|
||||||
format: targetFormat
|
|
||||||
})
|
|
||||||
|
|
||||||
if (transform.resize) {
|
|
||||||
const resized = await ImagePicker.openCropper({
|
|
||||||
mediaType: 'photo',
|
|
||||||
path: converted.uri,
|
|
||||||
width: transform.width,
|
|
||||||
height: transform.height,
|
|
||||||
cropperChooseText: i18next.t('common:buttons.apply'),
|
|
||||||
cropperCancelText: i18next.t('common:buttons.cancel'),
|
|
||||||
hideBottomControls: true
|
|
||||||
})
|
|
||||||
if (!resized) {
|
|
||||||
return Promise.reject('Resize failed')
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
uri: resized.path,
|
|
||||||
mime: resized.mime,
|
|
||||||
width: resized.width,
|
|
||||||
height: resized.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
uri: converted.uri,
|
|
||||||
mime: transform.imageFormat || SaveFormat.JPEG,
|
|
||||||
width: converted.width,
|
|
||||||
height: converted.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 'video':
|
|
||||||
const supportedVideoTypes =
|
|
||||||
configurationMediaAttachments.supported_mime_types.filter(mime =>
|
|
||||||
mime.startsWith('video/')
|
|
||||||
)
|
|
||||||
|
|
||||||
if (mime) {
|
|
||||||
if (mime !== `video/${fileExtension}`) {
|
|
||||||
console.warn('Video mime type and file extension does not match')
|
|
||||||
}
|
|
||||||
if (!supportedVideoTypes.includes(mime)) {
|
|
||||||
return Promise.reject('Video file type is not supported')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!fileExtension) {
|
|
||||||
return Promise.reject('Unable to get file extension')
|
|
||||||
}
|
|
||||||
if (!supportedVideoTypes.includes(`video/${fileExtension}`)) {
|
|
||||||
return Promise.reject('Video file type is not supported')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
uri: uri,
|
|
||||||
mime: mime || `video/${fileExtension}`,
|
|
||||||
width: 0,
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default mediaTransformation
|
|
@ -72,7 +72,6 @@ const openLink = async (url: string, navigation?: any) => {
|
|||||||
|
|
||||||
// If an account can be found
|
// If an account can be found
|
||||||
const matchedAccount = url.match(matcherAccount)
|
const matchedAccount = url.match(matcherAccount)
|
||||||
console.log(matchedAccount)
|
|
||||||
if (matchedAccount) {
|
if (matchedAccount) {
|
||||||
// If the link in current instance
|
// If the link in current instance
|
||||||
const instanceUrl = getInstanceUrl(store.getState())
|
const instanceUrl = getInstanceUrl(store.getState())
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
"action": "User melden"
|
"action": "User melden"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "",
|
||||||
|
"succeed": ""
|
||||||
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "",
|
"title": "",
|
||||||
"block": {
|
"block": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"HTML": {
|
"HTML": {
|
||||||
"expanded": {
|
"accessibilityHint": "",
|
||||||
"true": "Zusammenklappen {{hint}}",
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
"false": "Ausklappen {{hint}}"
|
"totalLines": "",
|
||||||
},
|
"defaultHint": ""
|
||||||
"defaultHint": "Artikel"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/i18n/de/screens/accountSelection.json
Normal file
6
src/i18n/de/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"select_account": ""
|
||||||
|
}
|
||||||
|
}
|
@ -78,9 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"showcase": "Beispieltröt",
|
|
||||||
"demo": "<p>Dies ist ein Beispieltröt😊. Du kannst aus mehreren der unteren Möglichkeiten auswählen.<br /><br />Diese Einstellung betrifft ausschließlich die Haupteinstellungen, nicht die Schriftgröße in anderen Bereichen der App.</p>",
|
"demo": "<p>Dies ist ein Beispieltröt😊. Du kannst aus mehreren der unteren Möglichkeiten auswählen.<br /><br />Diese Einstellung betrifft ausschließlich die Haupteinstellungen, nicht die Schriftgröße in anderen Bereichen der App.</p>",
|
||||||
"availableSizes": "Verfügbare Größen",
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
"S": "S",
|
"S": "S",
|
||||||
"M": "M – Standard",
|
"M": "M – Standard",
|
||||||
@ -147,7 +145,8 @@
|
|||||||
"group": "Gruppe {{index}}",
|
"group": "Gruppe {{index}}",
|
||||||
"label": "Kennzeichnung",
|
"label": "Kennzeichnung",
|
||||||
"content": "Inhalt"
|
"content": "Inhalt"
|
||||||
}
|
},
|
||||||
|
"mediaSelectionFailed": ""
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"notAvailable": "Dein Gerät unterstützt keine Push-Benachrichtigung",
|
"notAvailable": "Dein Gerät unterstützt keine Push-Benachrichtigung",
|
||||||
|
@ -2,6 +2,7 @@ export default {
|
|||||||
common: require('./common'),
|
common: require('./common'),
|
||||||
|
|
||||||
screens: require('./screens'),
|
screens: require('./screens'),
|
||||||
|
screenAccountSelection: require('./screens/accountSelection.json'),
|
||||||
screenActions: require('./screens/actions'),
|
screenActions: require('./screens/actions'),
|
||||||
screenAnnouncements: require('./screens/announcements'),
|
screenAnnouncements: require('./screens/announcements'),
|
||||||
screenCompose: require('./screens/compose'),
|
screenCompose: require('./screens/compose'),
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
"action": "Report user"
|
"action": "Report user"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "Copy toot",
|
||||||
|
"succeed": "Copied"
|
||||||
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "Instance action",
|
"title": "Instance action",
|
||||||
"block": {
|
"block": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"HTML": {
|
"HTML": {
|
||||||
"expanded": {
|
"accessibilityHint": "Tap to expand or collapse content",
|
||||||
"true": "Fold {{hint}}",
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
"false": "Expand {{hint}}"
|
"totalLines": " ({{count}} lines)",
|
||||||
},
|
"defaultHint": "Long toot"
|
||||||
"defaultHint": "article"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -81,7 +81,7 @@
|
|||||||
"accessibilityHint": "Tap to go to {{name}}'s page"
|
"accessibilityHint": "Tap to go to {{name}}'s page"
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"expandHint": "hidden content"
|
"expandHint": "Hidden content"
|
||||||
},
|
},
|
||||||
"filtered": "Filtered",
|
"filtered": "Filtered",
|
||||||
"fullConversation": "Read conversations",
|
"fullConversation": "Read conversations",
|
||||||
|
6
src/i18n/en/screens/accountSelection.json
Normal file
6
src/i18n/en/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "Share to ...",
|
||||||
|
"content": {
|
||||||
|
"select_account": "Select account"
|
||||||
|
}
|
||||||
|
}
|
@ -78,9 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"showcase": "Example toot",
|
|
||||||
"demo": "<p>This is a demo toot😊. You can choose from several options from below.<br /><br />This setting only affects the main content of toots, but not other font sizes.</p>",
|
"demo": "<p>This is a demo toot😊. You can choose from several options from below.<br /><br />This setting only affects the main content of toots, but not other font sizes.</p>",
|
||||||
"availableSizes": "Available sizes",
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
"S": "S",
|
"S": "S",
|
||||||
"M": "M - Default",
|
"M": "M - Default",
|
||||||
@ -147,7 +145,8 @@
|
|||||||
"group": "Group {{index}}",
|
"group": "Group {{index}}",
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"content": "Content"
|
"content": "Content"
|
||||||
}
|
},
|
||||||
|
"mediaSelectionFailed": "Image processing failed. Please try again."
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"notAvailable": "Your phone does not support tooot's push notification",
|
"notAvailable": "Your phone does not support tooot's push notification",
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
"action": "Segnala utente"
|
"action": "Segnala utente"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "",
|
||||||
|
"succeed": ""
|
||||||
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "Azione sull'istanza",
|
"title": "Azione sull'istanza",
|
||||||
"block": {
|
"block": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"HTML": {
|
"HTML": {
|
||||||
"expanded": {
|
"accessibilityHint": "",
|
||||||
"true": "Richiudi {{hint}}",
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
"false": "Espandi {{hint}}"
|
"totalLines": "",
|
||||||
},
|
"defaultHint": ""
|
||||||
"defaultHint": "toot"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/i18n/it/screens/accountSelection.json
Normal file
6
src/i18n/it/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"select_account": ""
|
||||||
|
}
|
||||||
|
}
|
@ -78,9 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"showcase": "Toot di esempio",
|
|
||||||
"demo": "<p>Questo toot è un esempio 😺️. Puoi scegliere diverse opzioni di grandezza del testo qui sotto.<br /><br />Questa impostazione si applica solo al testo dei toot, non anche agli altri testi della app.</p>",
|
"demo": "<p>Questo toot è un esempio 😺️. Puoi scegliere diverse opzioni di grandezza del testo qui sotto.<br /><br />Questa impostazione si applica solo al testo dei toot, non anche agli altri testi della app.</p>",
|
||||||
"availableSizes": "Dimensioni testo",
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
"S": "S",
|
"S": "S",
|
||||||
"M": "M - Predefinito",
|
"M": "M - Predefinito",
|
||||||
@ -147,7 +145,8 @@
|
|||||||
"group": "Gruppo {{index}}",
|
"group": "Gruppo {{index}}",
|
||||||
"label": "Etichetta",
|
"label": "Etichetta",
|
||||||
"content": "Contenuto"
|
"content": "Contenuto"
|
||||||
}
|
},
|
||||||
|
"mediaSelectionFailed": ""
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"notAvailable": "Il tuo dispositivo non supporta le notifiche push per tooot",
|
"notAvailable": "Il tuo dispositivo non supporta le notifiche push per tooot",
|
||||||
|
22
src/i18n/ja/common.json
Normal file
22
src/i18n/ja/common.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"buttons": {
|
||||||
|
"OK": "",
|
||||||
|
"apply": "",
|
||||||
|
"cancel": ""
|
||||||
|
},
|
||||||
|
"customEmoji": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"success": {
|
||||||
|
"message": ""
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"message": ""
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"message": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"separator": ""
|
||||||
|
}
|
76
src/i18n/ja/components/contextMenu.json
Normal file
76
src/i18n/ja/components/contextMenu.json
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"account": {
|
||||||
|
"title": "",
|
||||||
|
"mute": {
|
||||||
|
"action_false": "",
|
||||||
|
"action_true": ""
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"action_false": "",
|
||||||
|
"action_true": ""
|
||||||
|
},
|
||||||
|
"reports": {
|
||||||
|
"action": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "",
|
||||||
|
"succeed": ""
|
||||||
|
},
|
||||||
|
"instance": {
|
||||||
|
"title": "",
|
||||||
|
"block": {
|
||||||
|
"action": "",
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"confirm": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"status": {
|
||||||
|
"action": ""
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"action": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"title": "",
|
||||||
|
"edit": {
|
||||||
|
"action": ""
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"action": "",
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"confirm": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deleteEdit": {
|
||||||
|
"action": "",
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"confirm": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mute": {
|
||||||
|
"action_false": "",
|
||||||
|
"action_true": ""
|
||||||
|
},
|
||||||
|
"pin": {
|
||||||
|
"action_false": "",
|
||||||
|
"action_true": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/i18n/ja/components/emojis.json
Normal file
1
src/i18n/ja/components/emojis.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
30
src/i18n/ja/components/instance.json
Normal file
30
src/i18n/ja/components/instance.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"textInput": {
|
||||||
|
"placeholder": ""
|
||||||
|
},
|
||||||
|
"button": "",
|
||||||
|
"information": {
|
||||||
|
"name": "",
|
||||||
|
"accounts": "",
|
||||||
|
"statuses": "",
|
||||||
|
"domains": ""
|
||||||
|
},
|
||||||
|
"disclaimer": {
|
||||||
|
"base": ""
|
||||||
|
},
|
||||||
|
"terms": {
|
||||||
|
"base": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"cancel": "",
|
||||||
|
"continue": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/i18n/ja/components/mediaSelector.json
Normal file
18
src/i18n/ja/components/mediaSelector.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"title": "",
|
||||||
|
"options": {
|
||||||
|
"image": "",
|
||||||
|
"image_max": "",
|
||||||
|
"video": "",
|
||||||
|
"video_max": ""
|
||||||
|
},
|
||||||
|
"library": {
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"settings": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/i18n/ja/components/parse.json
Normal file
8
src/i18n/ja/components/parse.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"HTML": {
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
|
"totalLines": "",
|
||||||
|
"defaultHint": ""
|
||||||
|
}
|
||||||
|
}
|
16
src/i18n/ja/components/relationship.json
Normal file
16
src/i18n/ja/components/relationship.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"follow": {
|
||||||
|
"function": ""
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"function": ""
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"error": "",
|
||||||
|
"blocked_by": "",
|
||||||
|
"blocking": "",
|
||||||
|
"following": "",
|
||||||
|
"requested": "",
|
||||||
|
"default": ""
|
||||||
|
}
|
||||||
|
}
|
147
src/i18n/ja/components/timeline.json
Normal file
147
src/i18n/ja/components/timeline.json
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
{
|
||||||
|
"empty": {
|
||||||
|
"error": {
|
||||||
|
"message": "",
|
||||||
|
"button": ""
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"message": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"message": ""
|
||||||
|
},
|
||||||
|
"lookback": {
|
||||||
|
"message": ""
|
||||||
|
},
|
||||||
|
"refresh": {
|
||||||
|
"fetchPreviousPage": "",
|
||||||
|
"refetch": ""
|
||||||
|
},
|
||||||
|
"shared": {
|
||||||
|
"actioned": {
|
||||||
|
"pinned": "",
|
||||||
|
"favourite": "",
|
||||||
|
"status": "",
|
||||||
|
"follow": "",
|
||||||
|
"follow_request": "",
|
||||||
|
"poll": "",
|
||||||
|
"reblog": {
|
||||||
|
"default": "",
|
||||||
|
"notification": ""
|
||||||
|
},
|
||||||
|
"update": ""
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"reply": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"reblogged": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"function": ""
|
||||||
|
},
|
||||||
|
"favourited": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"function": ""
|
||||||
|
},
|
||||||
|
"bookmarked": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"function": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actionsUsers": {
|
||||||
|
"reblogged_by": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
"favourited_by": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"text_one": "",
|
||||||
|
"text_other": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attachment": {
|
||||||
|
"sensitive": {
|
||||||
|
"button": ""
|
||||||
|
},
|
||||||
|
"unsupported": {
|
||||||
|
"text": "",
|
||||||
|
"button": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"avatar": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"expandHint": ""
|
||||||
|
},
|
||||||
|
"filtered": "",
|
||||||
|
"fullConversation": "",
|
||||||
|
"translate": {
|
||||||
|
"default": "",
|
||||||
|
"succeed": "",
|
||||||
|
"failed": "",
|
||||||
|
"source_not_supported": "",
|
||||||
|
"target_not_supported": ""
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"shared": {
|
||||||
|
"account": {
|
||||||
|
"name": {
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"accessibilityHint": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application": "",
|
||||||
|
"edited": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"direct": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"private": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"withAccounts": "",
|
||||||
|
"delete": {
|
||||||
|
"function": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"meta": {
|
||||||
|
"button": {
|
||||||
|
"vote": "",
|
||||||
|
"refresh": ""
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"voters_one": "",
|
||||||
|
"voters_other": "",
|
||||||
|
"votes_one": "",
|
||||||
|
"votes_other": ""
|
||||||
|
},
|
||||||
|
"expiration": {
|
||||||
|
"expired": "",
|
||||||
|
"until": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/i18n/ja/screens.json
Normal file
18
src/i18n/ja/screens.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"screenshot": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"button": ""
|
||||||
|
},
|
||||||
|
"localCorrupt": {
|
||||||
|
"message": ""
|
||||||
|
},
|
||||||
|
"pushError": {
|
||||||
|
"message": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"shareError": {
|
||||||
|
"imageNotSupported": "",
|
||||||
|
"videoNotSupported": ""
|
||||||
|
}
|
||||||
|
}
|
6
src/i18n/ja/screens/accountSelection.json
Normal file
6
src/i18n/ja/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"select_account": ""
|
||||||
|
}
|
||||||
|
}
|
20
src/i18n/ja/screens/actions.json
Normal file
20
src/i18n/ja/screens/actions.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"altText": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"notificationsFilter": {
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"follow": "",
|
||||||
|
"follow_request": "",
|
||||||
|
"favourite": "",
|
||||||
|
"reblog": "",
|
||||||
|
"mention": "",
|
||||||
|
"poll": "",
|
||||||
|
"status": "",
|
||||||
|
"update": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/i18n/ja/screens/announcements.json
Normal file
10
src/i18n/ja/screens/announcements.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"published": "",
|
||||||
|
"button": {
|
||||||
|
"read": "",
|
||||||
|
"unread": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
179
src/i18n/ja/screens/compose.json
Normal file
179
src/i18n/ja/screens/compose.json
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
{
|
||||||
|
"heading": {
|
||||||
|
"left": {
|
||||||
|
"button": "",
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"buttons": {
|
||||||
|
"save": "",
|
||||||
|
"delete": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"button": {
|
||||||
|
"default": "",
|
||||||
|
"conversation": "",
|
||||||
|
"reply": "",
|
||||||
|
"deleteEdit": "",
|
||||||
|
"edit": "",
|
||||||
|
"share": ""
|
||||||
|
},
|
||||||
|
"alert": {
|
||||||
|
"default": {
|
||||||
|
"title": "",
|
||||||
|
"button": ""
|
||||||
|
},
|
||||||
|
"removeReply": {
|
||||||
|
"title": "",
|
||||||
|
"description": "",
|
||||||
|
"cancel": "",
|
||||||
|
"confirm": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"root": {
|
||||||
|
"header": {
|
||||||
|
"postingAs": "",
|
||||||
|
"spoilerInput": {
|
||||||
|
"placeholder": ""
|
||||||
|
},
|
||||||
|
"textInput": {
|
||||||
|
"placeholder": "",
|
||||||
|
"keyboardImage": {
|
||||||
|
"exceedMaximum": {
|
||||||
|
"title": "",
|
||||||
|
"OK": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"attachments": {
|
||||||
|
"sensitive": "",
|
||||||
|
"remove": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emojis": {
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"option": {
|
||||||
|
"placeholder": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"single": "",
|
||||||
|
"multiple": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"reduce": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"increase": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multiple": {
|
||||||
|
"heading": "",
|
||||||
|
"options": {
|
||||||
|
"single": "",
|
||||||
|
"multiple": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expiration": {
|
||||||
|
"heading": "",
|
||||||
|
"options": {
|
||||||
|
"300": "",
|
||||||
|
"1800": "",
|
||||||
|
"3600": "",
|
||||||
|
"21600": "",
|
||||||
|
"86400": "",
|
||||||
|
"259200": "",
|
||||||
|
"604800": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"attachment": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"failed": {
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"button": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"title": "",
|
||||||
|
"options": {
|
||||||
|
"public": "",
|
||||||
|
"unlisted": "",
|
||||||
|
"private": "",
|
||||||
|
"direct": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spoiler": {
|
||||||
|
"accessibilityLabel": ""
|
||||||
|
},
|
||||||
|
"emoji": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drafts_one": "",
|
||||||
|
"drafts_other": ""
|
||||||
|
},
|
||||||
|
"editAttachment": {
|
||||||
|
"header": {
|
||||||
|
"title": "",
|
||||||
|
"right": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"failed": {
|
||||||
|
"title": "",
|
||||||
|
"button": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"altText": {
|
||||||
|
"heading": "",
|
||||||
|
"placeholder": ""
|
||||||
|
},
|
||||||
|
"imageFocus": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"draftsList": {
|
||||||
|
"header": {
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
|
"warning": "",
|
||||||
|
"content": {
|
||||||
|
"accessibilityHint": "",
|
||||||
|
"textEmpty": ""
|
||||||
|
},
|
||||||
|
"checkAttachment": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/i18n/ja/screens/imageViewer.json
Normal file
17
src/i18n/ja/screens/imageViewer.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"actions": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"save": "",
|
||||||
|
"share": "",
|
||||||
|
"cancel": ""
|
||||||
|
},
|
||||||
|
"save": {
|
||||||
|
"succeed": "",
|
||||||
|
"failed": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
353
src/i18n/ja/screens/tabs.json
Normal file
353
src/i18n/ja/screens/tabs.json
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
{
|
||||||
|
"tabs": {
|
||||||
|
"local": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"name": "",
|
||||||
|
"segments": {
|
||||||
|
"left": "",
|
||||||
|
"right": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"me": {
|
||||||
|
"name": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"search": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"filter": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"me": {
|
||||||
|
"stacks": {
|
||||||
|
"bookmarks": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"conversations": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"favourites": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"lists": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"push": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"profileName": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"profileNote": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"profileFields": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"webSettings": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"name": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"demo": "",
|
||||||
|
"sizes": {
|
||||||
|
"S": "",
|
||||||
|
"M": "",
|
||||||
|
"L": "",
|
||||||
|
"XL": "",
|
||||||
|
"XXL": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"cancellation": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"cancel": "",
|
||||||
|
"discard": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"feedback": {
|
||||||
|
"succeed": "",
|
||||||
|
"failed": ""
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"name": {
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
|
"avatar": {
|
||||||
|
"title": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"title": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"title": "",
|
||||||
|
"total_one": "",
|
||||||
|
"total_other": ""
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"title": "",
|
||||||
|
"options": {
|
||||||
|
"public": "",
|
||||||
|
"unlisted": "",
|
||||||
|
"private": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensitive": {
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
|
"lock": {
|
||||||
|
"title": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"bot": {
|
||||||
|
"title": "",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"group": "",
|
||||||
|
"label": "",
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"mediaSelectionFailed": ""
|
||||||
|
},
|
||||||
|
"push": {
|
||||||
|
"notAvailable": "",
|
||||||
|
"enable": {
|
||||||
|
"direct": "",
|
||||||
|
"settings": ""
|
||||||
|
},
|
||||||
|
"global": {
|
||||||
|
"heading": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"decode": {
|
||||||
|
"heading": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"follow": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"follow_request": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"favourite": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"reblog": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"mention": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"howitworks": ""
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"announcements": {
|
||||||
|
"content": {
|
||||||
|
"unread": "",
|
||||||
|
"read": "",
|
||||||
|
"empty": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"push": {
|
||||||
|
"content": {
|
||||||
|
"enabled": "",
|
||||||
|
"disabled": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"title": ""
|
||||||
|
},
|
||||||
|
"logout": {
|
||||||
|
"button": "",
|
||||||
|
"alert": {
|
||||||
|
"title": "",
|
||||||
|
"message": "",
|
||||||
|
"buttons": {
|
||||||
|
"logout": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"fontsize": {
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"S": "",
|
||||||
|
"M": "",
|
||||||
|
"L": "",
|
||||||
|
"XL": "",
|
||||||
|
"XXL": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"heading": "",
|
||||||
|
"options": {
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"heading": "",
|
||||||
|
"options": {
|
||||||
|
"auto": "",
|
||||||
|
"light": "",
|
||||||
|
"dark": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"darkTheme": {
|
||||||
|
"heading": "",
|
||||||
|
"options": {
|
||||||
|
"lighter": "",
|
||||||
|
"darker": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browser": {
|
||||||
|
"heading": "",
|
||||||
|
"options": {
|
||||||
|
"internal": "",
|
||||||
|
"external": "",
|
||||||
|
"cancel": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"staticEmoji": {
|
||||||
|
"heading": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"feedback": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"support": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"review": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
|
"analytics": {
|
||||||
|
"heading": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"version": "",
|
||||||
|
"instanceVersion": ""
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"existing": "",
|
||||||
|
"new": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shared": {
|
||||||
|
"account": {
|
||||||
|
"actions": {
|
||||||
|
"accessibilityLabel": "",
|
||||||
|
"accessibilityHint": ""
|
||||||
|
},
|
||||||
|
"followed_by": "",
|
||||||
|
"moved": "",
|
||||||
|
"created_at": "",
|
||||||
|
"summary": {
|
||||||
|
"statuses_count": "",
|
||||||
|
"following_count": "",
|
||||||
|
"followers_count": ""
|
||||||
|
},
|
||||||
|
"toots": {
|
||||||
|
"default": "",
|
||||||
|
"all": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attachments": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"header": {
|
||||||
|
"prefix": "",
|
||||||
|
"placeholder": ""
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"general": "",
|
||||||
|
"advanced": {
|
||||||
|
"header": "",
|
||||||
|
"example": {
|
||||||
|
"account": "",
|
||||||
|
"hashtag": "",
|
||||||
|
"statusLink": "",
|
||||||
|
"accountLink": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sections": {
|
||||||
|
"accounts": "",
|
||||||
|
"hashtags": "",
|
||||||
|
"statuses": ""
|
||||||
|
},
|
||||||
|
"notFound": ""
|
||||||
|
},
|
||||||
|
"toot": {
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"accounts": {
|
||||||
|
"following": "",
|
||||||
|
"followers": ""
|
||||||
|
},
|
||||||
|
"statuses": {
|
||||||
|
"reblogged_by": "",
|
||||||
|
"favourited_by": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"name": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,10 @@
|
|||||||
"action": "사용자 신고"
|
"action": "사용자 신고"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "",
|
||||||
|
"succeed": ""
|
||||||
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "",
|
"title": "",
|
||||||
"block": {
|
"block": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"HTML": {
|
"HTML": {
|
||||||
"expanded": {
|
"accessibilityHint": "",
|
||||||
"true": "{{hint}} 접기",
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
"false": "{{hint}} 펼치기"
|
"totalLines": "",
|
||||||
},
|
"defaultHint": ""
|
||||||
"defaultHint": "글"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/i18n/ko/screens/accountSelection.json
Normal file
6
src/i18n/ko/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"select_account": ""
|
||||||
|
}
|
||||||
|
}
|
@ -78,9 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"showcase": "예시 툿",
|
|
||||||
"demo": "<p>데모 툿이에요😊. 아래의 여러 옵션 중에서 선택할 수 있어요.<br /><br />이 설정은 툿의 메인 내용에만 적용되고, 다른 폰트 크기에 영향을 미치지 않아요.</p>",
|
"demo": "<p>데모 툿이에요😊. 아래의 여러 옵션 중에서 선택할 수 있어요.<br /><br />이 설정은 툿의 메인 내용에만 적용되고, 다른 폰트 크기에 영향을 미치지 않아요.</p>",
|
||||||
"availableSizes": "사용할 수 있는 크기",
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
"S": "작게",
|
"S": "작게",
|
||||||
"M": "중간 - 기본값",
|
"M": "중간 - 기본값",
|
||||||
@ -147,7 +145,8 @@
|
|||||||
"group": "그룹 {{index}}",
|
"group": "그룹 {{index}}",
|
||||||
"label": "라벨",
|
"label": "라벨",
|
||||||
"content": "내용"
|
"content": "내용"
|
||||||
}
|
},
|
||||||
|
"mediaSelectionFailed": ""
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"notAvailable": "이 기기는 tooot의 푸시 알림을 지원하지 않아요",
|
"notAvailable": "이 기기는 tooot의 푸시 알림을 지원하지 않아요",
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
"action": "Denunciar usuário"
|
"action": "Denunciar usuário"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "",
|
||||||
|
"succeed": ""
|
||||||
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "Ação da Instância",
|
"title": "Ação da Instância",
|
||||||
"block": {
|
"block": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"HTML": {
|
"HTML": {
|
||||||
"expanded": {
|
"accessibilityHint": "Toque para expandir ou recolher conteúdo",
|
||||||
"true": "Fechar {{hint}}",
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
"false": "Expandir {{hint}}"
|
"totalLines": "",
|
||||||
},
|
"defaultHint": ""
|
||||||
"defaultHint": "artigo"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -81,7 +81,7 @@
|
|||||||
"accessibilityHint": "Toque para ir à página de {{name}}"
|
"accessibilityHint": "Toque para ir à página de {{name}}"
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"expandHint": "conteúdo oculto"
|
"expandHint": "Conteúdo oculto"
|
||||||
},
|
},
|
||||||
"filtered": "Filtrado",
|
"filtered": "Filtrado",
|
||||||
"fullConversation": "Ler conversas",
|
"fullConversation": "Ler conversas",
|
||||||
|
6
src/i18n/pt_BR/screens/accountSelection.json
Normal file
6
src/i18n/pt_BR/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"select_account": ""
|
||||||
|
}
|
||||||
|
}
|
@ -78,9 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"showcase": "Exemplo de toot",
|
|
||||||
"demo": "<p>Esta é uma demonstração também😊. Você pode escolher entre várias opções abaixo.<br /><br />Esta configuração afeta apenas o conteúdo principal dos toots, mas não os tamanhos de outra fonte.</p>",
|
"demo": "<p>Esta é uma demonstração também😊. Você pode escolher entre várias opções abaixo.<br /><br />Esta configuração afeta apenas o conteúdo principal dos toots, mas não os tamanhos de outra fonte.</p>",
|
||||||
"availableSizes": "Tamanhos disponíveis",
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
"S": "P",
|
"S": "P",
|
||||||
"M": "M - Padrão",
|
"M": "M - Padrão",
|
||||||
@ -147,7 +145,8 @@
|
|||||||
"group": "Grupo {{index}}",
|
"group": "Grupo {{index}}",
|
||||||
"label": "Rótulo",
|
"label": "Rótulo",
|
||||||
"content": "Conteúdo"
|
"content": "Conteúdo"
|
||||||
}
|
},
|
||||||
|
"mediaSelectionFailed": ""
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"notAvailable": "Seu telefone não suporta notificação de envio de tooot",
|
"notAvailable": "Seu telefone não suporta notificação de envio de tooot",
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
"action": "Báo cáo"
|
"action": "Báo cáo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "",
|
||||||
|
"succeed": ""
|
||||||
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "Hành động máy chủ",
|
"title": "Hành động máy chủ",
|
||||||
"block": {
|
"block": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"HTML": {
|
"HTML": {
|
||||||
"expanded": {
|
"accessibilityHint": "",
|
||||||
"true": "Cuộn {{hint}}",
|
"expanded": "{{hint}}{{totalLines}}",
|
||||||
"false": "Mở {{hint}}"
|
"totalLines": "",
|
||||||
},
|
"defaultHint": ""
|
||||||
"defaultHint": "Tút"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -81,7 +81,7 @@
|
|||||||
"accessibilityHint": "Đến trang của {{name}}"
|
"accessibilityHint": "Đến trang của {{name}}"
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"expandHint": "nội dung ẩn"
|
"expandHint": "Nội dung ẩn"
|
||||||
},
|
},
|
||||||
"filtered": "Đã lọc",
|
"filtered": "Đã lọc",
|
||||||
"fullConversation": "Xem thêm",
|
"fullConversation": "Xem thêm",
|
||||||
|
6
src/i18n/vi/screens/accountSelection.json
Normal file
6
src/i18n/vi/screens/accountSelection.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"heading": "",
|
||||||
|
"content": {
|
||||||
|
"select_account": ""
|
||||||
|
}
|
||||||
|
}
|
@ -78,9 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fontSize": {
|
"fontSize": {
|
||||||
"showcase": "Xem trước",
|
|
||||||
"demo": "<p>Đây là một tút mẫu 😊 Bạn có thể chọn một trong nhiều lựa chọn bên dưới.<br /><br />Tùy chọn này chỉ áp dụng cho nội dung tút chứ không ảnh hưởng những phần tử khác của app.</p>",
|
"demo": "<p>Đây là một tút mẫu 😊 Bạn có thể chọn một trong nhiều lựa chọn bên dưới.<br /><br />Tùy chọn này chỉ áp dụng cho nội dung tút chứ không ảnh hưởng những phần tử khác của app.</p>",
|
||||||
"availableSizes": "Kích cỡ",
|
|
||||||
"sizes": {
|
"sizes": {
|
||||||
"S": "S",
|
"S": "S",
|
||||||
"M": "M - Mặc định",
|
"M": "M - Mặc định",
|
||||||
@ -147,7 +145,8 @@
|
|||||||
"group": "Mục {{index}}",
|
"group": "Mục {{index}}",
|
||||||
"label": "Nhãn",
|
"label": "Nhãn",
|
||||||
"content": "Nội dung"
|
"content": "Nội dung"
|
||||||
}
|
},
|
||||||
|
"mediaSelectionFailed": ""
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"notAvailable": "Điện thoại của bạn chưa bật thông báo đẩy",
|
"notAvailable": "Điện thoại của bạn chưa bật thông báo đẩy",
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user