mirror of https://github.com/tooot-app/app
Merge branch 'main' into candidate
This commit is contained in:
commit
4a60d81e45
|
@ -0,0 +1,74 @@
|
|||
diff --git a/Libraries/Utilities/setAndForwardRef.js b/Libraries/Utilities/setAndForwardRef.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e67b530b9a933b68e219e2b8cec2a66dc8f51323
|
||||
--- /dev/null
|
||||
+++ b/Libraries/Utilities/setAndForwardRef.js
|
||||
@@ -0,0 +1,68 @@
|
||||
+/**
|
||||
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
+ *
|
||||
+ * This source code is licensed under the MIT license found in the
|
||||
+ * LICENSE file in the root directory of this source tree.
|
||||
+ *
|
||||
+ * @format
|
||||
+ * @flow
|
||||
+ */
|
||||
+
|
||||
+'use strict'
|
||||
+
|
||||
+import type { ElementRef, Ref } from 'react'
|
||||
+
|
||||
+type Args = $ReadOnly<{|
|
||||
+ getForwardedRef: () => ?Ref<any>,
|
||||
+ setLocalRef: (ref: ElementRef<any>) => mixed
|
||||
+|}>
|
||||
+
|
||||
+/**
|
||||
+ * This is a helper function for when a component needs to be able to forward a ref
|
||||
+ * to a child component, but still needs to have access to that component as part of
|
||||
+ * its implementation.
|
||||
+ *
|
||||
+ * Its main use case is in wrappers for native components.
|
||||
+ *
|
||||
+ * Usage:
|
||||
+ *
|
||||
+ * class MyView extends React.Component {
|
||||
+ * _nativeRef = null;
|
||||
+ *
|
||||
+ * _setNativeRef = setAndForwardRef({
|
||||
+ * getForwardedRef: () => this.props.forwardedRef,
|
||||
+ * setLocalRef: ref => {
|
||||
+ * this._nativeRef = ref;
|
||||
+ * },
|
||||
+ * });
|
||||
+ *
|
||||
+ * render() {
|
||||
+ * return <View ref={this._setNativeRef} />;
|
||||
+ * }
|
||||
+ * }
|
||||
+ *
|
||||
+ * const MyViewWithRef = React.forwardRef((props, ref) => (
|
||||
+ * <MyView {...props} forwardedRef={ref} />
|
||||
+ * ));
|
||||
+ *
|
||||
+ * module.exports = MyViewWithRef;
|
||||
+ */
|
||||
+
|
||||
+function setAndForwardRef({ getForwardedRef, setLocalRef }: Args): (ref: ElementRef<any>) => void {
|
||||
+ return function forwardRef(ref: ElementRef<any>) {
|
||||
+ const forwardedRef = getForwardedRef()
|
||||
+
|
||||
+ setLocalRef(ref)
|
||||
+
|
||||
+ // Forward to user ref prop (if one has been specified)
|
||||
+ if (typeof forwardedRef === 'function') {
|
||||
+ // Handle function-based refs. String-based refs are handled as functions.
|
||||
+ forwardedRef(ref)
|
||||
+ } else if (typeof forwardedRef === 'object' && forwardedRef != null) {
|
||||
+ // Handle createRef-based refs
|
||||
+ forwardedRef.current = ref
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+module.exports = setAndForwardRef
|
2
Gemfile
2
Gemfile
|
@ -1,6 +1,6 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
gem 'cocoapods'
|
||||
gem 'cocoapods', '~> 1.12'
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
||||
|
|
|
@ -2,8 +2,6 @@ apply plugin: "com.android.application"
|
|||
apply plugin: "com.facebook.react"
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
import com.android.build.OutputFile
|
||||
|
||||
/**
|
||||
* This is the configuration block to customize your React Native Android app.
|
||||
* By default you don't need to apply any configuration, just uncomment the lines you need.
|
||||
|
@ -15,8 +13,8 @@ react {
|
|||
// root = file("../")
|
||||
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||
// reactNativeDir = file("../node_modules/react-native")
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
|
||||
// codegenDir = file("../node_modules/react-native-codegen")
|
||||
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
|
||||
// codegenDir = file("../node_modules/@react-native/codegen")
|
||||
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
|
||||
// cliFile = file("../node_modules/react-native/cli.js")
|
||||
/* Variants */
|
||||
|
@ -51,14 +49,6 @@ react {
|
|||
// hermesFlags = ["-O", "-output-source-map"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to create four separate APKs instead of one,
|
||||
* one for each native architecture. This is useful if you don't
|
||||
* use App Bundles (https://developer.android.com/guide/app-bundle/)
|
||||
* and want to have separate APKs to upload to the Play Store.
|
||||
*/
|
||||
def enableSeparateBuildPerCPUArchitecture = false
|
||||
|
||||
/**
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
*/
|
||||
|
@ -77,16 +67,6 @@ def enableProguardInReleaseBuilds = false
|
|||
*/
|
||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
|
||||
/**
|
||||
* Private function to get the list of Native Architectures you want to build.
|
||||
* This reads the value from reactNativeArchitectures in your gradle.properties
|
||||
* file and works together with the --active-arch-only flag of react-native run-android.
|
||||
*/
|
||||
def reactNativeArchitectures() {
|
||||
def value = project.getProperties().get("reactNativeArchitectures")
|
||||
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
||||
}
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
||||
|
@ -105,14 +85,6 @@ android {
|
|||
versionCode 50
|
||||
versionName "0.2"
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable enableSeparateBuildPerCPUArchitecture
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include (*reactNativeArchitectures())
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('debug.keystore')
|
||||
|
@ -133,28 +105,9 @@ android {
|
|||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
}
|
||||
}
|
||||
|
||||
// applicationVariants are e.g. debug, release
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// https://developer.android.com/studio/build/configure-apk-splits.html
|
||||
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0") {
|
||||
force = true
|
||||
}
|
||||
|
||||
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
|
||||
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
|
||||
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
|
||||
|
@ -182,7 +135,6 @@ dependencies {
|
|||
|
||||
// The version of react-native is set by the React Native Gradle Plugin
|
||||
implementation("com.facebook.react:react-android")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
|
||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
|
||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
||||
|
|
|
@ -34,9 +34,6 @@ public class MainActivity extends ReactActivity {
|
|||
this,
|
||||
getMainComponentName(),
|
||||
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
|
||||
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
|
||||
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
|
||||
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
|
||||
);
|
||||
DefaultNewArchitectureEntryPoint.getFabricEnabled());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:7.4.1")
|
||||
classpath("com.android.tools.build:gradle")
|
||||
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||
classpath 'com.google.gms:google-services:4.3.14'
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ android.useAndroidX=true
|
|||
android.enableJetifier=true
|
||||
|
||||
# Version of flipper SDK to use with React Native
|
||||
FLIPPER_VERSION=0.176.1
|
||||
FLIPPER_VERSION=0.182.0
|
||||
|
||||
# Use this property to specify which architecture you want to build.
|
||||
# You can also override it from the CLI using
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -37,10 +37,11 @@ do
|
|||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
@ -99,12 +100,16 @@ fi
|
|||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
@ -157,6 +162,13 @@ set -- \
|
|||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
|
@ -25,7 +25,8 @@
|
|||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
@ -74,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
|
|
@ -8,4 +8,4 @@ applyNativeModulesSettingsGradle(settings)
|
|||
|
||||
include ':app'
|
||||
|
||||
includeBuild('../node_modules/react-native-gradle-plugin')
|
||||
includeBuild('../node_modules/@react-native/gradle-plugin')
|
||||
|
|
|
@ -1,26 +1,27 @@
|
|||
module.exports = function (api) {
|
||||
api.cache(false)
|
||||
|
||||
const plugins = [
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
[
|
||||
'module-resolver',
|
||||
{
|
||||
root: ['./'],
|
||||
alias: {
|
||||
'@components': './src/components',
|
||||
'@i18n': './src/i18n',
|
||||
'@screens': './src/screens',
|
||||
'@utils': './src/utils'
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
[
|
||||
'module-resolver',
|
||||
{
|
||||
root: ['./'],
|
||||
alias: {
|
||||
'@components': './src/components',
|
||||
'@i18n': './src/i18n',
|
||||
'@screens': './src/screens',
|
||||
'@utils': './src/utils'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'react-native-reanimated/plugin'
|
||||
]
|
||||
|
||||
if (process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production') {
|
||||
plugins.push('transform-remove-console')
|
||||
]
|
||||
].concat(
|
||||
process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production'
|
||||
? ['transform-remove-console']
|
||||
: [],
|
||||
['react-native-reanimated/plugin']
|
||||
)
|
||||
}
|
||||
|
||||
return { presets: ['babel-preset-expo'], plugins }
|
||||
}
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
Enjoy toooting! This version includes following improvements and fixes:
|
||||
- Long press avatar in tab bar to quickly switch to another account
|
||||
- Fix poll notifications wrongly greyed out
|
|
@ -1,3 +1,2 @@
|
|||
tooot-ing愉快!此版本包括以下改进和修复:
|
||||
- 长按底部菜单头像快速切换账户
|
||||
- 修复投票通知显示
|
||||
- 新增neodb.social演出卡片
|
12
ios/Podfile
12
ios/Podfile
|
@ -1,6 +1,11 @@
|
|||
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
|
||||
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")
|
||||
|
||||
# Resolve react_native_pods.rb with node to allow for hoisting
|
||||
require Pod::Executable.execute_command('node', ['-p',
|
||||
'require.resolve(
|
||||
"react-native/scripts/react_native_pods.rb",
|
||||
{paths: [process.argv[1]]},
|
||||
)', __dir__]).strip
|
||||
|
||||
platform :ios, '13.0'
|
||||
prepare_react_native_project!
|
||||
|
@ -33,8 +38,7 @@ target 'tooot' do
|
|||
post_install do |installer|
|
||||
react_native_post_install(
|
||||
installer,
|
||||
# Set `mac_catalyst_enabled` to `true` in order to apply patches
|
||||
# necessary for Mac Catalyst builds
|
||||
config[:reactNativePath],
|
||||
:mac_catalyst_enabled => false
|
||||
)
|
||||
__apply_Xcode_12_5_M1_post_install_workaround(installer)
|
||||
|
|
686
ios/Podfile.lock
686
ios/Podfile.lock
File diff suppressed because it is too large
Load Diff
|
@ -697,6 +697,8 @@
|
|||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
|
@ -753,6 +755,8 @@
|
|||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
|
|
@ -22,16 +22,6 @@
|
|||
#endif
|
||||
}
|
||||
|
||||
/// 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` feature is enabled. Otherwise, it returns `false`.
|
||||
- (BOOL)concurrentRootEnabled
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Linking API
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
||||
NSString *urlString = url.absoluteString;
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
module.exports = {
|
||||
transformer: { inlineRequires: true }
|
||||
}
|
||||
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
|
||||
|
||||
/**
|
||||
* Metro configuration
|
||||
* https://facebook.github.io/metro/docs/configuration
|
||||
*
|
||||
* @type {import('metro-config').MetroConfig}
|
||||
*/
|
||||
const config = {};
|
||||
|
||||
module.exports = mergeConfig(getDefaultConfig(__dirname), config)
|
||||
|
|
76
package.json
76
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tooot",
|
||||
"version": "4.9.5",
|
||||
"version": "4.9.7",
|
||||
"description": "tooot for Mastodon",
|
||||
"author": "xmflsct <me@xmflsct.com>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
@ -19,43 +19,43 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@expo/react-native-action-sheet": "^4.0.1",
|
||||
"@formatjs/intl-datetimeformat": "^6.8.0",
|
||||
"@formatjs/intl-getcanonicallocales": "^2.2.0",
|
||||
"@formatjs/intl-locale": "^3.3.0",
|
||||
"@formatjs/intl-numberformat": "^8.5.0",
|
||||
"@formatjs/intl-pluralrules": "^5.2.2",
|
||||
"@formatjs/intl-relativetimeformat": "^11.2.2",
|
||||
"@formatjs/intl-datetimeformat": "^6.10.0",
|
||||
"@formatjs/intl-getcanonicallocales": "^2.2.1",
|
||||
"@formatjs/intl-locale": "^3.3.2",
|
||||
"@formatjs/intl-numberformat": "^8.7.0",
|
||||
"@formatjs/intl-pluralrules": "^5.2.4",
|
||||
"@formatjs/intl-relativetimeformat": "^11.2.4",
|
||||
"@mattermost/react-native-paste-input": "^0.6.2",
|
||||
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
|
||||
"@react-native-async-storage/async-storage": "~1.17.11",
|
||||
"@react-native-camera-roll/camera-roll": "^5.4.0",
|
||||
"@react-native-camera-roll/camera-roll": "^5.6.0",
|
||||
"@react-native-clipboard/clipboard": "^1.11.2",
|
||||
"@react-native-community/blur": "^4.3.2",
|
||||
"@react-native-community/netinfo": "9.3.10",
|
||||
"@react-native-firebase/app": "^17.5.0",
|
||||
"@react-native-menu/menu": "^0.7.3",
|
||||
"@react-native-firebase/app": "^18.0.0",
|
||||
"@react-native-menu/menu": "^0.8.0",
|
||||
"@react-native-segmented-control/segmented-control": "^2.4.1",
|
||||
"@react-navigation/bottom-tabs": "^6.5.7",
|
||||
"@react-navigation/native": "^6.1.6",
|
||||
"@react-navigation/native-stack": "^6.9.12",
|
||||
"@react-navigation/stack": "^6.3.16",
|
||||
"@sentry/react-native": "5.4.2",
|
||||
"@sentry/react-native": "5.6.0",
|
||||
"@sharcoux/slider": "^6.1.2",
|
||||
"@tanstack/react-query": "^4.29.7",
|
||||
"@tanstack/react-query": "^4.29.15",
|
||||
"axios": "^1.4.0",
|
||||
"diff": "^5.1.0",
|
||||
"expo": "48.0.16",
|
||||
"expo": "48.0.19",
|
||||
"expo-auth-session": "^4.1.0",
|
||||
"expo-av": "^13.3.0",
|
||||
"expo-constants": "^14.3.0",
|
||||
"expo-crypto": "^12.3.0",
|
||||
"expo-file-system": "^15.3.0",
|
||||
"expo-constants": "^14.4.0",
|
||||
"expo-crypto": "^12.4.0",
|
||||
"expo-file-system": "^15.4.0",
|
||||
"expo-haptics": "^12.3.0",
|
||||
"expo-image": "^1.2.2",
|
||||
"expo-image": "^1.3.0",
|
||||
"expo-linking": "^4.1.0",
|
||||
"expo-localization": "^14.2.0",
|
||||
"expo-notifications": "^0.18.1",
|
||||
"expo-screen-capture": "5.1.1",
|
||||
"expo-screen-capture": "5.2.0",
|
||||
"expo-screen-orientation": "^5.2.0",
|
||||
"expo-secure-store": "^12.1.1",
|
||||
"expo-splash-screen": "^0.18.2",
|
||||
|
@ -63,51 +63,52 @@
|
|||
"expo-video-thumbnails": "^7.3.0",
|
||||
"expo-web-browser": "~12.1.1",
|
||||
"htmlparser2": "^9.0.0",
|
||||
"i18next": "^22.4.15",
|
||||
"i18next": "^23.2.2",
|
||||
"linkify-it": "^4.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-intl": "^6.4.2",
|
||||
"react-native": "^0.71.8",
|
||||
"react-i18next": "^13.0.0",
|
||||
"react-intl": "^6.4.4",
|
||||
"react-native": "^0.72.0",
|
||||
"react-native-flash-message": "^0.4.1",
|
||||
"react-native-gesture-handler": "~2.10.0",
|
||||
"react-native-image-picker": "^5.3.1",
|
||||
"react-native-gesture-handler": "~2.12.0",
|
||||
"react-native-image-picker": "^5.6.0",
|
||||
"react-native-ios-context-menu": "^1.15.3",
|
||||
"react-native-language-detection": "^0.2.2",
|
||||
"react-native-mmkv": "~2.8.0",
|
||||
"react-native-mmkv": "~2.9.0",
|
||||
"react-native-pager-view": "^6.2.0",
|
||||
"react-native-quick-base64": "^2.0.6",
|
||||
"react-native-reanimated": "^3.1.0",
|
||||
"react-native-reanimated": "^3.3.0",
|
||||
"react-native-reanimated-zoom": "^0.3.3",
|
||||
"react-native-safe-area-context": "^4.5.2",
|
||||
"react-native-screens": "^3.20.0",
|
||||
"react-native-safe-area-context": "^4.6.2",
|
||||
"react-native-screens": "^3.21.1",
|
||||
"react-native-share-menu": "^6.0.0",
|
||||
"react-native-svg": "^13.9.0",
|
||||
"react-native-swipe-list-view": "^3.2.9",
|
||||
"react-native-tab-view": "^3.5.1",
|
||||
"rn-placeholder": "^3.0.3",
|
||||
"zeego": "^1.6.0"
|
||||
"zeego": "^1.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.8",
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
|
||||
"@babel/preset-typescript": "^7.21.5",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@expo/config": "^8.0.4",
|
||||
"@react-native/metro-config": "^0.72.6",
|
||||
"@types/diff": "^5.0.3",
|
||||
"@types/linkify-it": "^3.0.2",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/react": "^18.2.6",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"@types/lodash": "^4.14.195",
|
||||
"@types/react": "^18.2.13",
|
||||
"@types/react-dom": "^18.2.6",
|
||||
"@types/react-native-share-menu": "^5.0.2",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||
"chalk": "^4.1.2",
|
||||
"deprecated-react-native-prop-types": "^4.1.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"dotenv": "^16.3.1",
|
||||
"react-native-clean-project": "^4.0.1",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"packageManager": "yarn@3.3.1",
|
||||
"resolutions": {
|
||||
|
@ -115,6 +116,7 @@
|
|||
"react-native-share-menu@^6.0.0": "patch:react-native-share-menu@npm%3A6.0.0#./.yarn/patches/react-native-share-menu-npm-6.0.0-f1094c3204.patch",
|
||||
"@types/react-native-share-menu@^5.0.2": "patch:@types/react-native-share-menu@npm%3A5.0.2#./.yarn/patches/@types-react-native-share-menu-npm-5.0.2-373df17ecc.patch",
|
||||
"react-native-ios-context-menu@^1.15.1": "patch:react-native-ios-context-menu@npm%3A1.15.1#./.yarn/patches/react-native-ios-context-menu-npm-1.15.1-0034bfa5ba.patch",
|
||||
"react-native-reanimated-zoom@^0.3.3": "patch:react-native-reanimated-zoom@npm%3A0.3.3#./.yarn/patches/react-native-reanimated-zoom-npm-0.3.3-bbb8d84109.patch"
|
||||
"react-native-reanimated-zoom@^0.3.3": "patch:react-native-reanimated-zoom@npm%3A0.3.3#./.yarn/patches/react-native-reanimated-zoom-npm-0.3.3-bbb8d84109.patch",
|
||||
"react-native@^0.72.0": "patch:react-native@npm%3A0.72.0#./.yarn/patches/react-native-npm-0.72.0-66f5fd62b3.patch"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||
!!domain.length &&
|
||||
!!errorCode &&
|
||||
!!(Linking.parse(`https://${domain}/`).hostname === domain) &&
|
||||
errorCode === 401
|
||||
(errorCode === 401 || errorCode === 500)
|
||||
|
||||
const instanceQuery = useInstanceQuery({
|
||||
domain,
|
||||
|
@ -80,7 +80,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||
clientSecret,
|
||||
scopes: variables.scopes,
|
||||
redirectUri,
|
||||
usePKCE: !['pawoo.net', 'mao.mastodonhub.com'].includes(domain)
|
||||
usePKCE: !['pawoo.net'].includes(domain)
|
||||
})
|
||||
await request.makeAuthUrlAsync(discovery)
|
||||
|
||||
|
@ -131,7 +131,8 @@ const ComponentInstance: React.FC<Props> = ({
|
|||
((instanceQuery.data as Mastodon.Instance_V1)?.uri
|
||||
? Linking.parse((instanceQuery.data as Mastodon.Instance_V1).uri).hostname
|
||||
: undefined) ||
|
||||
(instanceQuery.data as Mastodon.Instance_V1)?.uri,
|
||||
(instanceQuery.data as Mastodon.Instance_V1)?.uri ||
|
||||
domain,
|
||||
'auth.account.avatar_static': avatar_static,
|
||||
version: instanceQuery.data?.version || '0',
|
||||
preferences: undefined,
|
||||
|
|
|
@ -10,6 +10,7 @@ import React, { useContext } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
import StatusContext from './Context'
|
||||
import GracefullyImage from '@components/GracefullyImage'
|
||||
|
||||
export interface Props {
|
||||
action: Mastodon.Notification['type'] | 'reblog' | 'pinned'
|
||||
|
@ -34,11 +35,30 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
|||
content={content}
|
||||
emojis={account.emojis}
|
||||
size='S'
|
||||
style={{ color: action === 'admin.report' ? colors.red : colors.primaryDefault }}
|
||||
style={{ flex: 1, color: action === 'admin.report' ? colors.red : colors.primaryDefault }}
|
||||
/>
|
||||
)
|
||||
|
||||
const onPress = () => navigation.push('Tab-Shared-Account', { account })
|
||||
const miniAvatar = (
|
||||
<GracefullyImage
|
||||
sources={{
|
||||
default: { uri: account.avatar },
|
||||
static: { uri: account.avatar_static }
|
||||
}}
|
||||
dimension={{
|
||||
width: StyleConstants.Avatar.XS / 1.5,
|
||||
height: StyleConstants.Avatar.XS / 1.5
|
||||
}}
|
||||
style={{
|
||||
borderRadius: 99,
|
||||
overflow: 'hidden',
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
}}
|
||||
dim
|
||||
withoutTransition
|
||||
/>
|
||||
)
|
||||
|
||||
const children = () => {
|
||||
switch (action) {
|
||||
|
@ -63,7 +83,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
|||
color={iconColor}
|
||||
style={styles.icon}
|
||||
/>
|
||||
<Pressable onPress={onPress}>
|
||||
<Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{miniAvatar}
|
||||
{content(t('shared.actioned.favourite', { name }))}
|
||||
</Pressable>
|
||||
</>
|
||||
|
@ -77,7 +98,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
|||
color={iconColor}
|
||||
style={styles.icon}
|
||||
/>
|
||||
<Pressable onPress={onPress}>
|
||||
<Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{miniAvatar}
|
||||
{content(t('shared.actioned.follow', { name }))}
|
||||
</Pressable>
|
||||
</>
|
||||
|
@ -91,7 +113,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
|||
color={iconColor}
|
||||
style={styles.icon}
|
||||
/>
|
||||
<Pressable onPress={onPress}>
|
||||
<Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{miniAvatar}
|
||||
{content(t('shared.actioned.follow_request', { name }))}
|
||||
</Pressable>
|
||||
</>
|
||||
|
@ -118,7 +141,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
|||
color={iconColor}
|
||||
style={styles.icon}
|
||||
/>
|
||||
<Pressable onPress={onPress}>
|
||||
<Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{!myself ? miniAvatar : null}
|
||||
{content(
|
||||
isNotification
|
||||
? t('shared.actioned.reblog.notification', { name })
|
||||
|
@ -138,7 +162,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
|
|||
color={iconColor}
|
||||
style={styles.icon}
|
||||
/>
|
||||
<Pressable onPress={onPress}>
|
||||
<Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{miniAvatar}
|
||||
{content(t('shared.actioned.status', { name }))}
|
||||
</Pressable>
|
||||
</>
|
||||
|
|
|
@ -16,18 +16,19 @@ export type Props = {
|
|||
export const CardNeodb: React.FC<Props> = ({ card }) => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
const segments = Linking.parse(card.url).path?.split('/')
|
||||
if (!segments || !['movie', 'book', 'tv', 'game', 'album', 'podcast'].includes(segments[0]))
|
||||
const path = Linking.parse(card.url).path
|
||||
if (!path) return null
|
||||
|
||||
const segments = path?.split('/')
|
||||
if (
|
||||
!segments ||
|
||||
!['movie', 'book', 'tv', 'game', 'album', 'podcast', 'performance'].includes(segments[0])
|
||||
)
|
||||
return null
|
||||
|
||||
const [headingLines, setHeadingLines] = useState(3)
|
||||
|
||||
const { data } = useNeodbQuery({
|
||||
path:
|
||||
segments[0] === 'tv' && segments[1] === 'season'
|
||||
? `${segments[0]}${segments[1]}/${segments[2]}`
|
||||
: `${segments[0]}/${segments[1]}`
|
||||
})
|
||||
const { data } = useNeodbQuery({ path })
|
||||
|
||||
if (!data) return null
|
||||
|
||||
|
@ -44,7 +45,13 @@ export const CardNeodb: React.FC<Props> = ({ card }) => {
|
|||
>
|
||||
{data.cover_image_url ? (
|
||||
<GracefullyImage
|
||||
sources={{ default: { uri: data.cover_image_url } }}
|
||||
sources={{
|
||||
default: {
|
||||
uri: data.cover_image_url.startsWith('/')
|
||||
? `https://neodb.social${data.cover_image_url}`
|
||||
: data.cover_image_url
|
||||
}
|
||||
}}
|
||||
dimension={{
|
||||
width: StyleConstants.Font.LineHeight.M * 4,
|
||||
height: StyleConstants.Font.LineHeight.M * 5
|
||||
|
@ -162,6 +169,27 @@ export const CardNeodb: React.FC<Props> = ({ card }) => {
|
|||
return (
|
||||
<Content heading={[data.title]} details={[data.hosts.join(' '), data.genre.join(' ')]} />
|
||||
)
|
||||
case 'performance':
|
||||
if (segments[1] === 'production') {
|
||||
return (
|
||||
<Content
|
||||
heading={[data.display_title]}
|
||||
details={[
|
||||
data.opening_date,
|
||||
data.director.join(' '),
|
||||
data.playwright.join(' '),
|
||||
data.composer.join(' ')
|
||||
]}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Content
|
||||
heading={[data.title, data.orig_title]}
|
||||
details={[data.genre.join(' '), data.playwright.join(' '), data.director.join(' ')]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ const TimelineHeaderAndroid: React.FC = () => {
|
|||
<View
|
||||
style={{
|
||||
padding: StyleConstants.Spacing.L,
|
||||
paddingBottom: StyleConstants.Spacing.S,
|
||||
backgroundColor: colors.backgroundDefault
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"title": "Hành động người dùng",
|
||||
"following": {
|
||||
"action_false": "Theo dõi người này",
|
||||
"action_true": "Ngưng theo dõi người này"
|
||||
"action_true": "Bỏ theo dõi người này"
|
||||
},
|
||||
"inLists": "Danh sách người ...",
|
||||
"showBoosts": {
|
||||
|
@ -57,7 +57,7 @@
|
|||
"hashtag": {
|
||||
"follow": {
|
||||
"action_false": "Theo dõi",
|
||||
"action_true": "Ngưng theo dõi"
|
||||
"action_true": "Bỏ theo dõi"
|
||||
},
|
||||
"filter": {
|
||||
"action": "Lọc hashtag..."
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"error": "Xảy ra lỗi khi tải",
|
||||
"blocked_by": "Đã chặn",
|
||||
"blocking": "Bỏ chặn",
|
||||
"following": "Ngưng theo dõi",
|
||||
"following": "Bỏ theo dõi",
|
||||
"requested": "Yêu cầu theo dõi",
|
||||
"default": "Theo dõi"
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ const ScreenTabs = () => {
|
|||
case 'Tab-Me':
|
||||
return (
|
||||
<>
|
||||
<ContextMenu.Root onOpenChange={() => haptics('Light')}>
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger>
|
||||
<View
|
||||
key={avatarStatic}
|
||||
|
@ -112,7 +112,6 @@ const ScreenTabs = () => {
|
|||
onValueChange={async () => {
|
||||
if (!account.active) {
|
||||
await setAccount(account.key)
|
||||
haptics('Light')
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -144,17 +143,7 @@ const ScreenTabs = () => {
|
|||
{() => null}
|
||||
</Tab.Screen>
|
||||
<Tab.Screen name='Tab-Notifications' component={TabNotifications} />
|
||||
<Tab.Screen
|
||||
name='Tab-Me'
|
||||
component={TabMe}
|
||||
// listeners={({ navigation }) => ({
|
||||
// tabLongPress: () => {
|
||||
// haptics('Light')
|
||||
// navigation.navigate('Tab-Me', { screen: 'Tab-Me-Root' })
|
||||
// navigation.navigate('Tab-Me', { screen: 'Tab-Me-Switch' })
|
||||
// }
|
||||
// })}
|
||||
/>
|
||||
<Tab.Screen name='Tab-Me' component={TabMe} />
|
||||
</Tab.Navigator>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -34,5 +34,7 @@ const features: { feature: Features; version: number }[] = [
|
|||
]
|
||||
|
||||
export const featureCheck = (feature: Features, v?: string): boolean =>
|
||||
(features.find(f => f.feature === feature)?.version || 999) <=
|
||||
parseFloat(v || getAccountStorage.string('version'))
|
||||
v || getAccountStorage.string('version')
|
||||
? (features.find(f => f.feature === feature)?.version || 999) <=
|
||||
parseFloat(v || getAccountStorage.string('version'))
|
||||
: false
|
||||
|
|
Loading…
Reference in New Issue