mirror of
https://github.com/tooot-app/app
synced 2024-12-21 15:14:32 +01:00
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:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- '*-testing'
|
- '*-development'
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -27,5 +27,5 @@ jobs:
|
|||||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
SENTRY_DEPLOY_ENV: testing
|
SENTRY_DEPLOY_ENV: development
|
||||||
run: expo publish --release-channel=${GITHUB_REF#refs/heads/}
|
run: expo publish --release-channel=${GITHUB_REF#refs/heads/}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -17,6 +17,8 @@ web-build/
|
|||||||
coverage/
|
coverage/
|
||||||
builds/
|
builds/
|
||||||
|
|
||||||
|
fastlane/id_rsa
|
||||||
|
|
||||||
# @generated expo-cli sync-28e2ab0e9ece60556eaf932abe52d017ec33db50
|
# @generated expo-cli sync-28e2ab0e9ece60556eaf932abe52d017ec33db50
|
||||||
# The following patterns were generated by expo-cli
|
# The following patterns were generated by expo-cli
|
||||||
|
|
||||||
|
201
Gemfile.lock
Normal file
201
Gemfile.lock
Normal file
@ -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"/>
|
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
|
||||||
</application>
|
</application>
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<application android:requestLegacyExternalStorage="true"/>
|
||||||
</manifest>
|
</manifest>
|
82
fastlane/Fastfile
Normal file
82
fastlane/Fastfile
Normal file
@ -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
|
10
fastlane/Matchfile
Normal file
10
fastlane/Matchfile
Normal file
@ -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'])
|
39
fastlane/README.md
Normal file
39
fastlane/README.md
Normal file
@ -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).
|
43
fastlane/report.xml
Normal file
43
fastlane/report.xml
Normal file
@ -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)
|
# flipper_post_install(installer)
|
||||||
# end
|
# end
|
||||||
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
|
||||||
- react-native-blurhash (1.0.29):
|
- react-native-blurhash (1.0.29):
|
||||||
- React
|
- React
|
||||||
|
- react-native-cameraroll (4.0.2):
|
||||||
|
- React-Core
|
||||||
- react-native-netinfo (5.9.10):
|
- react-native-netinfo (5.9.10):
|
||||||
- React-Core
|
- React-Core
|
||||||
- react-native-safe-area-context (3.1.9):
|
- react-native-safe-area-context (3.1.9):
|
||||||
@ -524,6 +526,7 @@ DEPENDENCIES:
|
|||||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||||
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
|
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
|
||||||
- react-native-blurhash (from `../node_modules/react-native-blurhash`)
|
- 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-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
- 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`)"
|
- "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"
|
:path: "../node_modules/@react-native-community/blur"
|
||||||
react-native-blurhash:
|
react-native-blurhash:
|
||||||
:path: "../node_modules/react-native-blurhash"
|
:path: "../node_modules/react-native-blurhash"
|
||||||
|
react-native-cameraroll:
|
||||||
|
:path: "../node_modules/@react-native-community/cameraroll"
|
||||||
react-native-netinfo:
|
react-native-netinfo:
|
||||||
:path: "../node_modules/@react-native-community/netinfo"
|
:path: "../node_modules/@react-native-community/netinfo"
|
||||||
react-native-safe-area-context:
|
react-native-safe-area-context:
|
||||||
@ -802,6 +807,7 @@ SPEC CHECKSUMS:
|
|||||||
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
|
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
|
||||||
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
|
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
|
||||||
react-native-blurhash: 90886ae897cafbbdf2773cb3654656bcb34e8f43
|
react-native-blurhash: 90886ae897cafbbdf2773cb3654656bcb34e8f43
|
||||||
|
react-native-cameraroll: 1965db75c851b15e77a22ca0ac78e32af6b571ae
|
||||||
react-native-netinfo: 30fb89fa913c342be82a887b56e96be6d71201dd
|
react-native-netinfo: 30fb89fa913c342be82a887b56e96be6d71201dd
|
||||||
react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
|
react-native-safe-area-context: b6e0e284002381d2ff29fa4fff42b4d8282e3c94
|
||||||
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
|
react-native-segmented-control: 65df6cd0619b780b3843d574a72d4c7cec396097
|
||||||
@ -843,6 +849,6 @@ SPEC CHECKSUMS:
|
|||||||
UMTaskManagerInterface: 4c60b43eaf3cb05a164bc9113258a171c18b7bf7
|
UMTaskManagerInterface: 4c60b43eaf3cb05a164bc9113258a171c18b7bf7
|
||||||
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
||||||
|
|
||||||
PODFILE CHECKSUM: cda6b7a1593395b311286b33b0036167ce6f0a15
|
PODFILE CHECKSUM: 45a588d6415c6afb7aa7c5ef73a2ca1e38011f49
|
||||||
|
|
||||||
COCOAPODS: 1.10.1
|
COCOAPODS: 1.10.1
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>4</string>
|
<string>0</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
@ -74,6 +74,8 @@
|
|||||||
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
|
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Give $(PRODUCT_NAME) permission to save photos</string>
|
<string>Give $(PRODUCT_NAME) permission to save photos</string>
|
||||||
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
|
<string>Give $(PRODUCT_NAME) permission to save photos</string>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Give $(PRODUCT_NAME) permission to access your camera</string>
|
<string>Give $(PRODUCT_NAME) permission to access your camera</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
@ -2,15 +2,17 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<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>
|
<key>EXUpdatesSDKVersion</key>
|
||||||
<string>40.0.0</string>
|
<string>40.0.0</string>
|
||||||
<key>EXUpdatesURL</key>
|
<key>EXUpdatesURL</key>
|
||||||
<string>https://exp.host/@xmflsct/tooot</string>
|
<string>https://exp.host/@xmflsct/tooot</string>
|
||||||
<key>EXUpdatesEnabled</key>
|
|
||||||
<true/>
|
|
||||||
<key>EXUpdatesCheckOnLaunch</key>
|
|
||||||
<string>ALWAYS</string>
|
|
||||||
<key>EXUpdatesLaunchWaitMs</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
@ -3,8 +3,7 @@
|
|||||||
"start": "react-native start",
|
"start": "react-native start",
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
"ios": "react-native run-ios",
|
"ios": "react-native run-ios",
|
||||||
"web": "expo start --web",
|
"ios:development": "bundle exec fastlane ios development",
|
||||||
"eject": "expo eject",
|
|
||||||
"test": "jest --watchAll",
|
"test": "jest --watchAll",
|
||||||
"release": "scripts/release.sh"
|
"release": "scripts/release.sh"
|
||||||
},
|
},
|
||||||
@ -13,6 +12,7 @@
|
|||||||
"@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.13.3",
|
"@react-native-async-storage/async-storage": "^1.13.3",
|
||||||
"@react-native-community/blur": "^3.6.0",
|
"@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/masked-view": "0.1.10",
|
||||||
"@react-native-community/netinfo": "^5.9.10",
|
"@react-native-community/netinfo": "^5.9.10",
|
||||||
"@react-native-community/segmented-control": "2.2.2",
|
"@react-native-community/segmented-control": "2.2.2",
|
||||||
|
20
src/@types/react-navigation.d.ts
vendored
20
src/@types/react-navigation.d.ts
vendored
@ -9,11 +9,15 @@ interface IImageInfo {
|
|||||||
declare namespace Nav {
|
declare namespace Nav {
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
'Screen-Tabs': undefined
|
'Screen-Tabs': undefined
|
||||||
'Screen-Actions': {
|
'Screen-Actions':
|
||||||
|
| {
|
||||||
|
type: 'status'
|
||||||
queryKey: QueryKeyTimeline
|
queryKey: QueryKeyTimeline
|
||||||
status: Mastodon.Status
|
status: Mastodon.Status
|
||||||
url?: string
|
}
|
||||||
type?: 'status' | 'account'
|
| {
|
||||||
|
type: 'account'
|
||||||
|
account: Mastodon.Account
|
||||||
}
|
}
|
||||||
'Screen-Announcements': { showAll: boolean }
|
'Screen-Announcements': { showAll: boolean }
|
||||||
'Screen-Compose':
|
'Screen-Compose':
|
||||||
@ -61,6 +65,11 @@ declare namespace Nav {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScreenComposeStackParamList = {
|
||||||
|
'Screen-Compose-Root': undefined
|
||||||
|
'Screen-Compose-EditAttachment': { index: number }
|
||||||
|
}
|
||||||
|
|
||||||
type ScreenTabsStackParamList = {
|
type ScreenTabsStackParamList = {
|
||||||
'Tab-Local': undefined
|
'Tab-Local': undefined
|
||||||
'Tab-Public': undefined
|
'Tab-Public': undefined
|
||||||
@ -95,11 +104,6 @@ declare namespace Nav {
|
|||||||
'Tab-Public-Root': undefined
|
'Tab-Public-Root': undefined
|
||||||
} & TabSharedStackParamList
|
} & TabSharedStackParamList
|
||||||
|
|
||||||
type TabComposeStackParamList = {
|
|
||||||
'Tab-Compose-Root': undefined
|
|
||||||
'Tab-Compose-EditAttachment': unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
type TabNotificationsStackParamList = {
|
type TabNotificationsStackParamList = {
|
||||||
'Tab-Notifications-Root': undefined
|
'Tab-Notifications-Root': undefined
|
||||||
} & TabSharedStackParamList
|
} & TabSharedStackParamList
|
||||||
|
@ -200,7 +200,7 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
|
|||||||
}}
|
}}
|
||||||
sharedElements={route => {
|
sharedElements={route => {
|
||||||
const { imageIndex, imageUrls } = route.params
|
const { imageIndex, imageUrls } = route.params
|
||||||
return [{ id: `image.${imageUrls[imageIndex].url}`, debug: true }]
|
return [{ id: `image.${imageUrls[imageIndex].url}` }]
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
|
@ -28,5 +28,7 @@ export default {
|
|||||||
componentParse: require('./components/parse').default,
|
componentParse: require('./components/parse').default,
|
||||||
componentRelationship: require('./components/relationship').default,
|
componentRelationship: require('./components/relationship').default,
|
||||||
componentRelativeTime: require('./components/relativeTime').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)',
|
heading: '$t(sharedAnnouncements:heading)',
|
||||||
content: {
|
content: {
|
||||||
unread: '{{amount}} unread',
|
unread: '{{amount}} unread',
|
||||||
read: 'All read'
|
read: 'All read',
|
||||||
|
empty: 'None'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -40,6 +40,9 @@ export default {
|
|||||||
review: {
|
review: {
|
||||||
heading: 'Review tooot'
|
heading: 'Review tooot'
|
||||||
},
|
},
|
||||||
|
contact: {
|
||||||
|
heading: 'Contact tooot'
|
||||||
|
},
|
||||||
analytics: {
|
analytics: {
|
||||||
heading: 'Help us improve',
|
heading: 'Help us improve',
|
||||||
description: 'Collecting only non-user relative usage'
|
description: 'Collecting only non-user relative usage'
|
||||||
|
13
src/i18n/en/screens/screenImageViewer.ts
Normal file
13
src/i18n/en/screens/screenImageViewer.ts
Normal file
@ -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,
|
componentParse: require('./components/parse').default,
|
||||||
componentRelationship: require('./components/relationship').default,
|
componentRelationship: require('./components/relationship').default,
|
||||||
componentRelativeTime: require('./components/relativeTime').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)',
|
heading: '$t(sharedAnnouncements:heading)',
|
||||||
content: {
|
content: {
|
||||||
unread: '{{amount}} 条未读公告',
|
unread: '{{amount}} 条未读公告',
|
||||||
read: '无未读公告'
|
read: '无未读公告',
|
||||||
|
empty: '无公告'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -40,6 +40,9 @@ export default {
|
|||||||
review: {
|
review: {
|
||||||
heading: '给 tooot 打分'
|
heading: '给 tooot 打分'
|
||||||
},
|
},
|
||||||
|
contact: {
|
||||||
|
heading: '联系 tooot'
|
||||||
|
},
|
||||||
analytics: {
|
analytics: {
|
||||||
heading: '帮助我们改进',
|
heading: '帮助我们改进',
|
||||||
description: '收集不与用户相关联的使用信息'
|
description: '收集不与用户相关联的使用信息'
|
||||||
|
13
src/i18n/zh-Hans/screens/screenImageViewer.ts
Normal file
13
src/i18n/zh-Hans/screens/screenImageViewer.ts
Normal file
@ -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 { getLocalAccount, getLocalUrl } 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 React, { useCallback, useEffect } from 'react'
|
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||||
import {
|
import {
|
||||||
PanGestureHandler,
|
PanGestureHandler,
|
||||||
@ -31,20 +31,29 @@ export type ScreenAccountProp = StackScreenProps<
|
|||||||
>
|
>
|
||||||
|
|
||||||
const ScreenActions = React.memo(
|
const ScreenActions = React.memo(
|
||||||
({
|
({ route: { params }, navigation }: ScreenAccountProp) => {
|
||||||
route: {
|
|
||||||
params: { queryKey, status, url, type }
|
|
||||||
},
|
|
||||||
navigation
|
|
||||||
}: ScreenAccountProp) => {
|
|
||||||
const localAccount = useSelector(getLocalAccount)
|
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 localDomain = useSelector(getLocalUrl)
|
||||||
const statusDomain = status.uri
|
let sameDomain = true
|
||||||
? status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
let statusDomain: string
|
||||||
|
switch (params.type) {
|
||||||
|
case 'status':
|
||||||
|
statusDomain = params.status.uri
|
||||||
|
? params.status.uri.split(new RegExp(/\/\/(.*?)\//))[1]
|
||||||
: ''
|
: ''
|
||||||
const sameDomain = localDomain === statusDomain
|
sameDomain = localDomain === statusDomain
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const insets = useSafeAreaInsets()
|
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 (
|
return (
|
||||||
<Animated.View style={{ flex: 1 }}>
|
<Animated.View style={{ flex: 1 }}>
|
||||||
<TapGestureHandler
|
<TapGestureHandler
|
||||||
@ -114,34 +173,7 @@ const ScreenActions = React.memo(
|
|||||||
{ backgroundColor: theme.primaryOverlay }
|
{ backgroundColor: theme.primaryOverlay }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
{!sameAccount && (
|
{actions}
|
||||||
<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}
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</PanGestureHandler>
|
</PanGestureHandler>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
@ -229,7 +229,7 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={styles.base}
|
style={[styles.base, {backgroundColor: 'red'}]}
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||||
>
|
>
|
||||||
<SafeAreaView
|
<SafeAreaView
|
||||||
@ -237,14 +237,17 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
|
|||||||
edges={hasKeyboard ? ['top'] : ['top', 'bottom']}
|
edges={hasKeyboard ? ['top'] : ['top', 'bottom']}
|
||||||
>
|
>
|
||||||
<ComposeContext.Provider value={{ composeState, composeDispatch }}>
|
<ComposeContext.Provider value={{ composeState, composeDispatch }}>
|
||||||
<Stack.Navigator screenOptions={{ headerTopInsetEnabled: false }}>
|
<Stack.Navigator
|
||||||
|
screenOptions={{ headerTopInsetEnabled: false }}
|
||||||
|
initialRouteName='Screen-Compose-Root'
|
||||||
|
>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Compose-Root'
|
name='Screen-Compose-Root'
|
||||||
component={ComposeRoot}
|
component={ComposeRoot}
|
||||||
options={{ headerLeft, headerCenter, headerRight }}
|
options={{ headerLeft, headerCenter, headerRight }}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Compose-EditAttachment'
|
name='Screen-Compose-EditAttachment'
|
||||||
component={ComposeEditAttachment}
|
component={ComposeEditAttachment}
|
||||||
options={{ stackPresentation: 'modal', headerShown: false }}
|
options={{ stackPresentation: 'modal', headerShown: false }}
|
||||||
/>
|
/>
|
||||||
|
@ -2,6 +2,7 @@ import client from '@api/client'
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||||
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useContext,
|
useContext,
|
||||||
@ -18,16 +19,12 @@ import ComposeContext from './utils/createContext'
|
|||||||
|
|
||||||
const Stack = createNativeStackNavigator()
|
const Stack = createNativeStackNavigator()
|
||||||
|
|
||||||
export interface Props {
|
export type ScreenComposeEditAttachmentProp = StackScreenProps<
|
||||||
route: {
|
Nav.ScreenComposeStackParamList,
|
||||||
params: {
|
'Screen-Compose-EditAttachment'
|
||||||
index: number
|
>
|
||||||
}
|
|
||||||
}
|
|
||||||
navigation: any
|
|
||||||
}
|
|
||||||
|
|
||||||
const ComposeEditAttachment: React.FC<Props> = ({
|
const ComposeEditAttachment: React.FC<ScreenComposeEditAttachmentProp> = ({
|
||||||
route: {
|
route: {
|
||||||
params: { index }
|
params: { index }
|
||||||
},
|
},
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import { HeaderRight } from '@components/Header'
|
import { HeaderRight } from '@components/Header'
|
||||||
|
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||||
import { StackScreenProps } from '@react-navigation/stack'
|
import { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
import CameraRoll from '@react-native-community/cameraroll'
|
||||||
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 { findIndex } from 'lodash'
|
import { findIndex } from 'lodash'
|
||||||
import React, { useCallback, useLayoutEffect, useState } from 'react'
|
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 FastImage from 'react-native-fast-image'
|
||||||
import ImageViewer from 'react-native-image-zoom-viewer'
|
import ImageViewer from 'react-native-image-zoom-viewer'
|
||||||
import { SharedElement } from 'react-navigation-shared-element'
|
import { SharedElement } from 'react-navigation-shared-element'
|
||||||
|
import { toast } from '@components/toast'
|
||||||
|
|
||||||
export type ScreenImagesViewerProp = StackScreenProps<
|
export type ScreenImagesViewerProp = StackScreenProps<
|
||||||
Nav.RootStackParamList,
|
Nav.RootStackParamList,
|
||||||
@ -27,14 +37,70 @@ const ScreenImagesViewer = React.memo(
|
|||||||
findIndex(imageUrls, ['imageIndex', imageIndex])
|
findIndex(imageUrls, ['imageIndex', imageIndex])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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(() => {
|
const onPress = useCallback(() => {
|
||||||
analytics('imageviewer_share_press')
|
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) {
|
switch (Platform.OS) {
|
||||||
case 'ios':
|
case 'ios':
|
||||||
return Share.share({ url: imageUrls[currentIndex].url })
|
return Share.share({ url: imageUrls[currentIndex].url })
|
||||||
case 'android':
|
case 'android':
|
||||||
return Share.share({ message: imageUrls[currentIndex].url })
|
return Share.share({ message: imageUrls[currentIndex].url })
|
||||||
}
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}, [currentIndex])
|
}, [currentIndex])
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
@ -48,7 +114,11 @@ const ScreenImagesViewer = React.memo(
|
|||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight content='Share' native={false} onPress={onPress} />
|
<HeaderRight
|
||||||
|
content='MoreHorizontal'
|
||||||
|
native={false}
|
||||||
|
onPress={onPress}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
[currentIndex]
|
[currentIndex]
|
||||||
@ -77,6 +147,7 @@ const ScreenImagesViewer = React.memo(
|
|||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
onChange={index => index !== undefined && setCurrentIndex(index)}
|
onChange={index => index !== undefined && setCurrentIndex(index)}
|
||||||
renderImage={renderImage}
|
renderImage={renderImage}
|
||||||
|
onLongPress={saveImage}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -26,7 +26,7 @@ import TabPublic from './Tabs/Public'
|
|||||||
export type ScreenTabsParamList = {
|
export type ScreenTabsParamList = {
|
||||||
'Tab-Local': NavigatorScreenParams<Nav.TabLocalStackParamList>
|
'Tab-Local': NavigatorScreenParams<Nav.TabLocalStackParamList>
|
||||||
'Tab-Public': NavigatorScreenParams<Nav.TabPublicStackParamList>
|
'Tab-Public': NavigatorScreenParams<Nav.TabPublicStackParamList>
|
||||||
'Tab-Compose': NavigatorScreenParams<Nav.TabComposeStackParamList>
|
'Tab-Compose': NavigatorScreenParams<Nav.ScreenComposeStackParamList>
|
||||||
'Tab-Notifications': NavigatorScreenParams<Nav.TabNotificationsStackParamList>
|
'Tab-Notifications': NavigatorScreenParams<Nav.TabNotificationsStackParamList>
|
||||||
'Tab-Me': NavigatorScreenParams<Nav.TabMeStackParamList>
|
'Tab-Me': NavigatorScreenParams<Nav.TabMeStackParamList>
|
||||||
}
|
}
|
||||||
|
@ -8,17 +8,25 @@ const Collections: React.FC = () => {
|
|||||||
const { t, i18n } = useTranslation('meRoot')
|
const { t, i18n } = useTranslation('meRoot')
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
|
|
||||||
const { data, isFetching } = useAnnouncementQuery({ showAll: true })
|
const { data, isFetching } = useAnnouncementQuery({
|
||||||
|
showAll: true
|
||||||
|
})
|
||||||
|
|
||||||
const announcementContent = useMemo(() => {
|
const announcementContent = useMemo(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
if (data.length === 0) {
|
||||||
|
return t('content.collections.announcements.content.empty')
|
||||||
|
} else {
|
||||||
const amount = data.filter(announcement => !announcement.read).length
|
const amount = data.filter(announcement => !announcement.read).length
|
||||||
if (amount) {
|
if (amount) {
|
||||||
return t('content.collections.announcements.content.unread', { amount })
|
return t('content.collections.announcements.content.unread', {
|
||||||
|
amount
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
return t('content.collections.announcements.content.read')
|
return t('content.collections.announcements.content.read')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, [data, i18n.language])
|
}, [data, i18n.language])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -49,7 +57,7 @@ const Collections: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
iconFront='Clipboard'
|
iconFront='Clipboard'
|
||||||
iconBack='ChevronRight'
|
iconBack={data && data.length === 0 ? undefined : 'ChevronRight'}
|
||||||
title={t('content.collections.announcements.heading')}
|
title={t('content.collections.announcements.heading')}
|
||||||
content={announcementContent}
|
content={announcementContent}
|
||||||
loading={isFetching}
|
loading={isFetching}
|
||||||
|
@ -13,7 +13,10 @@ const ScreenMeSettings: React.FC = () => {
|
|||||||
<SettingsTooot />
|
<SettingsTooot />
|
||||||
<SettingsAnalytics />
|
<SettingsAnalytics />
|
||||||
|
|
||||||
{__DEV__ || Constants.manifest.releaseChannel?.includes('testing') ? (
|
{__DEV__ ||
|
||||||
|
['development'].some(channel =>
|
||||||
|
Constants.manifest.releaseChannel?.includes(channel)
|
||||||
|
) ? (
|
||||||
<SettingsDev />
|
<SettingsDev />
|
||||||
) : null}
|
) : null}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -25,7 +25,7 @@ const SettingsApp: React.FC = () => {
|
|||||||
const settingsLanguage = useSelector(getSettingsLanguage)
|
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||||
const settingsTheme = useSelector(getSettingsTheme)
|
const settingsTheme = useSelector(getSettingsTheme)
|
||||||
const settingsBrowser = useSelector(getSettingsBrowser)
|
const settingsBrowser = useSelector(getSettingsBrowser)
|
||||||
|
console.log(settingsLanguage)
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
<MenuRow
|
<MenuRow
|
||||||
@ -37,7 +37,9 @@ const SettingsApp: React.FC = () => {
|
|||||||
i18n.services.resourceStore.data
|
i18n.services.resourceStore.data
|
||||||
)
|
)
|
||||||
const options = availableLanguages
|
const options = availableLanguages
|
||||||
.map(language => t(`content.language.options.${language}`))
|
.map(language => {
|
||||||
|
return t(`content.language.options.${language}`)
|
||||||
|
})
|
||||||
.concat(t('content.language.options.cancel'))
|
.concat(t('content.language.options.cancel'))
|
||||||
|
|
||||||
showActionSheetWithOptions(
|
showActionSheetWithOptions(
|
||||||
@ -47,7 +49,7 @@ const SettingsApp: React.FC = () => {
|
|||||||
cancelButtonIndex: options.length - 1
|
cancelButtonIndex: options.length - 1
|
||||||
},
|
},
|
||||||
buttonIndex => {
|
buttonIndex => {
|
||||||
if (buttonIndex < options.length) {
|
if (buttonIndex < options.length - 1) {
|
||||||
analytics('settings_language_press', {
|
analytics('settings_language_press', {
|
||||||
current: i18n.language,
|
current: i18n.language,
|
||||||
new: availableLanguages[buttonIndex]
|
new: availableLanguages[buttonIndex]
|
||||||
|
@ -6,6 +6,7 @@ import { useSearchQuery } from '@utils/queryHooks/search'
|
|||||||
import { getLocalActiveIndex } from '@utils/slices/instancesSlice'
|
import { getLocalActiveIndex } 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 Constants from 'expo-constants'
|
||||||
import * as Linking from 'expo-linking'
|
import * as Linking from 'expo-linking'
|
||||||
import * as StoreReview from 'expo-store-review'
|
import * as StoreReview from 'expo-store-review'
|
||||||
import * as WebBrowser from 'expo-web-browser'
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
@ -41,19 +42,30 @@ const SettingsTooot: React.FC = () => {
|
|||||||
Linking.openURL('https://www.patreon.com/xmflsct')
|
Linking.openURL('https://www.patreon.com/xmflsct')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{__DEV__ ||
|
||||||
|
['production', 'development'].some(channel =>
|
||||||
|
Constants.manifest.releaseChannel?.includes(channel)
|
||||||
|
) ? (
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('content.review.heading')}
|
title={t('content.review.heading')}
|
||||||
content={
|
content={
|
||||||
<Icon name='Star' size={StyleConstants.Font.Size.M} color='#FF9500' />
|
<Icon
|
||||||
|
name='Star'
|
||||||
|
size={StyleConstants.Font.Size.M}
|
||||||
|
color='#FF9500'
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
iconBack='ChevronRight'
|
iconBack='ChevronRight'
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
analytics('settings_review_press')
|
analytics('settings_review_press')
|
||||||
StoreReview.isAvailableAsync().then(() => StoreReview.requestReview())
|
StoreReview.isAvailableAsync().then(() =>
|
||||||
|
StoreReview.requestReview()
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
) : null}
|
||||||
<MenuRow
|
<MenuRow
|
||||||
title={'联系 tooot'}
|
title={t('content.contact.heading')}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
content={
|
content={
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
|
import haptics from '@components/haptics'
|
||||||
import ComponentInstance from '@components/Instance'
|
import ComponentInstance from '@components/Instance'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import {
|
import {
|
||||||
@ -48,6 +49,7 @@ const AccountButton: React.FC<Props> = ({
|
|||||||
disabled ? ' ✓' : ''
|
disabled ? ' ✓' : ''
|
||||||
}`}
|
}`}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
|
haptics('Light')
|
||||||
analytics('switch_existing_press')
|
analytics('switch_existing_press')
|
||||||
dispatch(localUpdateActiveIndex(index))
|
dispatch(localUpdateActiveIndex(index))
|
||||||
queryClient.clear()
|
queryClient.clear()
|
||||||
@ -77,7 +79,14 @@ const ScreenMeSwitchRoot: React.FC = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
<View style={styles.accountButtons}>
|
<View style={styles.accountButtons}>
|
||||||
{localInstances.length
|
{localInstances.length
|
||||||
? localInstances.map((instance, index) => (
|
? localInstances
|
||||||
|
.slice()
|
||||||
|
.sort((a, b) =>
|
||||||
|
`${a.uri}${a.account.acct}`.localeCompare(
|
||||||
|
`${b.uri}${b.account.acct}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map((instance, index) => (
|
||||||
<AccountButton
|
<AccountButton
|
||||||
key={index}
|
key={index}
|
||||||
index={index}
|
index={index}
|
||||||
|
@ -1,21 +1,11 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import { HeaderRight } from '@components/Header'
|
import { HeaderRight } from '@components/Header'
|
||||||
import Timeline from '@components/Timelines/Timeline'
|
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 { useAccountQuery } from '@utils/queryHooks/account'
|
||||||
import { getLocalAccount } from '@utils/slices/instancesSlice'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, {
|
import React, { useCallback, useEffect, useMemo, useReducer } from 'react'
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useReducer,
|
|
||||||
useState
|
|
||||||
} from 'react'
|
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
import { useSharedValue } from 'react-native-reanimated'
|
import { useSharedValue } from 'react-native-reanimated'
|
||||||
import { useSelector } from 'react-redux'
|
|
||||||
import AccountAttachments from './Account/Attachments'
|
import AccountAttachments from './Account/Attachments'
|
||||||
import AccountHeader from './Account/Header'
|
import AccountHeader from './Account/Header'
|
||||||
import AccountInformation from './Account/Information'
|
import AccountInformation from './Account/Information'
|
||||||
@ -33,7 +23,6 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const localAccount = useSelector(getLocalAccount)
|
|
||||||
const { data } = useAccountQuery({ id: account.id })
|
const { data } = useAccountQuery({ id: account.id })
|
||||||
|
|
||||||
const scrollY = useSharedValue(0)
|
const scrollY = useSharedValue(0)
|
||||||
@ -42,7 +31,6 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||||||
accountInitialState
|
accountInitialState
|
||||||
)
|
)
|
||||||
|
|
||||||
const [modalVisible, setBottomSheetVisible] = useState(false)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateHeaderRight = () =>
|
const updateHeaderRight = () =>
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
@ -53,7 +41,10 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||||||
analytics('bottomsheet_open_press', {
|
analytics('bottomsheet_open_press', {
|
||||||
page: 'account'
|
page: 'account'
|
||||||
})
|
})
|
||||||
setBottomSheetVisible(true)
|
navigation.navigate('Screen-Actions', {
|
||||||
|
type: 'account',
|
||||||
|
account
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@ -89,25 +80,6 @@ const TabSharedAccount: React.FC<SharedAccountProp> = ({
|
|||||||
ListHeaderComponent
|
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>
|
</AccountContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import { useNavigation } from '@react-navigation/native'
|
|||||||
import { StackNavigationProp } from '@react-navigation/stack'
|
import { StackNavigationProp } from '@react-navigation/stack'
|
||||||
import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
import { useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback, useEffect } from 'react'
|
import React, { useCallback, useEffect } from 'react'
|
||||||
import {
|
import {
|
||||||
@ -29,6 +28,8 @@ const AccountAttachments = React.memo(
|
|||||||
>()
|
>()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
const DISPLAY_AMOUNT = 6
|
||||||
|
|
||||||
const width =
|
const width =
|
||||||
(Dimensions.get('screen').width -
|
(Dimensions.get('screen').width -
|
||||||
StyleConstants.Spacing.Global.PagePadding * 2) /
|
StyleConstants.Spacing.Global.PagePadding * 2) /
|
||||||
@ -38,7 +39,7 @@ const AccountAttachments = React.memo(
|
|||||||
page: 'Account_Attachments' as 'Account_Attachments',
|
page: 'Account_Attachments' as 'Account_Attachments',
|
||||||
account: account?.id
|
account: account?.id
|
||||||
}
|
}
|
||||||
const { data, refetch } = useTimelineQuery({
|
const { data, refetch } = useTimelineQuery<Mastodon.Status[]>({
|
||||||
...queryKeyParams,
|
...queryKeyParams,
|
||||||
options: { enabled: false }
|
options: { enabled: false }
|
||||||
})
|
})
|
||||||
@ -48,18 +49,16 @@ const AccountAttachments = React.memo(
|
|||||||
}
|
}
|
||||||
}, [account])
|
}, [account])
|
||||||
|
|
||||||
const flattenData = (data?.pages
|
const flattenData = data?.pages
|
||||||
? data.pages.flatMap(d => [...d])
|
? data.pages
|
||||||
: []) as Mastodon.Status[]
|
.flatMap(d => [...d])
|
||||||
useEffect(() => {
|
.filter(status => !status.sensitive)
|
||||||
if (flattenData.length) {
|
.splice(0, DISPLAY_AMOUNT)
|
||||||
layoutAnimation()
|
: []
|
||||||
}
|
|
||||||
}, [flattenData.length])
|
|
||||||
|
|
||||||
const renderItem = useCallback<ListRenderItem<Mastodon.Status>>(
|
const renderItem = useCallback<ListRenderItem<Mastodon.Status>>(
|
||||||
({ item, index }) => {
|
({ item, index }) => {
|
||||||
if (index === 3) {
|
if (index === DISPLAY_AMOUNT - 1) {
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
@ -128,7 +127,7 @@ const AccountAttachments = React.memo(
|
|||||||
<Animated.View style={[styles.base, styleContainer]}>
|
<Animated.View style={[styles.base, styleContainer]}>
|
||||||
<FlatList
|
<FlatList
|
||||||
horizontal
|
horizontal
|
||||||
data={flattenData.filter(status => !status.sensitive).splice(0, 4)}
|
data={flattenData}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
/>
|
/>
|
||||||
|
@ -66,7 +66,7 @@ const AccountInformationName: React.FC<Props> = ({ account }) => {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
base: {
|
base: {
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
marginTop: StyleConstants.Spacing.M,
|
marginTop: StyleConstants.Spacing.S,
|
||||||
marginBottom: StyleConstants.Spacing.XS
|
marginBottom: StyleConstants.Spacing.XS
|
||||||
},
|
},
|
||||||
moved: {
|
moved: {
|
||||||
|
@ -8,7 +8,11 @@ const sentry = () => {
|
|||||||
environment: Constants.manifest.extra.sentryEnv,
|
environment: Constants.manifest.extra.sentryEnv,
|
||||||
dsn: Constants.manifest.extra.sentryDSN,
|
dsn: Constants.manifest.extra.sentryDSN,
|
||||||
enableInExpoDevelopment: false,
|
enableInExpoDevelopment: false,
|
||||||
debug: __DEV__
|
debug:
|
||||||
|
__DEV__ ||
|
||||||
|
['development'].some(channel =>
|
||||||
|
Constants.manifest.releaseChannel?.includes(channel)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import { persistReducer, persistStore } from 'redux-persist'
|
|||||||
|
|
||||||
const secureStorage = createSecureStore()
|
const secureStorage = createSecureStore()
|
||||||
|
|
||||||
const prefix = 'ajieorjaiojwoirjwe'
|
const prefix = 'tooot'
|
||||||
|
|
||||||
const contextsPersistConfig = {
|
const contextsPersistConfig = {
|
||||||
key: 'contexts',
|
key: 'contexts',
|
||||||
|
@ -2,16 +2,30 @@ import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
|
|||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
import * as Analytics from 'expo-firebase-analytics'
|
import * as Analytics from 'expo-firebase-analytics'
|
||||||
import * as Localization from 'expo-localization'
|
import * as Localization from 'expo-localization'
|
||||||
|
import { pickBy } from 'lodash'
|
||||||
|
|
||||||
|
enum availableLanguages {
|
||||||
|
'zh-Hans',
|
||||||
|
'en'
|
||||||
|
}
|
||||||
|
|
||||||
export type SettingsState = {
|
export type SettingsState = {
|
||||||
language: 'zh-Hans' | 'en'
|
language: keyof availableLanguages
|
||||||
theme: 'light' | 'dark' | 'auto'
|
theme: 'light' | 'dark' | 'auto'
|
||||||
browser: 'internal' | 'external'
|
browser: 'internal' | 'external'
|
||||||
analytics: boolean
|
analytics: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settingsInitialState = {
|
export const settingsInitialState = {
|
||||||
language: Localization.locale,
|
language: Object.keys(
|
||||||
|
pickBy(availableLanguages, (_, key) => Localization.locale.includes(key))
|
||||||
|
)
|
||||||
|
? Object.keys(
|
||||||
|
pickBy(availableLanguages, (_, key) =>
|
||||||
|
Localization.locale.includes(key)
|
||||||
|
)
|
||||||
|
)[0]
|
||||||
|
: 'en',
|
||||||
theme: 'auto',
|
theme: 'auto',
|
||||||
browser: 'internal',
|
browser: 'internal',
|
||||||
analytics: true
|
analytics: true
|
||||||
|
@ -21,5 +21,5 @@ export const StyleConstants = {
|
|||||||
Global: { PagePadding: Base * 4 }
|
Global: { PagePadding: Base * 4 }
|
||||||
},
|
},
|
||||||
|
|
||||||
Avatar: { S: 40, M: 52, L: 104 }
|
Avatar: { S: 40, M: 52, L: 96 }
|
||||||
}
|
}
|
||||||
|
@ -1934,6 +1934,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
prop-types "^15.5.10"
|
prop-types "^15.5.10"
|
||||||
|
|
||||||
|
"@react-native-community/cameraroll@^4.0.2":
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@react-native-community/cameraroll/-/cameraroll-4.0.2.tgz#5baac97f4a56f50b7307b08efcc1fe37acdec462"
|
||||||
|
integrity sha512-GtSZO6pqUzyZvaYidB5zH90o6Yb9YatapgiMQ+JVdbK4bDD74GdrNGDwyinDTzE5LkAQ90HDoAhVgV/uWt5OrQ==
|
||||||
|
|
||||||
"@react-native-community/cli-debugger-ui@^4.13.1":
|
"@react-native-community/cli-debugger-ui@^4.13.1":
|
||||||
version "4.13.1"
|
version "4.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-4.13.1.tgz#07de6d4dab80ec49231de1f1fbf658b4ad39b32c"
|
resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-4.13.1.tgz#07de6d4dab80ec49231de1f1fbf658b4ad39b32c"
|
||||||
|
Loading…
Reference in New Issue
Block a user