Test release

Added screenshot package
This commit is contained in:
Zhiyuan Zheng 2021-02-05 01:13:57 +01:00
parent d7d41a44c3
commit 29f2bf7457
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
26 changed files with 179 additions and 109 deletions

View File

@ -41,5 +41,10 @@ jobs:
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }} APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }} APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }} APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
ANDROID_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE }}
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEYSTORE_ALIAS: ${{ secrets.ANDROID_KEYSTORE_ALIAS }}
ANDROID_KEYSTORE_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_KEY_PASSWORD }}
SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }}
FL_GITHUB_RELEASE_API_BEARER: ${{ secrets.GITHUB_TOKEN }} FL_GITHUB_RELEASE_API_BEARER: ${{ secrets.GITHUB_TOKEN }}
run: yarn app:build run: yarn app:build

View File

@ -8,16 +8,16 @@ GEM
atomos (0.1.3) atomos (0.1.3)
aws-eventstream (1.1.0) aws-eventstream (1.1.0)
aws-partitions (1.422.0) aws-partitions (1.422.0)
aws-sdk-core (3.111.2) aws-sdk-core (3.112.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0) aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
jmespath (~> 1.0) jmespath (~> 1.0)
aws-sdk-kms (1.41.0) aws-sdk-kms (1.42.0)
aws-sdk-core (~> 3, >= 3.109.0) aws-sdk-core (~> 3, >= 3.112.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.87.0) aws-sdk-s3 (1.88.0)
aws-sdk-core (~> 3, >= 3.109.0) aws-sdk-core (~> 3, >= 3.112.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.2) aws-sigv4 (1.2.2)
@ -36,7 +36,7 @@ GEM
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6) dotenv (2.7.6)
emoji_regex (3.2.1) emoji_regex (3.2.1)
excon (0.78.1) excon (0.79.0)
faraday (1.3.0) faraday (1.3.0)
faraday-net_http (~> 1.0) faraday-net_http (~> 1.0)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
@ -47,8 +47,8 @@ GEM
faraday-net_http (1.0.1) faraday-net_http (1.0.1)
faraday_middleware (1.0.0) faraday_middleware (1.0.0)
faraday (~> 1.0) faraday (~> 1.0)
fastimage (2.2.1) fastimage (2.2.2)
fastlane (2.172.0) fastlane (2.173.0)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0) addressable (>= 2.3, < 3.0.0)
artifactory (~> 3.0) artifactory (~> 3.0)
@ -86,6 +86,7 @@ GEM
xcpretty (~> 0.3.0) xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3) xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-json (1.0.0) fastlane-plugin-json (1.0.0)
fastlane-plugin-versioning_android (0.1.0)
fastlane-plugin-yarn (1.2) fastlane-plugin-yarn (1.2)
gh_inspector (1.1.3) gh_inspector (1.1.3)
google-api-client (0.38.0) google-api-client (0.38.0)
@ -199,6 +200,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
fastlane fastlane
fastlane-plugin-json fastlane-plugin-json
fastlane-plugin-versioning_android
fastlane-plugin-yarn fastlane-plugin-yarn
BUNDLED WITH BUNDLED WITH

View File

