mirror of https://github.com/tooot-app/app
Added fastlane and other updates
This commit is contained in:
parent
253ddee319
commit
1072d88191
5
.envrc
5
.envrc
|
@ -1,5 +0,0 @@
|
|||
export SENTRY_ORGANIZATION="xmflsct"
|
||||
export SENTRY_PROJECT="tooot-app"
|
||||
export SENTRY_DEPLOY_ENV="expo"
|
||||
export SENTRY_AUTH_TOKEN="dbccffb69144454784f2171ee7e39211b54392e5b535439aa5b77f2681578f4c"
|
||||
export SENTRY_DSN="https://835b42fb2b25463284edb5a7e18c377d@o389581.ingest.sentry.io/5571975"
|
|
@ -1,8 +1,8 @@
|
|||
name: Publish testing
|
||||
name: Publish development
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*-testing'
|
||||
- '*-development'
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -27,5 +27,5 @@ jobs:
|
|||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
SENTRY_DEPLOY_ENV: testing
|
||||
SENTRY_DEPLOY_ENV: development
|
||||
run: expo publish --release-channel=${GITHUB_REF#refs/heads/}
|
|
@ -17,6 +17,8 @@ web-build/
|
|||
coverage/
|
||||
builds/
|
||||
|
||||
fastlane/id_rsa
|
||||
|
||||
# @generated expo-cli sync-28e2ab0e9ece60556eaf932abe52d017ec33db50
|
||||
# The following patterns were generated by expo-cli
|
||||
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.3)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.422.0)
|
||||
aws-sdk-core (3.111.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.41.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.87.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
claide (1.0.3)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
declarative (0.0.20)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.6.3)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.6)
|
||||
emoji_regex (3.2.1)
|
||||
excon (0.78.1)
|
||||
faraday (1.3.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
faraday-cookie_jar (0.0.7)
|
||||
faraday (>= 0.8.0)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday_middleware (1.0.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.1)
|
||||
fastlane (2.172.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
aws-sdk-s3 (~> 1.0)
|
||||
babosa (>= 1.0.3, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 4.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 1.0)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.37.0, < 0.39.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
rubyzip (>= 2.0.0, < 3.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.38.0)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.9)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.12)
|
||||
google-apis-core (0.2.1)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.14)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
rexml
|
||||
signet (~> 0.14)
|
||||
webrick
|
||||
google-apis-iamcredentials_v1 (0.1.0)
|
||||
google-apis-core (~> 0.1)
|
||||
google-apis-storage_v1 (0.1.0)
|
||||
google-apis-core (~> 0.1)
|
||||
google-cloud-core (1.5.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.4.0)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
google-cloud-errors (1.0.1)
|
||||
google-cloud-storage (1.30.0)
|
||||
addressable (~> 2.5)
|
||||
digest-crc (~> 0.4)
|
||||
google-apis-iamcredentials_v1 (~> 0.1)
|
||||
google-apis-storage_v1 (~> 0.1)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (~> 0.9)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (0.15.0)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.14)
|
||||
highline (1.7.10)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.4.0)
|
||||
json (2.5.1)
|
||||
jwt (2.2.2)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.11.0)
|
||||
mini_mime (1.0.2)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
os (1.1.1)
|
||||
plist (3.6.0)
|
||||
public_suffix (4.0.6)
|
||||
rake (13.0.3)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.2.4)
|
||||
rouge (2.0.7)
|
||||
ruby2_keywords (0.0.4)
|
||||
rubyzip (2.3.0)
|
||||
security (0.1.3)
|
||||
signet (0.14.1)
|
||||
addressable (~> 2.3)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.8)
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
tty-cursor (0.7.1)
|
||||
tty-screen (0.8.1)
|
||||
tty-spinner (0.9.3)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
webrick (1.7.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.19.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.3.0)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
1.17.2
|
|
@ -43,4 +43,5 @@
|
|||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<application android:requestLegacyExternalStorage="true"/>
|
||||
</manifest>
|
|
@ -0,0 +1,82 @@
|
|||
$ExpoSDK = '40.0.0'
|
||||
$ExpoRelease = '40'
|
||||
|
||||
fastlane_version '2.172.0'
|
||||
|
||||
platform :ios do
|
||||
desc 'Build and deploy'
|
||||
private_lane :build do |options|
|
||||
branch = 'RELEASE-TYPE'.gsub('RELEASE', $ExpoRelease).gsub('TYPE', options[:type])
|
||||
|
||||
case options[:type]
|
||||
when 'staging', 'production'
|
||||
ensure_git_branch(
|
||||
branch: branch
|
||||
)
|
||||
ensure_git_status_clean
|
||||
build_number = Time.new.strftime('%y%m%d%k')
|
||||
increment_build_number build_number: build_number
|
||||
end
|
||||
|
||||
match(
|
||||
type: options[:type],
|
||||
readonly: true
|
||||
)
|
||||
|
||||
set_info_plist_value(
|
||||
path: './ios/tooot/Supporting/Expo.plist',
|
||||
key: 'EXUpdatesSDKVersion',
|
||||
value: $ExpoSDK
|
||||
)
|
||||
set_info_plist_value(
|
||||
path: './ios/tooot/Supporting/Expo.plist',
|
||||
key: 'EXUpdatesReleaseChannel',
|
||||
value: branch
|
||||
)
|
||||
|
||||
case options[:type]
|
||||
when 'development'
|
||||
build_ios_app(
|
||||
scheme: 'tooot',
|
||||
silent: true,
|
||||
include_bitcode: true,
|
||||
workspace: './ios/tooot.xcworkspace',
|
||||
output_directory: './build/ios',
|
||||
output_name: 'development',
|
||||
export_method: 'development'
|
||||
)
|
||||
install_on_device(
|
||||
skip_wifi: true,
|
||||
ipa: './build/ios/development.ipa'
|
||||
)
|
||||
when 'staging'
|
||||
build_ios_app(
|
||||
scheme: 'tooot',
|
||||
workspace: './ios/tooot.xcworkspace'
|
||||
)
|
||||
upload_to_testflight(
|
||||
api_key: '{"key_id": "KEY_ID", "issuer_id": "ISSUER_ID", "key_filepath": "appstore.p8"}'.gsub('KEY_ID', ENV['APP_STORE_KEY_ID']).gsub('ISSUER_ID', ENV['APP_STORE_ISSUER_ID']),
|
||||
skip_submission: true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Build development to phone'
|
||||
lane :development do
|
||||
build(type: 'development')
|
||||
end
|
||||
|
||||
desc 'Build staging to TestFlight'
|
||||
lane :staging do
|
||||
build(type: 'staging')
|
||||
end
|
||||
|
||||
desc 'Build product to App Store'
|
||||
lane :production do
|
||||
build(type: 'production')
|
||||
end
|
||||
end
|
||||
|
||||
platform :android do
|
||||
# Android Lanes
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
git_url(ENV('MATCH_GIT_REPO'))
|
||||
git_user_email("me@xmflsct.com")
|
||||
git_private_key("./id_rsa")
|
||||
|
||||
storage_mode("git")
|
||||
|
||||
type("development")
|
||||
|
||||
app_identifier(["com.xmflsct.app.tooot"])
|
||||
username(ENV['APP_STORE_EMAIL'])
|
|
@ -0,0 +1,39 @@
|
|||
fastlane documentation
|
||||
================
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
Install _fastlane_ using
|
||||
```
|
||||
[sudo] gem install fastlane -NV
|
||||
```
|
||||
or alternatively using `brew install fastlane`
|
||||
|
||||
# Available Actions
|
||||
## iOS
|
||||
### ios development
|
||||
```
|
||||
fastlane ios development
|
||||
```
|
||||
Build development to phone
|
||||
### ios staging
|
||||
```
|
||||
fastlane ios staging
|
||||
```
|
||||
Build staging to TestFlight
|
||||
### ios production
|
||||
```
|
||||
fastlane ios production
|
||||
```
|
||||
Build product to App Store
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
|
@ -0,0 +1,43 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite name="fastlane.lanes">
|
||||
|
||||
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="0: Verifying fastlane version" time="0.000454">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="1: Switch to ios build lane" time="0.00019">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="2: match" time="3.907079">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="3: set_info_plist_value" time="0.003664">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="4: set_info_plist_value" time="0.002893">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="5: build_ios_app" time="557.460706">
|
||||
|
||||
</testcase>
|
||||
|
||||
|
||||
<testcase classname="fastlane.lanes" name="6: install_on_device" time="3.305225">
|
||||
|
||||
</testcase>
|
||||
|
||||
</testsuite>
|
||||
</testsuites>
|
11
ios/Podfile
11
ios/Podfile
|
@ -22,3 +22,14 @@ target 'tooot' do
|
|||
# flipper_post_install(installer)
|
||||
# end
|
||||
end
|
||||
|
||||
# https://github.com/CocoaPods/CocoaPods/issues/9884
|
||||
post_install do |pi|
|
||||
pi.pods_project.targets.each do |t|
|
||||
t.build_configurations.each do |bc|
|
||||
if bc.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] == '8.0'
|
||||
bc.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -334,6 +334,8 @@ PODS:
|
|||
- React
|
||||
- react-native-blurhash (1.0.29):
|
||||
- React
|
||||
- react-native-cameraroll (4.0.2):
|
||||
- React-Core
|
||||
- react-native-netinfo (5.9.10):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (3.1.9):
|
||||
|
@ -524,6 +526,7 @@ DEPENDENCIES:
|
|||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
|
||||
- react-native-blurhash (from `../node_modules/react-native-blurhash`)
|
||||
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
|
||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- "react-native-segmented-control (from `../node_modules/@react-native-community/segmented-control`)"
|
||||
|
@ -669,6 +672,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/@react-native-community/blur"
|
||||
react-native-blurhash:
|
||||
:path: "../node_modules/react-native-blurhash"
|
||||
react-native-cameraroll:
|
||||
:path: "../node_modules/@react-native-community/cameraroll"
|
||||
react-native-netinfo:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-safe-area-context:
|
||||
|
@ -802,6 +807,7 @@ SPEC CHECKSUMS:
|
|||
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
|
||||
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
|
||||
react-native-blurhash: 90886ae897cafbbdf2773cb3654656bcb34e8f43
|
||||
react-native-cameraroll: 1965db75c851b15e77a22ca0ac78e32af6b571ae
|
||||
react-native-netinfo: 30fb89fa913c342be82a887b56e96be6d71201dd
|
||||
react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
|
||||
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
|
||||
|
@ -843,6 +849,6 @@ SPEC CHECKSUMS:
|
|||
UMTaskManagerInterface: 4c60b43eaf3cb05a164bc9113258a171c18b7bf7
|
||||
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
||||
|
||||
PODFILE CHECKSUM: cda6b7a1593395b311286b33b0036167ce6f0a15
|
||||
PODFILE CHECKSUM: 45a588d6415c6afb7aa7c5ef73a2ca1e38011f49
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4</string>
|
||||
<string>0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
|
@ -74,6 +74,8 @@
|
|||
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Give $(PRODUCT_NAME) permission to save photos</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Give $(PRODUCT_NAME) permission to save photos</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Give $(PRODUCT_NAME) permission to access your camera</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>EXUpdatesSDKVersion</key>
|
||||
<string>40.0.0</string>
|
||||
<key>EXUpdatesURL</key>
|
||||
<string>https://exp.host/@xmflsct/tooot</string>
|
||||
<key>EXUpdatesEnabled</key>
|
||||
<true/>
|
||||
<key>EXUpdatesCheckOnLaunch</key>
|
||||
<string>ALWAYS</string>
|
||||
<key>EXUpdatesLaunchWaitMs</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
<dict>
|
||||
<key>EXUpdatesCheckOnLaunch</key>
|
||||
<string>WIFI_ONLY</string>
|
||||
<key>EXUpdatesEnabled</key>
|
||||
<true/>
|
||||
<key>EXUpdatesLaunchWaitMs</key>
|
||||
<integer>0</integer>
|
||||
<key>EXUpdatesReleaseChannel</key>
|
||||
<string>40-development</string>
|
||||
<key>EXUpdatesSDKVersion</key>
|
||||
<string>40.0.0</string>
|
||||
<key>EXUpdatesURL</key>
|
||||
<string>https://exp.host/@xmflsct/tooot</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"start": "react-native start",
|
||||
"android": "react-native run-android",
|
||||
"ios": "react-native run-ios",
|
||||
"web": "expo start --web",
|
||||
"eject": "expo eject",
|
||||
"ios:development": "bundle exec fastlane ios development",
|
||||
"test": "jest --watchAll",
|
||||
"release": "scripts/release.sh"
|
||||
},
|
||||
|
@ -13,6 +12,7 @@
|
|||
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
|
||||
"@react-native-async-storage/async-storage": "^1.13.3",
|
||||
"@react-native-community/blur": "^3.6.0",
|
||||
"@react-native-community/cameraroll": "^4.0.2",
|
||||
"@react-native-community/masked-view": "0.1.10",
|
||||
"@react-native-community/netinfo": "^5.9.10",
|
||||
"@react-native-community/segmented-control": "2.2.2",
|
||||
|
|
|
@ -9,12 +9,16 @@ interface IImageInfo {
|
|||
declare namespace Nav {
|
||||
type RootStackParamList = {
|
||||
'Screen-Tabs': undefined
|
||||
'Screen-Actions': {
|
||||
queryKey: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
url?: string
|
||||
type?: 'status' | 'account'
|
||||
}
|
||||
'Screen-Actions':
|
||||
| {
|
||||
type: 'status'
|
||||
queryKey: QueryKeyTimeline
|
||||
status: Mastodon.Status
|
||||
}
|
||||
| {
|
||||
type: 'account'
|
||||
account: Mastodon.Account
|
||||
}
|
||||
'Screen-Announcements': { showAll: boolean }
|
||||
'Screen-Compose':
|
||||
| {
|
||||
|
@ -61,6 +65,11 @@ declare namespace Nav {
|
|||
}
|
||||
}
|
||||
|
||||
type ScreenComposeStackParamList = {
|
||||
'Screen-Compose-Root': undefined
|
||||
'Screen-Compose-EditAttachment': { index: number }
|
||||
}
|
||||
|
||||
type ScreenTabsStackParamList = {
|
||||
'Tab-Local': undefined
|
||||
'Tab-Public': undefined
|
||||
|
@ -95,11 +104,6 @@ declare namespace Nav {
|
|||
'Tab-Public-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
||||
type TabComposeStackParamList = {
|
||||
'Tab-Compose-Root': undefined
|
||||
'Tab-Compose-EditAttachment': unknown
|
||||
}
|
||||
|
||||
type TabNotificationsStackParamList = {
|
||||
'Tab-Notifications-Root': undefined
|
||||
} & TabSharedStackParamList
|
||||
|
|
|
@ -200,7 +200,7 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
|
|||
}}
|
||||
sharedElements={route => {
|
||||
const { imageIndex, imageUrls } = route.params
|
||||
return [{ id: `image.${imageUrls[imageIndex].url}`, debug: true }]
|
||||
return [{ id: `image.${imageUrls[imageIndex].url}` }]
|
||||
}}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
|
|
|
@ -28,5 +28,7 @@ export default {
|
|||
componentParse: require('./components/parse').default,
|
||||
componentRelationship: require('./components/relationship').default,
|
||||
componentRelativeTime: require('./components/relativeTime').default,
|
||||
componentTimeline: require('./components/timeline').default
|
||||
componentTimeline: require('./components/timeline').default,
|
||||
|
||||
screenImageViewer: require('./screens/screenImageViewer').default
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ export default {
|
|||
heading: '$t(sharedAnnouncements:heading)',
|
||||
content: {
|
||||
unread: '{{amount}} unread',
|
||||
read: 'All read'
|
||||
read: 'All read',
|
||||
empty: 'None'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -40,6 +40,9 @@ export default {
|
|||
review: {
|
||||
heading: 'Review tooot'
|
||||
},
|
||||
contact: {
|
||||
heading: 'Contact tooot'
|
||||
},
|
||||
analytics: {
|
||||
heading: 'Help us improve',
|
||||
description: 'Collecting only non-user relative usage'
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
export default {
|
||||
content: {
|
||||
options: {
|
||||
save: 'Save image',
|
||||
share: 'Share iamge',
|
||||
cancel: '$t(common:buttons.cancel)'
|
||||
},
|
||||
save: {
|
||||
function: 'Saving image',
|
||||
success: 'Image saved'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,5 +28,7 @@ export default {
|
|||
componentParse: require('./components/parse').default,
|
||||
componentRelationship: require('./components/relationship').default,
|
||||
componentRelativeTime: require('./components/relativeTime').default,
|
||||
componentTimeline: require('./components/timeline').default
|
||||
componentTimeline: require('./components/timeline').default,
|
||||
|
||||
screenImageViewer: require('./screens/screenImageViewer').default
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ export default {
|
|||
heading: '$t(sharedAnnouncements:heading)',
|
||||
content: {
|
||||
unread: '{{amount}} 条未读公告',
|
||||
read: '无未读公告'
|
||||
read: '无未读公告',
|
||||
empty: '无公告'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -40,6 +40,9 @@ export default {
|
|||
review: {
|
||||
heading: '给 tooot 打分'
|
||||
},
|
||||
contact: {
|
||||
heading: '联系 tooot'
|
||||
},
|
||||
analytics: {
|
||||
heading: '帮助我们改进',
|
||||
description: '收集不与用户相关联的使用信息'
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
export default {
|
||||
content: {
|
||||
options: {
|
||||
save: '保存图片',
|
||||
share: '分享图片',
|
||||
cancel: '$t(common:buttons.cancel)'
|
||||
},
|
||||
save: {
|
||||
function: '保存图片',
|
||||
success: '图片保存成功'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import { StackScreenProps } from '@react-navigation/stack'
|
|||
import { getLocalAccount, getLocalUrl } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||
import {
|
||||
PanGestureHandler,
|
||||
|
@ -31,20 +31,29 @@ export type ScreenAccountProp = StackScreenProps<
|
|||
>
|
||||
|
||||
const ScreenActions = React.memo(
|
||||
({
|
||||
route: {
|
||||
params: { queryKey, status, url, type }
|
||||
},
|
||||
navigation
|
||||
}: ScreenAccountProp) => {
|
||||
({ route: { params }, navigation }: ScreenAccountProp) => {
|
||||
const localAccount = useSelector(getLocalAccount)
|
||||
const sameAccount = localAccount?.id === status.account.id
|
||||
let sameAccount = false
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
sameAccount = localAccount?.id === params.status.account.id
|
||||
break
|
||||
case 'account':
|
||||
sameAccount = localAccount?.id === params.account.id
|
||||
break
|
||||
}
|
||||
|
||||
const localDomain = useSelector(getLocalUrl)
|
||||
const statusDomain = status.uri
|
||||
? status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
||||
: ''
|
||||
const sameDomain = localDomain === statusDomain
|
||||
let sameDomain = true
|
||||
let statusDomain: string
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
statusDomain = params.status.uri
|
||||
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
||||
: ''
|
||||
sameDomain = localDomain === statusDomain
|
||||
break
|
||||
}
|
||||
|
||||
const { theme } = useTheme()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
@ -82,6 +91,56 @@ const ScreenActions = React.memo(
|
|||
}
|
||||
})
|
||||
|
||||
const actions = useMemo(() => {
|
||||
switch (params.type) {
|
||||
case 'status':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount && (
|
||||
<ActionsAccount
|
||||
queryKey={params.queryKey}
|
||||
account={params.status.account}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)}
|
||||
{sameAccount && params.status && (
|
||||
<ActionsStatus
|
||||
navigation={navigation}
|
||||
queryKey={params.queryKey}
|
||||
status={params.status}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)}
|
||||
{!sameDomain && statusDomain && (
|
||||
<ActionsDomain
|
||||
queryKey={params.queryKey}
|
||||
domain={statusDomain}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)}
|
||||
<ActionsShare
|
||||
url={params.status.url || params.status.uri}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
case 'account':
|
||||
return (
|
||||
<>
|
||||
{!sameAccount && (
|
||||
<ActionsAccount account={params.account} dismiss={dismiss} />
|
||||
)}
|
||||
<ActionsShare
|
||||
url={params.account.url}
|
||||
type={params.type}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Animated.View style={{ flex: 1 }}>
|
||||
<TapGestureHandler
|
||||
|
@ -114,34 +173,7 @@ const ScreenActions = React.memo(
|
|||
{ backgroundColor: theme.primaryOverlay }
|
||||
]}
|
||||
/>
|
||||
{!sameAccount && (
|
||||
<ActionsAccount
|
||||
queryKey={queryKey}
|
||||
account={status.account}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)}
|
||||
|
||||
{sameAccount && status && (
|
||||
<ActionsStatus
|
||||
navigation={navigation}
|
||||
queryKey={queryKey}
|
||||
status={status}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!sameDomain && (
|
||||
<ActionsDomain
|
||||
queryKey={queryKey}
|
||||
domain={statusDomain}
|
||||
dismiss={dismiss}
|
||||
/>
|
||||
)}
|
||||
|
||||
{url && type ? (
|
||||
<ActionsShare url={url} type={type} dismiss={dismiss} />
|
||||
) : null}
|
||||
{actions}
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
</Animated.View>
|
||||
|
|
|
@ -229,7 +229,7 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.base}
|
||||
style={[styles.base, {backgroundColor: 'red'}]}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
>
|
||||
<SafeAreaView
|
||||
|
@ -237,14 +237,17 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||
edges={hasKeyboard ? ['top'] : ['top', 'bottom']}
|
||||
>
|
||||
<ComposeContext.Provider value={{ composeState, composeDispatch }}>
|
||||
<Stack.Navigator screenOptions={{ headerTopInsetEnabled: false }}>
|
||||
<Stack.Navigator
|
||||
screenOptions={{ headerTopInsetEnabled: false }}
|
||||
initialRouteName='Screen-Compose-Root'
|
||||
>
|
||||
<Stack.Screen
|
||||
name='Tab-Compose-Root'
|
||||
name='Screen-Compose-Root'
|
||||
component={ComposeRoot}
|
||||
options={{ headerLeft, headerCenter, headerRight }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Compose-EditAttachment'
|
||||
name='Screen-Compose-EditAttachment'
|
||||
component={ComposeEditAttachment}
|
||||
options={{ stackPresentation: 'modal', headerShown: false }}
|
||||
/>
|
||||
|
|
|
@ -2,6 +2,7 @@ import client from '@api/client'
|
|||
import analytics from '@components/analytics'
|
||||
import haptics from '@components/haptics'
|
||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
|
@ -18,16 +19,12 @@ import ComposeContext from './utils/createContext'
|
|||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
export interface Props {
|
||||
route: {
|
||||
params: {
|
||||
index: number
|
||||
}
|
||||
}
|
||||
navigation: any
|
||||
}
|
||||
export type ScreenComposeEditAttachmentProp = StackScreenProps<
|
||||
Nav.ScreenComposeStackParamList,
|
||||
'Screen-Compose-EditAttachment'
|
||||
>
|
||||
|
||||
const ComposeEditAttachment: React.FC<Props> = ({
|
||||
const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
||||
route: {
|
||||
params: { index }
|
||||
},
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
import analytics from '@components/analytics'
|
||||
import { HeaderRight } from '@components/Header'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { StackScreenProps } from '@react-navigation/stack'
|
||||
import CameraRoll from '@react-native-community/cameraroll'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import { findIndex } from 'lodash'
|
||||
import React, { useCallback, useLayoutEffect, useState } from 'react'
|
||||
import { Platform, Share, StyleSheet, Text } from 'react-native'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
PermissionsAndroid,
|
||||
Platform,
|
||||
Share,
|
||||
StyleSheet,
|
||||
Text
|
||||
} from 'react-native'
|
||||
import FastImage from 'react-native-fast-image'
|
||||
import ImageViewer from 'react-native-image-zoom-viewer'
|
||||
import { SharedElement } from 'react-navigation-shared-element'
|
||||
import { toast } from '@components/toast'
|
||||
|
||||
export type ScreenImagesViewerProp = StackScreenProps<
|
||||
Nav.RootStackParamList,
|
||||
|
@ -27,14 +37,70 @@ const ScreenImagesViewer = React.memo(
|
|||
findIndex(imageUrls, ['imageIndex', imageIndex])
|
||||
)
|
||||
|
||||
const onPress = useCallback(() => {
|
||||
analytics('imageviewer_share_press')
|
||||
switch (Platform.OS) {
|
||||
case 'ios':
|
||||
return Share.share({ url: imageUrls[currentIndex].url })
|
||||
case 'android':
|
||||
return Share.share({ message: imageUrls[currentIndex].url })
|
||||
const hasAndroidPermission = async () => {
|
||||
const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
|
||||
|
||||
const hasPermission = await PermissionsAndroid.check(permission)
|
||||
if (hasPermission) {
|
||||
return true
|
||||
}
|
||||
|
||||
const status = await PermissionsAndroid.request(permission)
|
||||
return status === 'granted'
|
||||
}
|
||||
const saveImage = async () => {
|
||||
if (Platform.OS === 'android' && !(await hasAndroidPermission())) {
|
||||
return
|
||||
}
|
||||
CameraRoll.save(
|
||||
imageUrls[imageIndex].originUrl ||
|
||||
imageUrls[imageIndex].remote_url ||
|
||||
imageUrls[imageIndex].preview_url
|
||||
)
|
||||
.then(() =>
|
||||
toast({ type: 'success', message: t('content.save.success') })
|
||||
)
|
||||
.catch(() =>
|
||||
toast({
|
||||
type: 'error',
|
||||
message: t('common:toastMessage.error.message', {
|
||||
function: t('content.save.function')
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const { t } = useTranslation('screenImageViewer')
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const onPress = useCallback(() => {
|
||||
analytics('imageviewer_more_press')
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
options: [
|
||||
t('content.options.save'),
|
||||
t('content.options.share'),
|
||||
t('content.options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
},
|
||||
async buttonIndex => {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
analytics('imageviewer_more_save_press')
|
||||
saveImage()
|
||||
break
|
||||
case 1:
|
||||
analytics('imageviewer_more_share_press')
|
||||
switch (Platform.OS) {
|
||||
case 'ios':
|
||||
return Share.share({ url: imageUrls[currentIndex].url })
|
||||
case 'android':
|
||||
return Share.share({ message: imageUrls[currentIndex].url })
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
}, [currentIndex])
|
||||
|
||||
useLayoutEffect(
|
||||
|
@ -48,7 +114,11 @@ const ScreenImagesViewer = React.memo(
|
|||
</Text>
|
||||
),
|
||||
headerRight: () => (
|
||||
<HeaderRight content='Share' native={false} onPress={onPress} />
|
||||
<HeaderRight
|
||||
content='MoreHorizontal'
|
||||
native={false}
|
||||
onPress={onPress}
|
||||
/>
|
||||
)
|
||||
}),
|
||||
[currentIndex]
|
||||
|
@ -77,6 +147,7 @@ const ScreenImagesViewer = React.memo(
|
|||
style={{ flex: 1 }}
|
||||
onChange={index => index !== undefined && setCurrentIndex(index)}
|
||||
renderImage={renderImage}
|
||||
onLongPress={saveImage}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -26,7 +26,7 @@ import TabPublic from './Tabs/Public'
|
|||
export type ScreenTabsParamList = {
|
||||
'Tab-Local': NavigatorScreenParams<Nav.TabLocalStackParamList>
|
||||
'Tab-Public': NavigatorScreenParams<Nav.TabPublicStackParamList>
|
||||
'Tab-Compose': NavigatorScreenParams<Nav.TabComposeStackParamList>
|
||||
'Tab-Compose': NavigatorScreenParams<Nav.ScreenComposeStackParamList>
|
||||
'Tab-Notifications': NavigatorScreenParams<Nav.TabNotificationsStackParamList>
|
||||
'Tab-Me': NavigatorScreenParams<Nav.TabMeStackParamList>
|
||||
}
|
||||
|
|
|
@ -8,15 +8,23 @@ const Collections: React.FC = () => {
|
|||
const { t, i18n } = useTranslation('meRoot')
|
||||
const navigation = useNavigation()
|
||||
|
||||
const { data, isFetching } = useAnnouncementQuery({ showAll: true })
|
||||
const { data, isFetching } = useAnnouncementQuery({
|
||||
showAll: true
|
||||
})
|
||||
|
||||
const announcementContent = useMemo(() => {
|
||||
if (data) {
|
||||
const amount = data.filter(announcement => !announcement.read).length
|
||||
if (amount) {
|
||||
return t('content.collections.announcements.content.unread', { amount })
|
||||
if (data.length === 0) {
|
||||
return t('content.collections.announcements.content.empty')
|
||||
} else {
|
||||
return t('content.collections.announcements.content.read')
|
||||
const amount = data.filter(announcement => !announcement.read).length
|
||||
if (amount) {
|
||||
return t('content.collections.announcements.content.unread', {
|
||||
amount
|
||||
})
|
||||
} else {
|
||||
return t('content.collections.announcements.content.read')
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [data, i18n.language])
|
||||
|
@ -49,7 +57,7 @@ const Collections: React.FC = () => {
|
|||
/>
|
||||
<MenuRow
|
||||
iconFront='Clipboard'
|
||||
iconBack='ChevronRight'
|
||||
iconBack={data && data.length === 0 ? undefined : 'ChevronRight'}
|
||||
title={t('content.collections.announcements.heading')}
|
||||
content={announcementContent}
|
||||
loading={isFetching}
|
||||
|
|
|
@ -13,7 +13,10 @@ const ScreenMeSettings: React.FC = () => {
|
|||
<SettingsTooot />
|
||||
<SettingsAnalytics />
|
||||
|
||||
{__DEV__ || Constants.manifest.releaseChannel?.includes('testing') ? (
|
||||
{__DEV__ ||
|
||||
['development'].some(channel =>
|
||||
Constants.manifest.releaseChannel?.includes(channel)
|
||||
) ? (
|
||||
<SettingsDev />
|
||||
) : null}
|
||||
</ScrollView>
|
||||
|
|
|
@ -25,7 +25,7 @@ const SettingsApp: React.FC = () => {
|
|||
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||
const settingsTheme = useSelector(getSettingsTheme)
|
||||
const settingsBrowser = useSelector(getSettingsBrowser)
|
||||
|
||||
console.log(settingsLanguage)
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
|
@ -37,7 +37,9 @@ const SettingsApp: React.FC = () => {
|
|||
i18n.services.resourceStore.data
|
||||
)
|
||||
const options = availableLanguages
|
||||
.map(language => t(`content.language.options.${language}`))
|
||||
.map(language => {
|
||||
return t(`content.language.options.${language}`)
|
||||
})
|
||||
.concat(t('content.language.options.cancel'))
|
||||
|
||||
showActionSheetWithOptions(
|
||||
|
@ -47,7 +49,7 @@ const SettingsApp: React.FC = () => {
|
|||
cancelButtonIndex: options.length - 1
|
||||
},
|
||||
buttonIndex => {
|
||||
if (buttonIndex < options.length) {
|
||||
if (buttonIndex < options.length - 1) {
|
||||
analytics('settings_language_press', {
|
||||
current: i18n.language,
|
||||
new: availableLanguages[buttonIndex]
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useSearchQuery } from '@utils/queryHooks/search'
|
|||
import { getLocalActiveIndex } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import Constants from 'expo-constants'
|
||||
import * as Linking from 'expo-linking'
|
||||
import * as StoreReview from 'expo-store-review'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
|
@ -41,19 +42,30 @@ const SettingsTooot: React.FC = () => {
|
|||
Linking.openURL('https://www.patreon.com/xmflsct')
|
||||
}}
|
||||
/>
|
||||
{__DEV__ ||
|
||||
['production', 'development'].some(channel =>
|
||||
Constants.manifest.releaseChannel?.includes(channel)
|
||||
) ? (
|
||||
<MenuRow
|
||||
title={t('content.review.heading')}
|
||||
content={
|
||||
<Icon
|
||||
name='Star'
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color='#FF9500'
|
||||
/>
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
analytics('settings_review_press')
|
||||
StoreReview.isAvailableAsync().then(() =>
|
||||
StoreReview.requestReview()
|
||||
)
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<MenuRow
|
||||
title={t('content.review.heading')}
|
||||
content={
|
||||
<Icon name='Star' size={StyleConstants.Font.Size.M} color='#FF9500' />
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
analytics('settings_review_press')
|
||||
StoreReview.isAvailableAsync().then(() => StoreReview.requestReview())
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={'联系 tooot'}
|
||||
title={t('content.contact.heading')}
|
||||
loading={isLoading}
|
||||
content={
|
||||
<Icon
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import analytics from '@components/analytics'
|
||||
import Button from '@components/Button'
|
||||
import haptics from '@components/haptics'
|
||||
import ComponentInstance from '@components/Instance'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import {
|
||||
|
@ -48,6 +49,7 @@ const AccountButton: React.FC<Props> = ({
|
|||
disabled ? ' ✓' : ''
|
||||
}`}
|
||||
onPress={() => {
|
||||
haptics('Light')
|
||||
analytics('switch_existing_press')
|
||||
dispatch(localUpdateActiveIndex(index))
|
||||
queryClient.clear()
|
||||
|
@ -77,14 +79,21 @@ const ScreenMeSwitchRoot: React.FC = () => {
|
|||
</Text>
|
||||
<View style={styles.accountButtons}>
|
||||
{localInstances.length
|
||||
? localInstances.map((instance, index) => (
|
||||
<AccountButton
|
||||
key={index}
|
||||
index={index}
|
||||
instance={instance}
|
||||
disabled={localActiveIndex === index}
|
||||
/>
|
||||
))
|
||||
? localInstances
|
||||
.slice()
|
||||
.sort((a, b) =>
|
||||
`${a.uri}${a.account.acct}`.localeCompare(
|
||||
`${b.uri}${b.account.acct}`
|
||||
)
|
||||
)
|
||||
.map((instance, index) => (
|
||||
<AccountButton
|
||||
key={index}
|
||||
index={index}
|
||||
instance={instance}
|
||||
disabled={localActiveIndex === index}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
import analytics from '@components/analytics'
|
||||
import { HeaderRight } from '@components/Header'
|
||||
import Timeline from '@components/Timelines/Timeline'
|
||||
import HeaderActionsAccount from '@components/Timelines/Timeline/Shared/HeaderActions/Account'
|
||||
import HeaderActionsShare from '@components/Timelines/Timeline/Shared/HeaderActions/Share'
|
||||
import { useAccountQuery } from '@utils/queryHooks/account'
|
||||
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useReducer,
|
||||
useState
|
||||
} from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useReducer } from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { useSharedValue } from 'react-native-reanimated'
|
||||
import { useSelector } from 'react-redux'
|
||||
import AccountAttachments from './Account/Attachments'
|
||||
import AccountHeader from './Account/Header'
|
||||
import AccountInformation from './Account/Information'
|
||||
|
@ -33,7 +23,6 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||
}) => {
|
||||
const { theme } = useTheme()
|
||||
|
||||
const localAccount = useSelector(getLocalAccount)
|
||||
const { data } = useAccountQuery({ id: account.id })
|
||||
|
||||
const scrollY = useSharedValue(0)
|
||||
|
@ -42,7 +31,6 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||
accountInitialState
|
||||
)
|
||||
|
||||
const [modalVisible, setBottomSheetVisible] = useState(false)
|
||||
useEffect(() => {
|
||||
const updateHeaderRight = () =>
|
||||
navigation.setOptions({
|
||||
|
@ -53,7 +41,10 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||
analytics('bottomsheet_open_press', {
|
||||
page: 'account'
|
||||
})
|
||||
setBottomSheetVisible(true)
|
||||
navigation.navigate('Screen-Actions', {
|
||||
type: 'account',
|
||||
account
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -89,25 +80,6 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||
ListHeaderComponent
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* <BottomSheet
|
||||
visible={modalVisible}
|
||||
handleDismiss={() => setBottomSheetVisible(false)}
|
||||
>
|
||||
添加到列表
|
||||
{localAccount?.id !== account.id && (
|
||||
<HeaderActionsAccount
|
||||
account={account}
|
||||
setBottomSheetVisible={setBottomSheetVisible}
|
||||
/>
|
||||
)}
|
||||
|
||||
<HeaderActionsShare
|
||||
url={account.url}
|
||||
type='account'
|
||||
setBottomSheetVisible={setBottomSheetVisible}
|
||||
/>
|
||||
</BottomSheet> */}
|
||||
</AccountContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import { useNavigation } from '@react-navigation/native'
|
|||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import {
|
||||
|
@ -29,6 +28,8 @@ const AccountAttachments = React.memo(
|
|||
>()
|
||||
const { theme } = useTheme()
|
||||
|
||||
const DISPLAY_AMOUNT = 6
|
||||
|
||||
const width =
|
||||
(Dimensions.get('screen').width -
|
||||
StyleConstants.Spacing.Global.PagePadding * 2) /
|
||||
|
@ -38,7 +39,7 @@ const AccountAttachments = React.memo(
|
|||
page: 'Account_Attachments' as 'Account_Attachments',
|
||||
account: account?.id
|
||||
}
|
||||
const { data, refetch } = useTimelineQuery({
|
||||
const { data, refetch } = useTimelineQuery<Mastodon.Status[]>({
|
||||
...queryKeyParams,
|
||||
options: { enabled: false }
|
||||
})
|
||||
|
@ -48,18 +49,16 @@ const AccountAttachments = React.memo(
|
|||
}
|
||||
}, [account])
|
||||
|
||||
const flattenData = (data?.pages
|
||||
? data.pages.flatMap(d => [...d])
|
||||
: []) as Mastodon.Status[]
|
||||
useEffect(() => {
|
||||
if (flattenData.length) {
|
||||
layoutAnimation()
|
||||
}
|