@ -135,8 +135,12 @@ android {
applicationId 'com.xmflsct.app.tooot' applicationId 'com.xmflsct.app.tooot'
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 4 versionCode 50
versionName "0.1.0" versionName "0.2"
manifestPlaceholders = [
expoSDK: project.hasProperty('expoSDK') ? project.property('expoSDK') : "",
releaseChannel: project.hasProperty('releaseChannel') ? project.property('releaseChannel') : "default"
]
} }
splits { splits {
abi { abi {
@ -161,7 +165,7 @@ android {
release { release {
// Caution! In production, you need to generate your own keystore file. // Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android. // see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug // signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
} }

View File

@ -1,26 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xmflsct.app.tooot"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.xmflsct.app.tooot">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<application <application
android:name=".MainApplication" android:name=".MainApplication"
android:label="@string/app_name" android:label="@string/app_name"
@ -28,9 +15,11 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="true" android:allowBackup="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:requestLegacyExternalStorage="true"
> >
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@xmflsct/tooot"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@xmflsct/tooot"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="40.0.0"/> <meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="${expoSDK}"/>
<meta-data android:name="expo.modules.updates.EXPO_RELEASE_CHANNEL" android:value="${releaseChannel}"/>
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/> <meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
@ -57,6 +46,4 @@
</activity> </activity>
<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"/>
<application android:requestLegacyExternalStorage="true"/>
</manifest> </manifest>

View File

@ -1 +1,2 @@
app_identifier "com.xmflsct.app.tooot" app_identifier "com.xmflsct.app.tooot"
package_name "com.xmflsct.app.tooot"

View File

@ -1,4 +1,4 @@
fastlane_version "2.172.0" fastlane_version "2.173.0"
skip_docs skip_docs
ensure_env_vars( ensure_env_vars(
@ -15,7 +15,7 @@ case ENVIRONMENT
when "development" when "development"
GITHUB_RELEASE= "" GITHUB_RELEASE= ""
when "staging" when "staging"
GITHUB_RELEASE = "v#{VERSION} (#{BUILD_NUMBER})" GITHUB_RELEASE = "v#{VERSION}(#{BUILD_NUMBER})"
when "production" when "production"
GITHUB_RELEASE = "v#{VERSION}" GITHUB_RELEASE = "v#{VERSION}"
end end
@ -26,20 +26,23 @@ EXPO_PLIST = "./ios/tooot/Supporting/Expo.plist"
desc "IOS: Prepare app store" desc "IOS: Prepare app store"
private_lane :prepare_appstore_ios do private_lane :prepare_appstore_ios do
case ENVIRONMENT set_info_plist_value( path: INFO_PLIST, key: "CFBundleShortVersionString", value: VERSION )
when "staging", "production" increment_build_number( xcodeproj: XCODEPROJ, build_number: BUILD_NUMBER )
increment_build_number( xcodeproj: XCODEPROJ, build_number: BUILD_NUMBER ) app_store_connect_api_key
app_store_connect_api_key
end
end end
desc 'IOS: Update version information' desc 'IOS: Update expo information'
private_lane :update_versions_ios do private_lane :update_expo_ios do
set_info_plist_value( path: INFO_PLIST, key: "CFBundleShortVersionString", value: VERSION )
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesSDKVersion", value: VERSIONS[:expo] ) set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesSDKVersion", value: VERSIONS[:expo] )
set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesReleaseChannel", value: RELEASE_CHANNEL ) set_info_plist_value( path: EXPO_PLIST, key: "EXUpdatesReleaseChannel", value: RELEASE_CHANNEL )
end end
desc "ANDROID: Prepare play store"
private_lane :prepare_playstore_android do
android_set_version_name( version_name: VERSION, gradle_file: "./android/app/build.gradle" )
android_set_version_code( version_code: BUILD_NUMBER, gradle_file: "./android/app/build.gradle" )
end
desc "Create new GitHub release" desc "Create new GitHub release"
private_lane :github_release do private_lane :github_release do
case ENVIRONMENT case ENVIRONMENT
@ -67,8 +70,7 @@ desc "Build and deploy iOS app"
private_lane :build_ios do private_lane :build_ios do
BUILD_DIRECTORY = "./ios/build" BUILD_DIRECTORY = "./ios/build"
update_versions_ios update_expo_ios
prepare_appstore_ios
setup_ci setup_ci
case ENVIRONMENT case ENVIRONMENT
@ -77,6 +79,7 @@ private_lane :build_ios do
build_ios_app( export_method: "development", output_directory: BUILD_DIRECTORY, output_name: "#{VERSION}-#{BUILD_NUMBER}" ) build_ios_app( export_method: "development", output_directory: BUILD_DIRECTORY, output_name: "#{VERSION}-#{BUILD_NUMBER}" )
install_on_device( skip_wifi: true ) install_on_device( skip_wifi: true )
when "staging" when "staging"
prepare_appstore_ios
match( type: "appstore", readonly: true ) match( type: "appstore", readonly: true )
build_ios_app( export_method: "app-store" ) build_ios_app( export_method: "app-store" )
upload_to_testflight( upload_to_testflight(
@ -86,6 +89,7 @@ private_lane :build_ios do
changelog: "Ready for testing" changelog: "Ready for testing"
) )
when "production" when "production"
prepare_appstore_ios
match( type: "appstore", readonly: true ) match( type: "appstore", readonly: true )
build_ios_app( export_method: "app-store" ) build_ios_app( export_method: "app-store" )
end end
@ -93,32 +97,43 @@ end
desc "Build and deploy Android app" desc "Build and deploy Android app"
private_lane :build_android do private_lane :build_android do
sh("echo #{ENV["ANDROID_KEYSTORE"]} | base64 -d | tee #{File.expand_path('..', Dir.pwd)}/android/tooot.jks >/dev/null", log: false)
case ENVIRONMENT case ENVIRONMENT
when "development" when "development"
build_android_app( build_android_app(
task: 'assemble', task: 'assemble',
build_type: 'Debug', build_type: 'debug',
project_dir: "./android"
)
adb(
command: "install #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]}"
)
when "staging"
prepare_playstore_android
build_android_app(
task: 'clean bundle',
build_type: 'release',
project_dir: "./android", project_dir: "./android",
print_command: false,
print_command_output: false,
properties: { properties: {
"android.injected.signing.store.file" => "keystore.jks", "expoSDK" => VERSIONS[:expo],
"android.injected.signing.store.password" => "store_password", "releaseChannel" => RELEASE_CHANNEL,
"android.injected.signing.key.alias" => "key_alias", "android.injected.signing.store.file" => "#{File.expand_path('..', Dir.pwd)}/android/tooot.jks",
"android.injected.signing.key.password" => "key_password", "android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
"android.injected.signing.key.alias" => ENV["ANDROID_KEYSTORE_ALIAS"],
"android.injected.signing.key.password" => ENV["ANDROID_KEYSTORE_KEY_PASSWORD"],
} }
) )
puts lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH] upload_to_play_store(
when "staging" track: "alpha",
match( type: "appstore", readonly: true ) skip_upload_metadata: true,
build_ios_app( export_method: "app-store" ) skip_upload_changelogs: true,
upload_to_testflight( skip_upload_images: true,
demo_account_required: true, skip_upload_screenshots: true
distribute_external: true,
groups: "内测用户",
changelog: "Ready for testing"
) )
when "production" when "production"
match( type: "appstore", readonly: true )
build_ios_app( export_method: "app-store" )
end end
end end
@ -129,7 +144,7 @@ lane :build do
else else
puts("Release #{GITHUB_RELEASE} does not exist. Create new release as well as new native build.") puts("Release #{GITHUB_RELEASE} does not exist. Create new release as well as new native build.")
build_ios build_ios
# build_android build_android
case ENVIRONMENT case ENVIRONMENT
when "staging" when "staging"
github_release github_release
@ -137,6 +152,6 @@ lane :build do
github_release github_release
end end
end end
# expo_release expo_release
rocket rocket
end end

View File

@ -4,3 +4,4 @@
gem 'fastlane-plugin-yarn' gem 'fastlane-plugin-yarn'
gem 'fastlane-plugin-json' gem 'fastlane-plugin-json'
gem 'fastlane-plugin-versioning_android'

View File

@ -54,6 +54,8 @@ PODS:
- UMPermissionsInterface - UMPermissionsInterface
- EXRandom (10.0.0): - EXRandom (10.0.0):
- React-Core - React-Core
- EXScreenCapture (3.0.0):
- UMCore
- EXSecureStore (9.3.0): - EXSecureStore (9.3.0):
- UMCore - UMCore
- EXSplashScreen (0.8.1): - EXSplashScreen (0.8.1):
@ -465,7 +467,7 @@ PODS:
- UMBarCodeScannerInterface (5.4.0) - UMBarCodeScannerInterface (5.4.0)
- UMCameraInterface (5.4.0) - UMCameraInterface (5.4.0)
- UMConstantsInterface (5.4.0) - UMConstantsInterface (5.4.0)
- UMCore (6.0.0) - UMCore (7.0.0)
- UMFaceDetectorInterface (5.4.0) - UMFaceDetectorInterface (5.4.0)
- UMFileSystemInterface (5.4.0) - UMFileSystemInterface (5.4.0)
- UMFontInterface (5.4.0) - UMFontInterface (5.4.0)
@ -501,6 +503,7 @@ DEPENDENCIES:
- EXLocation (from `../node_modules/expo-location/ios`) - EXLocation (from `../node_modules/expo-location/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`) - EXPermissions (from `../node_modules/expo-permissions/ios`)
- EXRandom (from `../node_modules/expo-random/ios`) - EXRandom (from `../node_modules/expo-random/ios`)
- EXScreenCapture (from `../node_modules/expo-screen-capture/ios`)
- EXSecureStore (from `../node_modules/expo-secure-store/ios`) - EXSecureStore (from `../node_modules/expo-secure-store/ios`)
- EXSplashScreen (from `../node_modules/expo-splash-screen/ios`) - EXSplashScreen (from `../node_modules/expo-splash-screen/ios`)
- EXSQLite (from `../node_modules/expo-sqlite/ios`) - EXSQLite (from `../node_modules/expo-sqlite/ios`)
@ -554,7 +557,7 @@ DEPENDENCIES:
- UMBarCodeScannerInterface (from `../node_modules/unimodules-barcode-scanner-interface/ios`) - UMBarCodeScannerInterface (from `../node_modules/unimodules-barcode-scanner-interface/ios`)
- UMCameraInterface (from `../node_modules/unimodules-camera-interface/ios`) - UMCameraInterface (from `../node_modules/unimodules-camera-interface/ios`)
- UMConstantsInterface (from `../node_modules/unimodules-constants-interface/ios`) - UMConstantsInterface (from `../node_modules/unimodules-constants-interface/ios`)
- "UMCore (from `../node_modules/@unimodules/core/ios`)" - "UMCore (from `../node_modules/expo-screen-capture/node_modules/@unimodules/core/ios`)"
- UMFaceDetectorInterface (from `../node_modules/unimodules-face-detector-interface/ios`) - UMFaceDetectorInterface (from `../node_modules/unimodules-face-detector-interface/ios`)
- UMFileSystemInterface (from `../node_modules/unimodules-file-system-interface/ios`) - UMFileSystemInterface (from `../node_modules/unimodules-file-system-interface/ios`)
- UMFontInterface (from `../node_modules/unimodules-font-interface/ios`) - UMFontInterface (from `../node_modules/unimodules-font-interface/ios`)
@ -626,6 +629,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/expo-permissions/ios" :path: "../node_modules/expo-permissions/ios"
EXRandom: EXRandom:
:path: "../node_modules/expo-random/ios" :path: "../node_modules/expo-random/ios"
EXScreenCapture:
:path: "../node_modules/expo-screen-capture/ios"
EXSecureStore: EXSecureStore:
:path: "../node_modules/expo-secure-store/ios" :path: "../node_modules/expo-secure-store/ios"
EXSplashScreen: EXSplashScreen:
@ -729,7 +734,7 @@ EXTERNAL SOURCES:
UMConstantsInterface: UMConstantsInterface:
:path: "../node_modules/unimodules-constants-interface/ios" :path: "../node_modules/unimodules-constants-interface/ios"
UMCore: UMCore:
:path: "../node_modules/@unimodules/core/ios" :path: "../node_modules/expo-screen-capture/node_modules/@unimodules/core/ios"
UMFaceDetectorInterface: UMFaceDetectorInterface:
:path: "../node_modules/unimodules-face-detector-interface/ios" :path: "../node_modules/unimodules-face-detector-interface/ios"
UMFileSystemInterface: UMFileSystemInterface:
@ -771,6 +776,7 @@ SPEC CHECKSUMS:
EXLocation: d55e2a37f61bcfb4eba9c813b3f4621d896c4c00 EXLocation: d55e2a37f61bcfb4eba9c813b3f4621d896c4c00
EXPermissions: 17d4846ad1880f6891c74ae58ca1acb43e47ed47 EXPermissions: 17d4846ad1880f6891c74ae58ca1acb43e47ed47
EXRandom: d7e0f3dd64810aabd27d59f8ecffee359177e2c3 EXRandom: d7e0f3dd64810aabd27d59f8ecffee359177e2c3
EXScreenCapture: 5b8447139e56e2b922e93ccdc7c773c103fb44fd
EXSecureStore: 1b571851e6068b30b8ec097be848a04603c03bae EXSecureStore: 1b571851e6068b30b8ec097be848a04603c03bae
EXSplashScreen: 8c7c1112ce7611a853486af4737fe2298eda7657 EXSplashScreen: 8c7c1112ce7611a853486af4737fe2298eda7657
EXSQLite: bda6a286dded0637bb312ee781239dcca163ff4b EXSQLite: bda6a286dded0637bb312ee781239dcca163ff4b
@ -838,7 +844,7 @@ SPEC CHECKSUMS:
UMBarCodeScannerInterface: 3f6c1b09ef4b867ce752b8c0b3893bcf9cd85f32 UMBarCodeScannerInterface: 3f6c1b09ef4b867ce752b8c0b3893bcf9cd85f32
UMCameraInterface: d516032121192fee9a6c93bdfff0bb2cc7282796 UMCameraInterface: d516032121192fee9a6c93bdfff0bb2cc7282796
UMConstantsInterface: 6825ea3832d26ed392ca6eff2df84edd69968fd0 UMConstantsInterface: 6825ea3832d26ed392ca6eff2df84edd69968fd0
UMCore: 97ba5041c9c92317ce61739f6d126a692c8ef4a8 UMCore: a882a262c77a535d46b058c150f957eface073f4
UMFaceDetectorInterface: 60b36b07faa539205efce30b20c192e058b31c23 UMFaceDetectorInterface: 60b36b07faa539205efce30b20c192e058b31c23
UMFileSystemInterface: ab01294ce58a3c773aefb4a5b131ce589c199559 UMFileSystemInterface: ab01294ce58a3c773aefb4a5b131ce589c199559
UMFontInterface: 85fe1b845fb7caab45e04d9ce47e1677a5ce90a5 UMFontInterface: 85fe1b845fb7caab45e04d9ce47e1677a5ce90a5

View File

@ -35,6 +35,7 @@
"expo-linking": "~2.0.1", "expo-linking": "~2.0.1",
"expo-localization": "~9.1.0", "expo-localization": "~9.1.0",
"expo-random": "~10.0.0", "expo-random": "~10.0.0",
"expo-screen-capture": "^3.0.0",
"expo-secure-store": "~9.3.0", "expo-secure-store": "~9.3.0",
"expo-splash-screen": "~0.8.1", "expo-splash-screen": "~0.8.1",
"expo-status-bar": "~1.0.3", "expo-status-bar": "~1.0.3",
@ -108,7 +109,7 @@
"versions": { "versions": {
"native": "210201", "native": "210201",
"major": 0, "major": 0,
"minor": 2, "minor": 3,
"patch": 0, "patch": 0,
"expo": "40.0.0" "expo": "40.0.0"
} }

View File

@ -1,5 +1,5 @@
import client from '@api/client' import client from '@api/client'
import { HeaderLeft } from '@components/Header' import { HeaderCenter, HeaderLeft } from '@components/Header'
import { toast, toastConfig } from '@components/toast' import { toast, toastConfig } from '@components/toast'
import { import {
NavigationContainer, NavigationContainer,
@ -17,9 +17,10 @@ import {
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { themes } from '@utils/styles/themes' import { themes } from '@utils/styles/themes'
import * as Analytics from 'expo-firebase-analytics' import * as Analytics from 'expo-firebase-analytics'
import { addScreenshotListener } from 'expo-screen-capture'
import React, { createRef, useCallback, useEffect, useRef } from 'react' import React, { createRef, useCallback, useEffect, useRef } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Platform, StatusBar } from 'react-native' import { Alert, Platform, StatusBar } from 'react-native'
import Toast from 'react-native-toast-message' import Toast from 'react-native-toast-message'
import { createSharedElementStackNavigator } from 'react-navigation-shared-element' import { createSharedElementStackNavigator } from 'react-navigation-shared-element'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
@ -33,6 +34,7 @@ export interface Props {
export const navigationRef = createRef<NavigationContainerRef>() export const navigationRef = createRef<NavigationContainerRef>()
const Index: React.FC<Props> = ({ localCorrupt }) => { const Index: React.FC<Props> = ({ localCorrupt }) => {
const { t } = useTranslation('common')
const dispatch = useDispatch() const dispatch = useDispatch()
const localActiveIndex = useSelector(getLocalActiveIndex) const localActiveIndex = useSelector(getLocalActiveIndex)
const { mode, theme } = useTheme() const { mode, theme } = useTheme()
@ -56,8 +58,18 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
// } // }
// }, [isConnected, firstRender]) // }, [isConnected, firstRender])
// Prevent screenshot alert
useEffect(() => {
const screenshotListener = addScreenshotListener(() =>
Alert.alert(t('screenshot.title'), t('screenshot.message'), [
{ text: t('screenshot.button'), style: 'destructive' }
])
)
Platform.OS === 'ios' && screenshotListener
return () => screenshotListener.remove()
}, [])
// On launch display login credentials corrupt information // On launch display login credentials corrupt information
const { t } = useTranslation('common')
useEffect(() => { useEffect(() => {
const showLocalCorrect = localCorrupt const showLocalCorrect = localCorrupt
? toast({ ? toast({
@ -153,7 +165,12 @@ const Index: React.FC<Props> = ({ localCorrupt }) => {
component={ScreenAnnouncements} component={ScreenAnnouncements}
options={{ options={{
gestureEnabled: false, gestureEnabled: false,
title: t('sharedAnnouncements:heading'), headerTitle: t('sharedAnnouncements:heading'),
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter content={t('sharedAnnouncements:heading')} />
)
}),
headerTransparent: true, headerTransparent: true,
headerLeft: () => ( headerLeft: () => (
<HeaderLeft <HeaderLeft

View File

@ -3,7 +3,6 @@ import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation' import layoutAnimation from '@utils/styles/layoutAnimation'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { useEffect, useMemo, useRef } from 'react' import React, { useEffect, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { import {
Pressable, Pressable,
StyleProp, StyleProp,
@ -49,8 +48,7 @@ const Button: React.FC<Props> = ({
overlay = false, overlay = false,
onPress onPress
}) => { }) => {
const { i18n } = useTranslation() const { mode, theme } = useTheme()
const { theme } = useTheme()
const mounted = useRef(false) const mounted = useRef(false)
useEffect(() => { useEffect(() => {
@ -67,7 +65,7 @@ const Button: React.FC<Props> = ({
<Chase size={StyleConstants.Font.Size[size]} color={theme.secondary} /> <Chase size={StyleConstants.Font.Size[size]} color={theme.secondary} />
</View> </View>
), ),
[theme] [mode]
) )
const colorContent = useMemo(() => { const colorContent = useMemo(() => {
@ -88,7 +86,7 @@ const Button: React.FC<Props> = ({
} }
} }
} }
}, [theme, disabled]) }, [mode, disabled])
const colorBorder = useMemo(() => { const colorBorder = useMemo(() => {
if (active) { if (active) {
return theme.blue return theme.blue
@ -103,14 +101,14 @@ const Button: React.FC<Props> = ({
} }
} }
} }
}, [theme, loading, disabled]) }, [mode, loading, disabled])
const colorBackground = useMemo(() => { const colorBackground = useMemo(() => {
if (overlay) { if (overlay) {
return theme.backgroundOverlay return theme.backgroundOverlay
} else { } else {
return theme.background return theme.background
} }
}, [theme]) }, [mode])
const children = useMemo(() => { const children = useMemo(() => {
switch (type) { switch (type) {
@ -147,7 +145,7 @@ const Button: React.FC<Props> = ({
</> </>
) )
} }
}, [i18n.language, theme, content, loading, disabled, active]) }, [mode, content, loading, disabled, active])
enum spacingMapping { enum spacingMapping {
XS = 'S', XS = 'S',

View File

@ -28,10 +28,7 @@ const ComponentHashtag: React.FC<Props> = ({
}, []) }, [])
return ( return (
<Pressable <Pressable style={styles.itemDefault} onPress={customOnPress || onPress}>
style={[styles.itemDefault, { borderBottomColor: theme.border }]}
onPress={customOnPress || onPress}
>
<Text style={[styles.itemHashtag, { color: theme.primary }]}> <Text style={[styles.itemHashtag, { color: theme.primary }]}>
#{hashtag.name} #{hashtag.name}
</Text> </Text>
@ -41,8 +38,7 @@ const ComponentHashtag: React.FC<Props> = ({
const styles = StyleSheet.create({ const styles = StyleSheet.create({
itemDefault: { itemDefault: {
padding: StyleConstants.Spacing.S * 1.5, padding: StyleConstants.Spacing.S * 1.5
borderBottomWidth: StyleSheet.hairlineWidth
}, },
itemHashtag: { itemHashtag: {
...StyleConstants.FontStyle.M ...StyleConstants.FontStyle.M

View File

@ -33,7 +33,7 @@ const ComponentInstance: React.FC<Props> = ({
disableHeaderImage, disableHeaderImage,
goBack = false goBack = false
}) => { }) => {
const { t } = useTranslation('componentInstance') const { t, i18n } = useTranslation('componentInstance')
const { theme } = useTheme() const { theme } = useTheme()
const navigation = useNavigation() const navigation = useNavigation()
@ -136,7 +136,7 @@ const ComponentInstance: React.FC<Props> = ({
case 'remote': case 'remote':
return t('server.button.remote') return t('server.button.remote')
} }
}, []) }, [i18n.language])
const requestAuth = useMemo(() => { const requestAuth = useMemo(() => {
if ( if (

View File

@ -164,7 +164,13 @@ const Timeline: React.FC<Props> = ({
<RefreshControl <RefreshControl
{...(Platform.OS === 'android' && { enabled: true })} {...(Platform.OS === 'android' && { enabled: true })}
refreshing={ refreshing={
isSwipeDown.current && isFetching && !isFetchingNextPage && !isLoading Platform.OS === 'android'
? (isSwipeDown.current && isFetching && !isFetchingNextPage) ||
isLoading
: isSwipeDown.current &&
isFetching &&
!isFetchingNextPage &&
!isLoading
} }
onRefresh={() => { onRefresh={() => {
isSwipeDown.current = true isSwipeDown.current = true

View File

@ -1,4 +1,9 @@
export default { export default {
screenshot: {
title: 'Privacy Protection',
message: 'Please do not disclose other user\'s identity, such as username, avatar, etc. Thank you!',
button: 'Confirm'
},
index: { index: {
localCorrupt: 'Login expired, please login again' localCorrupt: 'Login expired, please login again'
}, },

View File

@ -1,3 +1,3 @@
export default { export default {
heading: 'Direct messages' heading: 'Discussions'
} }

View File

@ -1,4 +1,9 @@
export default { export default {
screenshot: {
title: '隐私保护',
message: '请确保不要泄露其它用户的敏感信息,例如用户名、头像等,谢谢!',
button: '好的'
},
index: { index: {
localCorrupt: '登录已过期,请重新登录' localCorrupt: '登录已过期,请重新登录'
}, },

View File

@ -231,6 +231,7 @@ const ScreenCompose: React.FC<ScreenComposeProp> = ({
<KeyboardAvoidingView <KeyboardAvoidingView
style={styles.base} style={styles.base}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={Platform.OS === 'android' ? 23 : 0}
> >
<SafeAreaView <SafeAreaView
style={styles.base} style={styles.base}

View File

@ -5,7 +5,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { forEach, groupBy, sortBy } from 'lodash' import { forEach, groupBy, sortBy } from 'lodash'
import React, { useCallback, useContext, useEffect, useMemo } from 'react' import React, { useCallback, useContext, useEffect, useMemo } from 'react'
import { FlatList, Image, StyleSheet, View } from 'react-native' import { FlatList, StyleSheet, View } from 'react-native'
import { Chase } from 'react-native-animated-spinkit' import { Chase } from 'react-native-animated-spinkit'
import ComposeActions from './Root/Actions' import ComposeActions from './Root/Actions'
import ComposePosting from './Posting' import ComposePosting from './Posting'
@ -70,7 +70,7 @@ const ComposeRoot: React.FC = () => {
const listItem = useCallback( const listItem = useCallback(
({ item, index }) => ( ({ item, index }) => (
<ComposeRootSuggestion <ComposeRootSuggestion
key={(item.id || item.name) + index} key={index}
item={item} item={item}
composeState={composeState} composeState={composeState}
composeDispatch={composeDispatch} composeDispatch={composeDispatch}

View File

@ -1,5 +1,5 @@
import analytics from '@components/analytics' import analytics from '@components/analytics'
import { HeaderRight } from '@components/Header' import { HeaderCenter, HeaderRight } from '@components/Header'
import { useActionSheet } from '@expo/react-native-action-sheet' 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 CameraRoll from '@react-native-community/cameraroll'
@ -8,13 +8,7 @@ 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 { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import { PermissionsAndroid, Platform, Share, StyleSheet } from 'react-native'
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'
@ -107,11 +101,9 @@ const ScreenImagesViewer = React.memo(
() => () =>
navigation.setOptions({ navigation.setOptions({
headerTitle: () => ( headerTitle: () => (
<Text <HeaderCenter
style={[styles.headerCenter, { color: theme.primaryOverlay }]} content={`${currentIndex + 1} / ${imageUrls.length}`}
> />
{currentIndex + 1} / {imageUrls.length}
</Text>
), ),
headerRight: () => ( headerRight: () => (
<HeaderRight <HeaderRight

View File

@ -9,8 +9,8 @@ import ScreenMeSwitchRoot from './Switch/Root'
const Stack = createNativeStackNavigator() const Stack = createNativeStackNavigator()
const ScreenMeSwitch: React.FC<StackScreenProps< const ScreenMeSwitch: React.FC<StackScreenProps<
Nav.MeStackParamList, Nav.TabMeStackParamList,
'Screen-Me-Switch' 'Tab-Me-Switch'
>> = ({ navigation }) => { >> = ({ navigation }) => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (

View File

@ -45,8 +45,8 @@ const AccountButton: React.FC<Props> = ({ instance, disabled = false }) => {
onPress={() => { onPress={() => {
haptics('Light') haptics('Light')
analytics('switch_existing_press') analytics('switch_existing_press')
dispatch(localUpdateActiveIndex(instance))
queryClient.clear() queryClient.clear()
dispatch(localUpdateActiveIndex(instance))
navigation.goBack() navigation.goBack()
}} }}
/> />

View File

@ -2,8 +2,6 @@ import Timeline from '@components/Timelines/Timeline'
import React from 'react' import React from 'react'
import { SharedHashtagProp } from './sharedScreens' import { SharedHashtagProp } from './sharedScreens'
// Show remote hashtag? Only when private, show local version?
const TabSharedHashtag: React.FC<SharedHashtagProp> = ({ const TabSharedHashtag: React.FC<SharedHashtagProp> = ({
route: { route: {
params: { hashtag } params: { hashtag }

View File

@ -136,7 +136,14 @@ const sharedScreens = (
name='Tab-Shared-Hashtag' name='Tab-Shared-Hashtag'
component={TabSharedHashtag} component={TabSharedHashtag}
options={({ route, navigation }: SharedHashtagProp) => ({ options={({ route, navigation }: SharedHashtagProp) => ({
title: `#${decodeURIComponent(route.params.hashtag)}`, headerTitle: `#${decodeURIComponent(route.params.hashtag)}`,
...(Platform.OS === 'android' && {
headerCenter: () => (
<HeaderCenter
content={`#${decodeURIComponent(route.params.hashtag)}`}
/>
)
}),
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} /> headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
})} })}
/>, />,

View File

@ -0,0 +1,9 @@
import { preventScreenCaptureAsync } from 'expo-screen-capture'
import log from './log'
const preventScreenshot = () => {
log('log', 'Screenshot', 'preventing')
preventScreenCaptureAsync()
}
export default preventScreenshot

View File

@ -2630,6 +2630,13 @@
dependencies: dependencies:
compare-versions "^3.4.0" compare-versions "^3.4.0"
"@unimodules/core@~7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@unimodules/core/-/core-7.0.0.tgz#0311a9c7c0a661368ceef8891f758eb2e166bdf4"
integrity sha512-hKxNN6ad2VmmJqB3i1C8IJe27TcchY7YAKpkQhshjPxso61f7iM7AUFeG4vcU1vPH5d/X4Vk1ds8bWxaxg7nnw==
dependencies:
compare-versions "^3.4.0"
"@unimodules/react-native-adapter@~5.7.0": "@unimodules/react-native-adapter@~5.7.0":
version "5.7.0" version "5.7.0"
resolved "https://registry.yarnpkg.com/@unimodules/react-native-adapter/-/react-native-adapter-5.7.0.tgz#c5b7c660c5c69e77a7baeaed62be73cfe18dd7b0" resolved "https://registry.yarnpkg.com/@unimodules/react-native-adapter/-/react-native-adapter-5.7.0.tgz#c5b7c660c5c69e77a7baeaed62be73cfe18dd7b0"
@ -4565,6 +4572,13 @@ expo-random@~10.0.0:
dependencies: dependencies:
base64-js "^1.3.0" base64-js "^1.3.0"
expo-screen-capture@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/expo-screen-capture/-/expo-screen-capture-3.0.0.tgz#c35a94acca4274a0ea67c8e09e0b39c19fecc0a6"
integrity sha512-TXLIH/NcuMPNT5dUGKWdwZtBhA+N17A3cFk1cICHlalerGU5uyRYJalaJAY+U+WwAEpOAIehfonv1Qa87W58Nw==
dependencies:
"@unimodules/core" "~7.0.0"
expo-secure-store@~9.3.0: expo-secure-store@~9.3.0:
version "9.3.0" version "9.3.0"
resolved "https://registry.yarnpkg.com/expo-secure-store/-/expo-secure-store-9.3.0.tgz#b716d5d115cc50a34037d1afef84fe4b8ea0745c" resolved "https://registry.yarnpkg.com/expo-secure-store/-/expo-secure-store-9.3.0.tgz#b716d5d115cc50a34037d1afef84fe4b8ea0745c"