Merge branch 'main' into nandr
This commit is contained in:
commit
29d0ae921f
120 changed files with 3771 additions and 3059 deletions
|
|
@ -1,617 +0,0 @@
|
|||
version: 2.1
|
||||
orbs:
|
||||
owasp: entur/owasp@0.0.10
|
||||
node: circleci/node@5.0.3
|
||||
|
||||
executors:
|
||||
android:
|
||||
parameters:
|
||||
resource_class:
|
||||
default: xlarge
|
||||
type: string
|
||||
environment:
|
||||
NODE_OPTIONS: --max_old_space_size=12000
|
||||
NODE_ENV: production
|
||||
BABEL_ENV: production
|
||||
docker:
|
||||
- image: cimg/android:2022.09.2-node
|
||||
working_directory: ~/mattermost-mobile
|
||||
resource_class: <<parameters.resource_class>>
|
||||
|
||||
ios:
|
||||
parameters:
|
||||
resource_class:
|
||||
default: medium
|
||||
type: string
|
||||
environment:
|
||||
NODE_OPTIONS: --max_old_space_size=12000
|
||||
NODE_ENV: production
|
||||
BABEL_ENV: production
|
||||
macos:
|
||||
xcode: "14.2.0"
|
||||
working_directory: ~/mattermost-mobile
|
||||
shell: /bin/bash --login -o pipefail
|
||||
resource_class: <<parameters.resource_class>>
|
||||
|
||||
commands:
|
||||
checkout-private:
|
||||
description: "Checkout the private repo with build env vars"
|
||||
steps:
|
||||
- add_ssh_keys:
|
||||
fingerprints:
|
||||
- "03:1c:a7:07:35:bc:57:e4:1d:6c:e1:2c:4b:be:09:6d"
|
||||
- run:
|
||||
name: Clone the mobile private repo
|
||||
command: git clone git@github.com:mattermost/mattermost-mobile-private.git ~/mattermost-mobile-private
|
||||
|
||||
fastlane-dependencies:
|
||||
description: "Get Fastlane dependencies"
|
||||
parameters:
|
||||
for:
|
||||
type: string
|
||||
steps:
|
||||
- restore_cache:
|
||||
name: Restore Fastlane cache
|
||||
key: v1-gems-<< parameters.for >>-{{ checksum "fastlane/Gemfile.lock" }}-{{ arch }}
|
||||
- run:
|
||||
working_directory: fastlane
|
||||
name: Download Fastlane dependencies
|
||||
command: bundle install --path vendor/bundle
|
||||
- save_cache:
|
||||
name: Save Fastlane cache
|
||||
key: v1-gems-<< parameters.for >>-{{ checksum "fastlane/Gemfile.lock" }}-{{ arch }}
|
||||
paths:
|
||||
- fastlane/vendor/bundle
|
||||
|
||||
gradle-dependencies:
|
||||
description: "Get Gradle dependencies"
|
||||
steps:
|
||||
- restore_cache:
|
||||
name: Restore Gradle cache
|
||||
key: v1-gradle-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
|
||||
- run:
|
||||
working_directory: android
|
||||
name: Download Gradle dependencies
|
||||
command: ./gradlew dependencies
|
||||
- save_cache:
|
||||
name: Save Gradle cache
|
||||
paths:
|
||||
- ~/.gradle
|
||||
key: v1-gradle-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
|
||||
|
||||
assets:
|
||||
description: "Generate app assets"
|
||||
steps:
|
||||
- restore_cache:
|
||||
name: Restore assets cache
|
||||
key: v1-assets-{{ checksum "assets/base/config.json" }}-{{ arch }}
|
||||
- run:
|
||||
name: Generate assets
|
||||
command: node ./scripts/generate-assets.js
|
||||
- run:
|
||||
name: Compass Icons
|
||||
environment:
|
||||
COMPASS_ICONS: "node_modules/@mattermost/compass-icons/font/compass-icons.ttf"
|
||||
command: |
|
||||
cp "$COMPASS_ICONS" "assets/fonts/"
|
||||
cp "$COMPASS_ICONS" "android/app/src/main/assets/fonts"
|
||||
- save_cache:
|
||||
name: Save assets cache
|
||||
key: v1-assets-{{ checksum "assets/base/config.json" }}-{{ arch }}
|
||||
paths:
|
||||
- dist
|
||||
|
||||
npm-dependencies:
|
||||
description: "Get JavaScript dependencies"
|
||||
steps:
|
||||
- node/install:
|
||||
node-version: '18.7.0'
|
||||
- restore_cache:
|
||||
name: Restore npm cache
|
||||
key: v2-npm-{{ checksum "package.json" }}-{{ arch }}
|
||||
- run:
|
||||
name: Getting JavaScript dependencies
|
||||
command: |
|
||||
NODE_ENV=development npm ci --ignore-scripts
|
||||
node node_modules/\@sentry/cli/scripts/install.js
|
||||
- save_cache:
|
||||
name: Save npm cache
|
||||
key: v2-npm-{{ checksum "package.json" }}-{{ arch }}
|
||||
paths:
|
||||
- node_modules
|
||||
- run:
|
||||
name: "Patch dependencies"
|
||||
command: npx patch-package
|
||||
|
||||
pods-dependencies:
|
||||
description: "Get cocoapods dependencies"
|
||||
steps:
|
||||
- restore_cache:
|
||||
name: Restore cocoapods specs and pods
|
||||
key: v1-cocoapods-{{ checksum "ios/Podfile.lock" }}-{{ arch }}
|
||||
- run:
|
||||
name: iOS gems
|
||||
command: npm run ios-gems
|
||||
- run:
|
||||
name: Getting cocoapods dependencies
|
||||
command: npm run pod-install
|
||||
- save_cache:
|
||||
name: Save cocoapods specs and pods cache
|
||||
key: v1-cocoapods-{{ checksum "ios/Podfile.lock" }}-{{ arch }}
|
||||
paths:
|
||||
- ios/Pods
|
||||
- ~/.cocoapods
|
||||
|
||||
build-android:
|
||||
description: "Build the android app"
|
||||
steps:
|
||||
- checkout:
|
||||
path: ~/mattermost-mobile
|
||||
- checkout-private
|
||||
- npm-dependencies
|
||||
- assets
|
||||
- fastlane-dependencies:
|
||||
for: android
|
||||
- gradle-dependencies
|
||||
- run:
|
||||
name: Append Keystore to build Android
|
||||
command: |
|
||||
cp ~/mattermost-mobile-private/android/${STORE_FILE} android/app/${STORE_FILE}
|
||||
echo "" | tee -a android/gradle.properties > /dev/null
|
||||
echo MATTERMOST_RELEASE_STORE_FILE=${STORE_FILE} | tee -a android/gradle.properties > /dev/null
|
||||
echo ${STORE_ALIAS} | tee -a android/gradle.properties > /dev/null
|
||||
echo ${STORE_PASSWORD} | tee -a android/gradle.properties > /dev/null
|
||||
- run:
|
||||
name: Jetify android libraries
|
||||
command: ./node_modules/.bin/jetify
|
||||
- run:
|
||||
working_directory: fastlane
|
||||
name: Run fastlane to build android
|
||||
no_output_timeout: 30m
|
||||
command: export TERM=xterm && bundle exec fastlane android build
|
||||
|
||||
build-ios:
|
||||
description: "Build the iOS app"
|
||||
steps:
|
||||
- checkout:
|
||||
path: ~/mattermost-mobile
|
||||
- npm-dependencies
|
||||
- pods-dependencies
|
||||
- assets
|
||||
- fastlane-dependencies:
|
||||
for: ios
|
||||
- run:
|
||||
working_directory: fastlane
|
||||
name: Run fastlane to build iOS
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman
|
||||
export TERM=xterm && bundle exec fastlane ios build
|
||||
|
||||
deploy-to-store:
|
||||
description: "Deploy build to store"
|
||||
parameters:
|
||||
task:
|
||||
type: string
|
||||
target:
|
||||
type: string
|
||||
file:
|
||||
type: string
|
||||
env:
|
||||
type: string
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: <<parameters.task>>
|
||||
working_directory: fastlane
|
||||
command: <<parameters.env>> bundle exec fastlane <<parameters.target>> deploy file:$HOME/mattermost-mobile/<<parameters.file>>
|
||||
|
||||
persist:
|
||||
description: "Persist mattermost-mobile directory"
|
||||
steps:
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- mattermost-mobile*
|
||||
|
||||
save:
|
||||
description: "Save binaries artifacts"
|
||||
parameters:
|
||||
filename:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Copying artifacts
|
||||
command: |
|
||||
mkdir /tmp/artifacts;
|
||||
cp ~/mattermost-mobile/<<parameters.filename>> /tmp/artifacts;
|
||||
- store_artifacts:
|
||||
path: /tmp/artifacts
|
||||
|
||||
jobs:
|
||||
test:
|
||||
working_directory: ~/mattermost-mobile
|
||||
docker:
|
||||
- image: cimg/node:16.14.2
|
||||
steps:
|
||||
- checkout:
|
||||
path: ~/mattermost-mobile
|
||||
- npm-dependencies
|
||||
- assets
|
||||
- run:
|
||||
name: Check styles
|
||||
command: npm run check
|
||||
- run:
|
||||
name: Running Tests
|
||||
command: npm test
|
||||
- run:
|
||||
name: Check i18n
|
||||
command: ./scripts/precommit/i18n.sh
|
||||
|
||||
check-deps:
|
||||
parameters:
|
||||
cve_data_directory:
|
||||
type: string
|
||||
default: "~/.owasp/dependency-check-data"
|
||||
working_directory: ~/mattermost-mobile
|
||||
executor: owasp/default
|
||||
environment:
|
||||
version_url: "https://jeremylong.github.io/DependencyCheck/current.txt"
|
||||
executable_url: "https://dl.bintray.com/jeremy-long/owasp/dependency-check-VERSION-release.zip"
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore npm cache
|
||||
key: v2-npm-{{ checksum "package.json" }}-{{ arch }}
|
||||
- run:
|
||||
name: Checkout config
|
||||
command: cd .. && git clone https://github.com/mattermost/security-automation-config
|
||||
- run:
|
||||
name: Install Go
|
||||
command: sudo apt-get update && sudo apt-get install golang
|
||||
- owasp/with_commandline:
|
||||
steps:
|
||||
# Taken from https://github.com/entur/owasp-orb/blob/master/src/%40orb.yml#L349-L361
|
||||
- owasp/generate_cache_keys:
|
||||
cache_key: commmandline-default-cache-key-v7
|
||||
- owasp/restore_owasp_cache
|
||||
- run:
|
||||
name: Update OWASP Dependency-Check Database
|
||||
command: |
|
||||
if ! ~/.owasp/dependency-check/bin/dependency-check.sh --data << parameters.cve_data_directory >> --updateonly; then
|
||||
# Update failed, probably due to a bad DB version; delete cached DB and try again
|
||||
rm -rv ~/.owasp/dependency-check-data/*.db
|
||||
~/.owasp/dependency-check/bin/dependency-check.sh --data << parameters.cve_data_directory >> --updateonly
|
||||
fi
|
||||
- owasp/store_owasp_cache:
|
||||
cve_data_directory: <<parameters.cve_data_directory>>
|
||||
- run:
|
||||
name: Run OWASP Dependency-Check Analyzer
|
||||
command: |
|
||||
~/.owasp/dependency-check/bin/dependency-check.sh \
|
||||
--data << parameters.cve_data_directory >> --format ALL --noupdate --enableExperimental \
|
||||
--propertyfile ../security-automation-config/dependency-check/dependencycheck.properties \
|
||||
--suppression ../security-automation-config/dependency-check/suppression.xml \
|
||||
--suppression ../security-automation-config/dependency-check/suppression.$CIRCLE_PROJECT_REPONAME.xml \
|
||||
--scan './**/*' || true
|
||||
- owasp/collect_reports:
|
||||
persist_to_workspace: false
|
||||
- run:
|
||||
name: Post results to Mattermost
|
||||
command: go run ../security-automation-config/dependency-check/post_results.go
|
||||
|
||||
build-android-beta:
|
||||
executor: android
|
||||
steps:
|
||||
- build-android
|
||||
- persist
|
||||
- save:
|
||||
filename: "*.apk"
|
||||
|
||||
build-android-release:
|
||||
executor: android
|
||||
steps:
|
||||
- build-android
|
||||
- persist
|
||||
- save:
|
||||
filename: "*.apk"
|
||||
|
||||
build-android-pr:
|
||||
executor: android
|
||||
environment:
|
||||
BRANCH_TO_BUILD: ${CIRCLE_BRANCH}
|
||||
steps:
|
||||
- build-android
|
||||
- save:
|
||||
filename: "*.apk"
|
||||
|
||||
build-android-unsigned:
|
||||
executor: android
|
||||
steps:
|
||||
- checkout:
|
||||
path: ~/mattermost-mobile
|
||||
- npm-dependencies
|
||||
- assets
|
||||
- fastlane-dependencies:
|
||||
for: android
|
||||
- gradle-dependencies
|
||||
- run:
|
||||
name: Jetify Android libraries
|
||||
command: ./node_modules/.bin/jetify
|
||||
- run:
|
||||
working_directory: fastlane
|
||||
name: Run fastlane to build unsigned android
|
||||
no_output_timeout: 30m
|
||||
command: bundle exec fastlane android unsigned
|
||||
- persist
|
||||
- save:
|
||||
filename: "*.apk"
|
||||
|
||||
build-ios-beta:
|
||||
executor:
|
||||
name: ios
|
||||
resource_class: large
|
||||
steps:
|
||||
- build-ios
|
||||
- persist
|
||||
- save:
|
||||
filename: "*.ipa"
|
||||
|
||||
build-ios-release:
|
||||
executor: ios
|
||||
steps:
|
||||
- build-ios
|
||||
- persist
|
||||
- save:
|
||||
filename: "*.ipa"
|
||||
|
||||
build-ios-pr:
|
||||
executor: ios
|
||||
environment:
|
||||
BRANCH_TO_BUILD: ${CIRCLE_BRANCH}
|
||||
steps:
|
||||
- build-ios
|
||||
- save:
|
||||
filename: "*.ipa"
|
||||
|
||||
build-ios-unsigned:
|
||||
executor: ios
|
||||
steps:
|
||||
- checkout:
|
||||
path: ~/mattermost-mobile
|
||||
- npm-dependencies
|
||||
- pods-dependencies
|
||||
- assets
|
||||
- fastlane-dependencies:
|
||||
for: ios
|
||||
- run:
|
||||
working_directory: fastlane
|
||||
name: Run fastlane to build unsigned iOS
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman
|
||||
bundle exec fastlane ios unsigned
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- mattermost-mobile/*.ipa
|
||||
- save:
|
||||
filename: "*.ipa"
|
||||
|
||||
build-ios-simulator:
|
||||
executor: ios
|
||||
steps:
|
||||
- checkout:
|
||||
path: ~/mattermost-mobile
|
||||
- npm-dependencies
|
||||
- pods-dependencies
|
||||
- assets
|
||||
- fastlane-dependencies:
|
||||
for: ios
|
||||
- run:
|
||||
working_directory: fastlane
|
||||
name: Run fastlane to build unsigned x86_64 iOS app for iPhone simulator
|
||||
no_output_timeout: 30m
|
||||
command: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install watchman
|
||||
bundle exec fastlane ios simulator
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- mattermost-mobile/Mattermost-simulator-x86_64.app.zip
|
||||
- save:
|
||||
filename: "Mattermost-simulator-x86_64.app.zip"
|
||||
|
||||
deploy-android-release:
|
||||
executor:
|
||||
name: android
|
||||
resource_class: medium
|
||||
steps:
|
||||
- deploy-to-store:
|
||||
task: "Deploy to Google Play"
|
||||
target: android
|
||||
file: "*.apk"
|
||||
env: "SUPPLY_TRACK=beta"
|
||||
|
||||
deploy-android-beta:
|
||||
executor:
|
||||
name: android
|
||||
resource_class: medium
|
||||
steps:
|
||||
- deploy-to-store:
|
||||
task: "Deploy to Google Play"
|
||||
target: android
|
||||
file: "*.apk"
|
||||
env: "SUPPLY_TRACK=alpha"
|
||||
|
||||
deploy-ios-release:
|
||||
executor: ios
|
||||
steps:
|
||||
- deploy-to-store:
|
||||
task: "Deploy to TestFlight"
|
||||
target: ios
|
||||
file: "*.ipa"
|
||||
env: ""
|
||||
|
||||
deploy-ios-beta:
|
||||
executor: ios
|
||||
steps:
|
||||
- deploy-to-store:
|
||||
task: "Deploy to TestFlight"
|
||||
target: ios
|
||||
file: "*.ipa"
|
||||
env: ""
|
||||
|
||||
github-release:
|
||||
executor:
|
||||
name: android
|
||||
resource_class: medium
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: Create GitHub release
|
||||
working_directory: fastlane
|
||||
command: bundle exec fastlane github
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build:
|
||||
jobs:
|
||||
- test
|
||||
# - check-deps:
|
||||
# context: sast-webhook
|
||||
# requires:
|
||||
# - test
|
||||
|
||||
- build-android-release:
|
||||
context: mattermost-mobile-android-release
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-release-\d+$/
|
||||
- /^build-android-release-\d+$/
|
||||
- deploy-android-release:
|
||||
context: mattermost-mobile-android-release
|
||||
requires:
|
||||
- build-android-release
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-release-\d+$/
|
||||
- /^build-android-release-\d+$/
|
||||
|
||||
- build-android-beta:
|
||||
context: mattermost-mobile-android-beta
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-\d+$/
|
||||
- /^build-android-\d+$/
|
||||
- /^build-android-beta-\d+$/
|
||||
- deploy-android-beta:
|
||||
context: mattermost-mobile-android-beta
|
||||
requires:
|
||||
- build-android-beta
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-\d+$/
|
||||
- /^build-android-\d+$/
|
||||
- /^build-android-beta-\d+$/
|
||||
|
||||
- build-ios-release:
|
||||
context: mattermost-mobile-ios-release
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-release-\d+$/
|
||||
- /^build-ios-release-\d+$/
|
||||
- deploy-ios-release:
|
||||
context: mattermost-mobile-ios-release
|
||||
requires:
|
||||
- build-ios-release
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-release-\d+$/
|
||||
- /^build-ios-release-\d+$/
|
||||
|
||||
- build-ios-beta:
|
||||
context: mattermost-mobile-ios-beta
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-\d+$/
|
||||
- /^build-ios-\d+$/
|
||||
- /^build-ios-beta-\d+$/
|
||||
- deploy-ios-beta:
|
||||
context: mattermost-mobile-ios-beta
|
||||
requires:
|
||||
- build-ios-beta
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-\d+$/
|
||||
- /^build-ios-\d+$/
|
||||
- /^build-ios-beta-\d+$/
|
||||
|
||||
- build-android-pr:
|
||||
context: mattermost-mobile-android-pr
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
only: /^(build|android)-pr-.*/
|
||||
- build-ios-pr:
|
||||
context: mattermost-mobile-ios-pr
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
only: /^(build|ios)-pr-.*/
|
||||
|
||||
- build-android-unsigned:
|
||||
context: mattermost-mobile-unsigned
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
tags:
|
||||
only: /^v(\d+\.)(\d+\.)(\d+)(.*)?$/
|
||||
branches:
|
||||
only: unsigned
|
||||
- build-ios-unsigned:
|
||||
context: mattermost-mobile-unsigned
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
tags:
|
||||
only: /^v(\d+\.)(\d+\.)(\d+)(.*)?$/
|
||||
branches:
|
||||
only: unsigned
|
||||
- build-ios-simulator:
|
||||
context: mattermost-mobile-unsigned
|
||||
requires:
|
||||
- test
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- /^build-\d+$/
|
||||
- /^build-release-\d+$/
|
||||
- /^build-ios-sim-\d+$/
|
||||
|
||||
- github-release:
|
||||
context: mattermost-mobile-unsigned
|
||||
requires:
|
||||
- build-android-unsigned
|
||||
- build-ios-unsigned
|
||||
filters:
|
||||
tags:
|
||||
only: /^v(\d+\.)(\d+\.)(\d+)(.*)?$/
|
||||
branches:
|
||||
only: unsigned
|
||||
49
.github/actions/prepare-android-build/action.yaml
vendored
Normal file
49
.github/actions/prepare-android-build/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
name: prepare-android-build
|
||||
description: Action to prepare environment for android build
|
||||
|
||||
inputs:
|
||||
sign:
|
||||
description: Flag to enable android package signing
|
||||
default: "true"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: ci/prepare-mobile-build
|
||||
uses: ./.github/actions/prepare-mobile-build
|
||||
|
||||
# Disable this since we are not caching anything for now
|
||||
# - name: ci/install-gradle-dependencies
|
||||
# shell: bash
|
||||
# working-directory: android
|
||||
# run: |
|
||||
# echo "::group::install-gradle-dependencies"
|
||||
# ./gradlew dependencies
|
||||
# echo "::endgroup::"
|
||||
|
||||
- name: ci/jetify-android-libraries
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::jetify-android-libraries"
|
||||
./node_modules/.bin/jetify
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: ci/checkout-private-repo
|
||||
if: ${{ inputs.sign == 'true' }}
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
repository: mattermost/mattermost-mobile-private
|
||||
token: ${{ env.MATTERMOST_BUILD_GH_TOKEN }}
|
||||
path: ${{ github.workspace }}/mattermost-mobile-private
|
||||
|
||||
- name: ci/append-keystore-to-android-build-for-signing
|
||||
if: ${{ inputs.sign == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::append-keystore-to-android-build-for-signing"
|
||||
cp ${{ github.workspace }}/mattermost-mobile-private/android/${STORE_FILE} android/app/${STORE_FILE}
|
||||
echo "" | tee -a android/gradle.properties > /dev/null
|
||||
echo MATTERMOST_RELEASE_STORE_FILE=${STORE_FILE} | tee -a android/gradle.properties > /dev/null
|
||||
echo ${STORE_ALIAS} | tee -a android/gradle.properties > /dev/null
|
||||
echo ${STORE_PASSWORD} | tee -a android/gradle.properties > /dev/null
|
||||
echo "::endgroup::"
|
||||
25
.github/actions/prepare-ios-build/action.yaml
vendored
Normal file
25
.github/actions/prepare-ios-build/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
name: prepare-ios-build
|
||||
description: Action to prepare environment for ios build
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: ci/install-os-deps
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: "1"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::install-os-deps"
|
||||
brew install watchman
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: ci/prepare-mobile-build
|
||||
uses: ./.github/actions/prepare-mobile-build
|
||||
|
||||
- name: ci/install-pods-dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::install-pods-dependencies"
|
||||
npm run ios-gems
|
||||
npm run pod-install
|
||||
echo "::endgroup::"
|
||||
20
.github/actions/prepare-mobile-build/action.yaml
vendored
Normal file
20
.github/actions/prepare-mobile-build/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
name: prepare-mobile-build
|
||||
description: Action to prepare environment for mobile build
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: ruby/setup-ruby@9669f3ee51dc3f4eda8447ab696b3ab19a90d14b # v1.144.0
|
||||
with:
|
||||
ruby-version: "2.7.7"
|
||||
|
||||
- name: ci/setup-fastlane-dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::setup-fastlane-dependencies"
|
||||
bundle install
|
||||
echo "::endgroup::"
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/prepare-node-deps
|
||||
uses: ./.github/actions/prepare-node-deps
|
||||
46
.github/actions/prepare-node-deps/action.yaml
vendored
Normal file
46
.github/actions/prepare-node-deps/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
name: deps
|
||||
description: Common deps for mobile repo
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: ci/setup-node
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
cache: "npm"
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: ci/install-npm-dependencies
|
||||
shell: bash
|
||||
env:
|
||||
NODE_ENV: development
|
||||
run: |
|
||||
echo "::group::install-npm-dependencies"
|
||||
npm ci --ignore-scripts
|
||||
node node_modules/\@sentry/cli/scripts/install.js
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: ci/patch-npm-dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::patch-npm-dependencies"
|
||||
npx patch-package
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: ci/generate-assets
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::generate-assets"
|
||||
node ./scripts/generate-assets.js
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: ci/import-compass-icon
|
||||
shell: bash
|
||||
env:
|
||||
COMPASS_ICONS: "node_modules/@mattermost/compass-icons/font/compass-icons.ttf"
|
||||
run: |
|
||||
echo "::group::import-compass-icon"
|
||||
cp "$COMPASS_ICONS" "assets/fonts/"
|
||||
cp "$COMPASS_ICONS" "android/app/src/main/assets/fonts"
|
||||
echo "::endgroup::"
|
||||
27
.github/actions/test/action.yaml
vendored
Normal file
27
.github/actions/test/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
name: test
|
||||
description: Common tests for mobile repo
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: ci/prepare-node-deps
|
||||
uses: ./.github/actions/prepare-node-deps
|
||||
|
||||
- name: ci/check-styles
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::check-styles"
|
||||
npm run check
|
||||
echo "::endgroup::"
|
||||
- name: ci/run-tests
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::run-tests"
|
||||
npm test
|
||||
echo "::endgroup::"
|
||||
- name: ci/check-i18n
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::check-i18n"
|
||||
./scripts/precommit/i18n.sh
|
||||
echo "::endgroup::"
|
||||
61
.github/workflows/build-android-beta.yml
vendored
Normal file
61
.github/workflows/build-android-beta.yml
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
name: build-android-beta
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build-beta-[0-9]+
|
||||
- build-android-[0-9]+
|
||||
- build-android-beta-[0-9]+
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.7.0
|
||||
TERM: xterm
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
|
||||
build-and-deploy-android-beta:
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-android-build
|
||||
uses: ./.github/actions/prepare-android-build
|
||||
env:
|
||||
STORE_FILE: "${{ secrets.MM_MOBILE_STORE_FILE }}"
|
||||
STORE_ALIAS: "${{ secrets.MM_MOBILE_STORE_ALIAS }}"
|
||||
STORE_PASSWORD: "${{ secrets.MM_MOBILE_STORE_PASSWORD }}"
|
||||
MATTERMOST_BUILD_GH_TOKEN: "${{ secrets.MATTERMOST_BUILD_GH_TOKEN }}"
|
||||
|
||||
- name: ci/build-and-deploy-android-beta
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_BETA_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_BETA_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}"
|
||||
SENTRY_AUTH_TOKEN: "${{ secrets.MM_MOBILE_SENTRY_AUTH_TOKEN }}"
|
||||
SENTRY_DSN_ANDROID: ${{ secrets.MM_MOBILE_BETA_SENTRY_DSN_ANDROID }}
|
||||
SUPPLY_JSON_KEY: ${{ github.workspace }}/mattermost-mobile-private/android/mattermost-credentials.json
|
||||
run: |
|
||||
echo "::group::Build"
|
||||
bundle exec fastlane android build --env android.beta
|
||||
echo "::endgroup::"
|
||||
echo "::group::Deploy to Play Store"
|
||||
bundle exec fastlane android deploy file:"${{ github.workspace }}/*.apk" --env android.beta
|
||||
echo "::endgroup::"
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-android-beta-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: android-build-beta-${{ github.run_id }}
|
||||
path: "*.apk"
|
||||
60
.github/workflows/build-android-release.yml
vendored
Normal file
60
.github/workflows/build-android-release.yml
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
name: build-android-release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build-release-[0-9]+
|
||||
- build-release-android-[0-9]+
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.7.0
|
||||
TERM: xterm
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
|
||||
build-and-deploy-android-release:
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-android-build
|
||||
uses: ./.github/actions/prepare-android-build
|
||||
env:
|
||||
STORE_FILE: "${{ secrets.MM_MOBILE_STORE_FILE }}"
|
||||
STORE_ALIAS: "${{ secrets.MM_MOBILE_STORE_ALIAS }}"
|
||||
STORE_PASSWORD: "${{ secrets.MM_MOBILE_STORE_PASSWORD }}"
|
||||
MATTERMOST_BUILD_GH_TOKEN: "${{ secrets.MATTERMOST_BUILD_GH_TOKEN }}"
|
||||
|
||||
- name: ci/build-and-deploy-android-release
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_RELEASE_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_RELEASE_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_RELEASE_MATTERMOST_WEBHOOK_URL }}"
|
||||
SENTRY_AUTH_TOKEN: "${{ secrets.MM_MOBILE_SENTRY_AUTH_TOKEN }}"
|
||||
SENTRY_DSN_ANDROID: ${{ secrets.MM_MOBILE_RELEASE_SENTRY_DSN_ANDROID }}
|
||||
SUPPLY_JSON_KEY: ${{ github.workspace }}/mattermost-mobile-private/android/mattermost-credentials.json
|
||||
run: |
|
||||
echo "::group::Build"
|
||||
bundle exec fastlane android build --env android.release
|
||||
echo "::endgroup::"
|
||||
echo "::group::Deploy to Play Store"
|
||||
bundle exec fastlane android deploy file:"${{ github.workspace }}/*.apk" --env android.release
|
||||
echo "::endgroup::"
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-android-release-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: android-build-release-${{ github.run_id }}
|
||||
path: "*.apk"
|
||||
99
.github/workflows/build-ios-beta.yml
vendored
Normal file
99
.github/workflows/build-ios-beta.yml
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
name: build-ios-beta
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build-beta-[0-9]+
|
||||
- build-beta-ios-[0-9]+
|
||||
- build-beta-sim-[0-9]+
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.7.0
|
||||
TERM: xterm
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
|
||||
build-ios-simulator:
|
||||
runs-on: macos-12
|
||||
if: ${{ !contains(github.ref_name, 'beta-ios') }}
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-ios-build
|
||||
uses: ./.github/actions/prepare-ios-build
|
||||
|
||||
- name: ci/build-ios-simulator
|
||||
env:
|
||||
TAG: "${{ github.ref_name }}"
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_BETA_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_BETA_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}"
|
||||
GITHUB_TOKEN: "${{ secrets.MM_MOBILE_GITHUB_TOKEN }}"
|
||||
run: bundle exec fastlane ios simulator --env ios.simulator
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-ios-pr-simulator
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: ios-build-simulator-${{ github.run_id }}
|
||||
path: Mattermost-simulator-x86_64.app.zip
|
||||
|
||||
build-and-deploy-ios-beta:
|
||||
runs-on: macos-12
|
||||
if: ${{ !contains(github.ref_name, 'beta-sim') }}
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/output-ssh-private-key
|
||||
shell: bash
|
||||
run: |
|
||||
SSH_KEY_PATH=~/.ssh/id_ed25519
|
||||
mkdir -p ~/.ssh
|
||||
echo -e '${{ secrets.MM_MOBILE_PRIVATE_DEPLOY_KEY }}' > ${SSH_KEY_PATH}
|
||||
chmod 0600 ${SSH_KEY_PATH}
|
||||
ssh-keygen -y -f ${SSH_KEY_PATH} > ${SSH_KEY_PATH}.pub
|
||||
|
||||
- name: ci/prepare-ios-build
|
||||
uses: ./.github/actions/prepare-ios-build
|
||||
|
||||
- name: ci/build-and-deploy-ios-beta
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_BETA_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_BETA_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}"
|
||||
FASTLANE_TEAM_ID: "${{ secrets.MM_MOBILE_FASTLANE_TEAM_ID }}"
|
||||
IOS_API_ISSUER_ID: "${{ secrets.MM_MOBILE_IOS_API_ISSUER_ID }}"
|
||||
IOS_API_KEY: "${{ secrets.MM_MOBILE_IOS_API_KEY }}"
|
||||
IOS_API_KEY_ID: "${{ secrets.MM_MOBILE_IOS_API_KEY_ID }}"
|
||||
MATCH_GIT_URL: "${{ secrets.MM_MOBILE_MATCH_GIT_URL }}"
|
||||
MATCH_PASSWORD: "${{ secrets.MM_MOBILE_MATCH_PASSWORD }}"
|
||||
SENTRY_AUTH_TOKEN: "${{ secrets.MM_MOBILE_SENTRY_AUTH_TOKEN }}"
|
||||
SENTRY_DSN_IOS: "${{ secrets.MM_MOBILE_BETA_SENTRY_DSN_IOS }}"
|
||||
run: |
|
||||
echo "::group::Build"
|
||||
bundle exec fastlane ios build --env ios.beta
|
||||
echo "::endgroup::"
|
||||
echo "::group::Deploy to TestFlight"
|
||||
bundle exec fastlane ios deploy file:"${{ github.workspace }}/*.ipa" --env ios.beta
|
||||
echo "::endgroup::"
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-ios-beta-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: ios-build-beta-${{ github.run_id }}
|
||||
path: "*.ipa"
|
||||
99
.github/workflows/build-ios-release.yml
vendored
Normal file
99
.github/workflows/build-ios-release.yml
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
name: build-ios-release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build-release-[0-9]+
|
||||
- build-release-ios-[0-9]+
|
||||
- build-release-sim-[0-9]+
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.7.0
|
||||
TERM: xterm
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
|
||||
build-and-deploy-ios-release:
|
||||
runs-on: macos-12
|
||||
if: ${{ !contains(github.ref_name, 'release-sim') }}
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-ios-build
|
||||
uses: ./.github/actions/prepare-ios-build
|
||||
|
||||
- name: ci/output-ssh-private-key
|
||||
shell: bash
|
||||
run: |
|
||||
SSH_KEY_PATH=~/.ssh/id_ed25519
|
||||
mkdir -p ~/.ssh
|
||||
echo -e '${{ secrets.MM_MOBILE_PRIVATE_DEPLOY_KEY }}' > ${SSH_KEY_PATH}
|
||||
chmod 0600 ${SSH_KEY_PATH}
|
||||
ssh-keygen -y -f ${SSH_KEY_PATH} > ${SSH_KEY_PATH}.pub
|
||||
|
||||
- name: ci/build-and-deploy-ios-release
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_RELEASE_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_RELEASE_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_RELEASE_MATTERMOST_WEBHOOK_URL }}"
|
||||
FASTLANE_TEAM_ID: "${{ secrets.MM_MOBILE_FASTLANE_TEAM_ID }}"
|
||||
IOS_API_ISSUER_ID: "${{ secrets.MM_MOBILE_IOS_API_ISSUER_ID }}"
|
||||
IOS_API_KEY: "${{ secrets.MM_MOBILE_IOS_API_KEY }}"
|
||||
IOS_API_KEY_ID: "${{ secrets.MM_MOBILE_IOS_API_KEY_ID }}"
|
||||
MATCH_GIT_URL: "${{ secrets.MM_MOBILE_MATCH_GIT_URL }}"
|
||||
MATCH_PASSWORD: "${{ secrets.MM_MOBILE_MATCH_PASSWORD }}"
|
||||
SENTRY_AUTH_TOKEN: "${{ secrets.MM_MOBILE_SENTRY_AUTH_TOKEN }}"
|
||||
SENTRY_DSN_IOS: ${{ secrets.MM_MOBILE_RELEASE_SENTRY_DSN_IOS }}
|
||||
run: |
|
||||
echo "::group::Build"
|
||||
bundle exec fastlane ios build --env ios.release
|
||||
echo "::endgroup::"
|
||||
echo "::group::Deploy to TestFlight"
|
||||
bundle exec fastlane ios deploy file:"${{ github.workspace }}/*.ipa" --env ios.release
|
||||
echo "::endgroup::"
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-ios-release-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: ios-build-release-${{ github.run_id }}
|
||||
path: "*.ipa"
|
||||
|
||||
build-ios-simulator:
|
||||
runs-on: macos-12
|
||||
if: ${{ !contains(github.ref_name , 'release-ios') }}
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-ios-build
|
||||
uses: ./.github/actions/prepare-ios-build
|
||||
|
||||
- name: ci/build-ios-simulator
|
||||
env:
|
||||
TAG: "${{ github.ref_name }}"
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_BETA_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_BETA_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_BETA_MATTERMOST_WEBHOOK_URL }}"
|
||||
GITHUB_TOKEN: "${{ secrets.MM_MOBILE_GITHUB_TOKEN }}"
|
||||
run: bundle exec fastlane ios simulator --env ios.simulator
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-ios-pr-simulator
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: ios-build-simulator-${{ github.run_id }}
|
||||
path: Mattermost-simulator-x86_64.app.zip
|
||||
95
.github/workflows/build-pr.yml
vendored
Normal file
95
.github/workflows/build-pr.yml
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
name: build-pr
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build-pr-*
|
||||
- build-pr-android-*
|
||||
- build-pr-ios-*
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.7.0
|
||||
TERM: xterm
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
|
||||
build-ios-pr:
|
||||
runs-on: macos-12
|
||||
if: ${{ !contains(github.ref_name, 'android') }}
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-ios-build
|
||||
uses: ./.github/actions/prepare-ios-build
|
||||
|
||||
- name: ci/output-ssh-private-key
|
||||
shell: bash
|
||||
run: |
|
||||
SSH_KEY_PATH=~/.ssh/id_ed25519
|
||||
mkdir -p ~/.ssh
|
||||
echo -e '${{ secrets.MM_MOBILE_PRIVATE_DEPLOY_KEY }}' > ${SSH_KEY_PATH}
|
||||
chmod 0600 ${SSH_KEY_PATH}
|
||||
ssh-keygen -y -f ${SSH_KEY_PATH} > ${SSH_KEY_PATH}.pub
|
||||
|
||||
- name: ci/build-ios-pr
|
||||
env:
|
||||
BRANCH_TO_BUILD: "${{ github.ref_name }}"
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_PR_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_PR_AWS_SECRET_ACCESS_KEY }}"
|
||||
FASTLANE_TEAM_ID: "${{ secrets.MM_MOBILE_FASTLANE_TEAM_ID }}"
|
||||
IOS_API_ISSUER_ID: "${{ secrets.MM_MOBILE_IOS_API_ISSUER_ID }}"
|
||||
IOS_API_KEY: "${{ secrets.MM_MOBILE_IOS_API_KEY }}"
|
||||
IOS_API_KEY_ID: "${{ secrets.MM_MOBILE_IOS_API_KEY_ID }}"
|
||||
MATCH_GIT_URL: "${{ secrets.MM_MOBILE_MATCH_GIT_URL }}"
|
||||
MATCH_PASSWORD: "${{ secrets.MM_MOBILE_MATCH_PASSWORD }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_PR_MATTERMOST_WEBHOOK_URL }}"
|
||||
run: bundle exec fastlane ios build --env ios.pr
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-ios-pr-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: ios-build-pr-${{ github.run_id }}
|
||||
path: "*.ipa"
|
||||
|
||||
build-android-pr:
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ !contains(github.ref_name, 'ios') }}
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-android-build
|
||||
uses: ./.github/actions/prepare-android-build
|
||||
env:
|
||||
STORE_FILE: "${{ secrets.MM_MOBILE_STORE_FILE }}"
|
||||
STORE_ALIAS: "${{ secrets.MM_MOBILE_STORE_ALIAS }}"
|
||||
STORE_PASSWORD: "${{ secrets.MM_MOBILE_STORE_PASSWORD }}"
|
||||
MATTERMOST_BUILD_GH_TOKEN: "${{ secrets.MATTERMOST_BUILD_GH_TOKEN }}"
|
||||
|
||||
- name: ci/build-android-pr
|
||||
env:
|
||||
BRANCH_TO_BUILD: "${{ github.ref_name }}"
|
||||
AWS_ACCESS_KEY_ID: "${{ secrets.MM_MOBILE_PR_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets.MM_MOBILE_PR_AWS_SECRET_ACCESS_KEY }}"
|
||||
MATTERMOST_WEBHOOK_URL: "${{ secrets.MM_MOBILE_PR_MATTERMOST_WEBHOOK_URL }}"
|
||||
run: bundle exec fastlane android build --env android.pr
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-android-pr-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: android-build-pr-${{ github.run_id }}
|
||||
path: "*.apk"
|
||||
17
.github/workflows/ci.yml
vendored
Normal file
17
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
name: ci
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
NODE_VERSION: 18.7.0
|
||||
TERM: xterm
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
100
.github/workflows/github-release.yml
vendored
Normal file
100
.github/workflows/github-release.yml
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
name: github-release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
- name: ci/test
|
||||
uses: ./.github/actions/test
|
||||
|
||||
build-ios-unsigned:
|
||||
runs-on: macos-12
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-ios-build
|
||||
uses: ./.github/actions/prepare-ios-build
|
||||
|
||||
- name: ci/output-ssh-private-key
|
||||
shell: bash
|
||||
run: |
|
||||
SSH_KEY_PATH=~/.ssh/id_ed25519
|
||||
mkdir -p ~/.ssh
|
||||
echo -e '${{ secrets.MM_MOBILE_PRIVATE_DEPLOY_KEY }}' > ${SSH_KEY_PATH}
|
||||
chmod 0600 ${SSH_KEY_PATH}
|
||||
ssh-keygen -y -f ${SSH_KEY_PATH} > ${SSH_KEY_PATH}.pub
|
||||
|
||||
- name: ci/build-ios-unsigned
|
||||
env:
|
||||
TAG: "${{ github.ref_name }}"
|
||||
GITHUB_TOKEN: "${{ secrets.MM_MOBILE_GITHUB_TOKEN }}"
|
||||
run: bundle exec fastlane ios unsigned
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-ios-unsigned
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
path: Mattermost-unsigned.ipa
|
||||
name: Mattermost-unsigned.ipa
|
||||
|
||||
build-android-unsigned:
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- test
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: ci/prepare-android-build
|
||||
uses: ./.github/actions/prepare-android-build
|
||||
with:
|
||||
sign: false
|
||||
|
||||
- name: ci/build-android-beta
|
||||
env:
|
||||
TAG: "${{ github.ref_name }}"
|
||||
GITHUB_TOKEN: "${{ secrets.MM_MOBILE_GITHUB_TOKEN }}"
|
||||
run: bundle exec fastlane android unsigned
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/upload-android-unsigned-build
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
path: Mattermost-unsigned.apk
|
||||
name: Mattermost-unsigned.apk
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-22.04
|
||||
needs:
|
||||
- build-ios-unsigned
|
||||
- build-android-unsigned
|
||||
steps:
|
||||
- name: ci/checkout-repo
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- uses: ruby/setup-ruby@9669f3ee51dc3f4eda8447ab696b3ab19a90d14b # v1.144.0
|
||||
with:
|
||||
ruby-version: "2.7"
|
||||
|
||||
- name: release/setup-fastlane-dependencies
|
||||
run: bundle install
|
||||
working-directory: ./fastlane
|
||||
|
||||
- name: ci/download-artifacts
|
||||
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
|
||||
|
||||
- name: release/create-github-release
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.MM_MOBILE_GITHUB_TOKEN }}"
|
||||
run: bundle exec fastlane github
|
||||
working-directory: ./fastlane
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -103,6 +103,7 @@ detox/detox_pixel_*
|
|||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
.bundle
|
||||
|
||||
#editor-settings
|
||||
.vscode
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ android {
|
|||
applicationId "com.mattermost.rnbeta"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 473
|
||||
versionName "2.5.0"
|
||||
versionCode 476
|
||||
versionName "2.5.1"
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class DatabaseHelper {
|
|||
private fun setDefaultDatabase(context: Context) {
|
||||
val databaseName = "app.db"
|
||||
val databasePath = Uri.fromFile(context.filesDir).toString() + "/" + databaseName
|
||||
defaultDatabase = Database(databasePath, context)
|
||||
defaultDatabase = Database.getInstance(databasePath, context)
|
||||
}
|
||||
|
||||
internal fun JSONObject.toMap(): Map<String, Any?> = keys().asSequence().associateWith { it ->
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fun DatabaseHelper.getDatabaseForServer(context: Context?, serverUrl: String): D
|
|||
if (cursor.count == 1) {
|
||||
cursor.moveToFirst()
|
||||
val databasePath = cursor.getString(0)
|
||||
return Database(databasePath, context!!)
|
||||
return Database.getInstance(databasePath, context!!)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import {DeviceEventEmitter} from 'react-native';
|
|||
import {addChannelToDefaultCategory, storeCategories} from '@actions/local/category';
|
||||
import {markChannelAsViewed, removeCurrentUserFromChannel, setChannelDeleteAt, storeMyChannelsForTeam, switchToChannel} from '@actions/local/channel';
|
||||
import {switchToGlobalThreads} from '@actions/local/thread';
|
||||
import {getIsCRTEnabled} from '@app/queries/servers/thread';
|
||||
import {loadCallForChannel} from '@calls/actions/calls';
|
||||
import {DeepLink, Events, General, Preferences, Screens} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
|
|
@ -20,6 +19,7 @@ import {prepareMyChannelsForTeam, getChannelById, getChannelByName, getMyChannel
|
|||
import {queryDisplayNamePreferences} from '@queries/servers/preference';
|
||||
import {getCommonSystemValues, getConfig, getCurrentChannelId, getCurrentTeamId, getCurrentUserId, getLicense, setCurrentChannelId, setCurrentTeamAndChannelId} from '@queries/servers/system';
|
||||
import {getNthLastChannelFromTeam, getMyTeamById, getTeamByName, queryMyTeams, removeChannelFromTeamHistory} from '@queries/servers/team';
|
||||
import {getIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {getCurrentUser} from '@queries/servers/user';
|
||||
import {dismissAllModalsAndPopToRoot} from '@screens/navigation';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const fetchGroupsForAutocomplete = async (serverUrl: string, query: strin
|
|||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
if (!license || !license.IsLicensed) {
|
||||
if (!license || license.IsLicensed !== 'true') {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ export const fetchGroupsByNames = async (serverUrl: string, names: string[], fet
|
|||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
if (!license || !license.IsLicensed) {
|
||||
if (!license || license.IsLicensed !== 'true') {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ export const fetchGroupsForChannel = async (serverUrl: string, channelId: string
|
|||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
if (!license || !license.IsLicensed) {
|
||||
if (!license || license.IsLicensed !== 'true') {
|
||||
return {groups: [], groupChannels: []};
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ export const fetchGroupsForTeam = async (serverUrl: string, teamId: string, fetc
|
|||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
if (!license || !license.IsLicensed) {
|
||||
if (!license || license.IsLicensed !== 'true') {
|
||||
return {groups: [], groupTeams: []};
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ export const fetchGroupsForMember = async (serverUrl: string, userId: string, fe
|
|||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
if (!license || !license.IsLicensed) {
|
||||
if (!license || license.IsLicensed !== 'true') {
|
||||
return {groups: [], groupMemberships: []};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ export const fetchPostsForUnreadChannels = async (serverUrl: string, channels: C
|
|||
const promises = [];
|
||||
for (const member of memberships) {
|
||||
const channel = channels.find((c) => c.id === member.channel_id);
|
||||
if (channel && (channel.total_msg_count - member.msg_count) > 0 && channel.id !== excludeChannelId) {
|
||||
if (channel && !channel.delete_at && (channel.total_msg_count - member.msg_count) > 0 && channel.id !== excludeChannelId) {
|
||||
promises.push(fetchPostsForChannel(serverUrl, channel.id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useMemo, useState} from 'react';
|
||||
import {type StyleProp, StyleSheet, useWindowDimensions, View, type ViewStyle} from 'react-native';
|
||||
import {StyleSheet, useWindowDimensions, View} from 'react-native';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
|
||||
import {buildFilePreviewUrl, buildFileThumbnailUrl} from '@actions/remote/file';
|
||||
|
|
@ -59,15 +59,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
imagePreview: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
},
|
||||
smallImageBorder: {
|
||||
borderRadius: 5,
|
||||
},
|
||||
smallImageOverlay: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: 4,
|
||||
position: 'absolute',
|
||||
},
|
||||
singleSmallImageWrapper: {
|
||||
height: SMALL_IMAGE_MAX_HEIGHT,
|
||||
width: SMALL_IMAGE_MAX_WIDTH,
|
||||
|
|
@ -117,56 +108,9 @@ const ImageFile = ({
|
|||
return props;
|
||||
};
|
||||
|
||||
const imageDimensions = getImageDimensions();
|
||||
if (imageDimensions && (imageDimensions.height <= SMALL_IMAGE_MAX_HEIGHT || imageDimensions.width <= SMALL_IMAGE_MAX_WIDTH)) {
|
||||
let wrapperStyle: StyleProp<ViewStyle> = style.fileImageWrapper;
|
||||
if (isSingleImage) {
|
||||
wrapperStyle = style.singleSmallImageWrapper;
|
||||
|
||||
if (file.width > SMALL_IMAGE_MAX_WIDTH) {
|
||||
wrapperStyle = [wrapperStyle, {width: '100%'}];
|
||||
}
|
||||
}
|
||||
|
||||
image = (
|
||||
<ProgressiveImage
|
||||
id={file.id!}
|
||||
forwardRef={forwardRef}
|
||||
style={{height: file.height, width: file.width}}
|
||||
tintDefaultSource={!file.localPath && !failed}
|
||||
onError={handleError}
|
||||
resizeMode={'contain'}
|
||||
{...imageProps()}
|
||||
/>
|
||||
);
|
||||
|
||||
if (failed) {
|
||||
image = (
|
||||
<FileIcon
|
||||
failed={failed}
|
||||
file={file}
|
||||
backgroundColor={backgroundColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
wrapperStyle,
|
||||
style.smallImageBorder,
|
||||
{
|
||||
borderColor: changeOpacity(theme.centerChannelColor, 0.4),
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
|
||||
},
|
||||
]}
|
||||
>
|
||||
{!isSingleImage && <View style={style.boxPlaceholder}/>}
|
||||
<View style={style.smallImageOverlay}>
|
||||
{image}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
let imageDimensions = getImageDimensions();
|
||||
if (isSingleImage && (!imageDimensions || (imageDimensions?.height === 0 && imageDimensions?.width === 0))) {
|
||||
imageDimensions = style.singleSmallImageWrapper;
|
||||
}
|
||||
|
||||
image = (
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import React, {useEffect, useRef, useState} from 'react';
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
|
||||
import Badge from '@components/badge';
|
||||
import {Screens} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {subscribeAllServers} from '@database/subscription/servers';
|
||||
import {subscribeMentionsByServer} from '@database/subscription/unreads';
|
||||
|
||||
|
|
@ -27,9 +29,9 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
});
|
||||
|
||||
const subscriptions: Map<string, UnreadSubscription> = new Map();
|
||||
|
||||
const OtherMentionsBadge = ({channelId}: Props) => {
|
||||
const currentServerUrl = useServerUrl();
|
||||
const subscriptions: Map<string, UnreadSubscription> = useRef(new Map()).current;
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
const updateCount = () => {
|
||||
|
|
@ -50,7 +52,10 @@ const OtherMentionsBadge = ({channelId}: Props) => {
|
|||
}
|
||||
}
|
||||
|
||||
unreads.mentions = mentions + threadMentionCount;
|
||||
unreads.mentions = mentions;
|
||||
if (serverUrl !== currentServerUrl || channelId !== Screens.GLOBAL_THREADS) {
|
||||
unreads.mentions += threadMentionCount;
|
||||
}
|
||||
subscriptions.set(serverUrl, unreads);
|
||||
updateCount();
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ export default function SendHandler({
|
|||
|
||||
const sendCommand = useCallback(async () => {
|
||||
if (value.trim().startsWith('/call')) {
|
||||
const {handled, error} = await handleCallsSlashCommand(value.trim(), serverUrl, channelId, currentUserId, intl);
|
||||
const {handled, error} = await handleCallsSlashCommand(value.trim(), serverUrl, channelId, rootId, currentUserId, intl);
|
||||
if (handled) {
|
||||
setSendingMessage(false);
|
||||
clearDraft();
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ const PostList = ({
|
|||
|
||||
const viewableItemsMap = viewableItems.reduce((acc: Record<string, boolean>, {item, isViewable}) => {
|
||||
if (isViewable && item.type === 'post') {
|
||||
acc[`${location}-${item.value.id}`] = true;
|
||||
acc[`${location}-${item.value.currentPost.id}`] = true;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import FastImage, {type ResizeMode} from 'react-native-fast-image';
|
|||
import Animated, {interpolate, useAnimatedStyle, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated';
|
||||
|
||||
import {useTheme} from '@context/theme';
|
||||
import {emptyFunction} from '@utils/general';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import Thumbnail from './thumbnail';
|
||||
|
|
@ -153,8 +154,9 @@ const ProgressiveImage = ({
|
|||
<Animated.View
|
||||
style={[styles.defaultImageContainer, style, containerStyle]}
|
||||
>
|
||||
{Boolean(thumbnailUri) &&
|
||||
<Thumbnail
|
||||
onError={onError}
|
||||
onError={emptyFunction}
|
||||
opacity={defaultOpacity}
|
||||
source={{uri: thumbnailUri}}
|
||||
style={[
|
||||
|
|
@ -163,6 +165,7 @@ const ProgressiveImage = ({
|
|||
]}
|
||||
tintColor={thumbnailUri ? undefined : theme.centerChannelColor}
|
||||
/>
|
||||
}
|
||||
{image}
|
||||
</Animated.View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -186,11 +186,11 @@ export default class BaseDataOperator {
|
|||
try {
|
||||
if (models.length > 0) {
|
||||
await this.database.write(async (writer) => {
|
||||
await writer.batch(models);
|
||||
await writer.batch(...models);
|
||||
}, description);
|
||||
}
|
||||
} catch (e) {
|
||||
logWarning('batchRecords error ', e as Error);
|
||||
logWarning('batchRecords error ', description, e as Error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import {requestNotifications} from 'react-native-permissions';
|
|||
|
||||
import {storeDeviceToken} from '@actions/app/global';
|
||||
import {markChannelAsViewed} from '@actions/local/channel';
|
||||
import {updateThread} from '@actions/local/thread';
|
||||
import {backgroundNotification, openNotification} from '@actions/remote/notifications';
|
||||
import {markThreadAsRead} from '@actions/remote/thread';
|
||||
import {Device, Events, Navigation, PushNotification, Screens} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
|
||||
|
|
@ -90,7 +90,12 @@ class PushNotifications {
|
|||
if (isCRTEnabled && payload.root_id) {
|
||||
const thread = await getThreadById(database, payload.root_id);
|
||||
if (thread?.isFollowing) {
|
||||
markThreadAsRead(serverUrl, payload.team_id, payload.root_id);
|
||||
const data: Partial<ThreadWithViewedAt> = {
|
||||
unread_mentions: 0,
|
||||
unread_replies: 0,
|
||||
last_viewed_at: Date.now(),
|
||||
};
|
||||
updateThread(serverUrl, payload.root_id, data);
|
||||
}
|
||||
} else {
|
||||
markChannelAsViewed(serverUrl, payload.channel_id);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Alert, DeviceEventEmitter, Linking, NativeEventEmitter, NativeModules} from 'react-native';
|
||||
import RNLocalize from 'react-native-localize';
|
||||
import semver from 'semver';
|
||||
|
||||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {autoUpdateTimezone} from '@actions/remote/user';
|
||||
import LocalConfig from '@assets/config.json';
|
||||
import {Device, Events, Sso} from '@constants';
|
||||
import {MIN_REQUIRED_VERSION} from '@constants/supported_server';
|
||||
|
|
@ -14,13 +12,12 @@ import DatabaseManager from '@database/manager';
|
|||
import {DEFAULT_LOCALE, getTranslations, t} from '@i18n';
|
||||
import {getServerCredentials} from '@init/credentials';
|
||||
import * as analytics from '@managers/analytics';
|
||||
import {getAllServers, getActiveServerUrl} from '@queries/app/servers';
|
||||
import {getActiveServerUrl} from '@queries/app/servers';
|
||||
import {queryTeamDefaultChannel} from '@queries/servers/channel';
|
||||
import {getCommonSystemValues} from '@queries/servers/system';
|
||||
import {getTeamChannelHistory} from '@queries/servers/team';
|
||||
import {setScreensOrientation} from '@screens/navigation';
|
||||
import {handleDeepLink} from '@utils/deep_link';
|
||||
import {logError} from '@utils/log';
|
||||
|
||||
type LinkingCallbackArg = {url: string};
|
||||
|
||||
|
|
@ -33,19 +30,6 @@ class GlobalEventHandler {
|
|||
constructor() {
|
||||
DeviceEventEmitter.addListener(Events.SERVER_VERSION_CHANGED, this.onServerVersionChanged);
|
||||
DeviceEventEmitter.addListener(Events.CONFIG_CHANGED, this.onServerConfigChanged);
|
||||
RNLocalize.addEventListener('change', async () => {
|
||||
try {
|
||||
const servers = await getAllServers();
|
||||
for (const server of servers) {
|
||||
if (server.url && server.lastActiveAt > 0) {
|
||||
autoUpdateTimezone(server.url);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('Localize change', e);
|
||||
}
|
||||
});
|
||||
|
||||
splitViewEmitter.addListener('SplitViewChanged', this.onSplitViewChanged);
|
||||
Linking.addEventListener('url', this.onDeepLink);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,13 @@ jest.mock('@queries/servers/thread', () => ({
|
|||
}));
|
||||
|
||||
jest.mock('@calls/alerts');
|
||||
jest.mock('react-native-navigation', () => ({
|
||||
Navigation: {
|
||||
pop: jest.fn(() => Promise.resolve({
|
||||
catch: jest.fn(),
|
||||
})),
|
||||
},
|
||||
}));
|
||||
|
||||
const addFakeCall = (serverUrl: string, channelId: string) => {
|
||||
const call = {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
import {Alert} from 'react-native';
|
||||
import InCallManager from 'react-native-incall-manager';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import {forceLogoutIfNecessary} from '@actions/remote/session';
|
||||
import {updateThreadFollowing} from '@actions/remote/thread';
|
||||
|
|
@ -24,7 +23,7 @@ import {
|
|||
getCurrentCall,
|
||||
getChannelsWithCalls,
|
||||
} from '@calls/state';
|
||||
import {General, Preferences, Screens} from '@constants';
|
||||
import {General, Preferences} from '@constants';
|
||||
import Calls from '@constants/calls';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
|
|
@ -34,8 +33,6 @@ import {queryDisplayNamePreferences} from '@queries/servers/preference';
|
|||
import {getConfig, getLicense} from '@queries/servers/system';
|
||||
import {getThreadById} from '@queries/servers/thread';
|
||||
import {getCurrentUser, getUserById} from '@queries/servers/user';
|
||||
import {dismissAllModalsAndPopToScreen} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {getFullErrorMessage} from '@utils/errors';
|
||||
import {logDebug} from '@utils/log';
|
||||
import {displayUsername, getUserIdFromChannelName, isSystemAdmin} from '@utils/user';
|
||||
|
|
@ -211,6 +208,7 @@ export const joinCall = async (
|
|||
userId: string,
|
||||
hasMicPermission: boolean,
|
||||
title?: string,
|
||||
rootId?: string,
|
||||
): Promise<{ error?: unknown; data?: string }> => {
|
||||
// Edge case: calls was disabled when app loaded, and then enabled, but app hasn't
|
||||
// reconnected its websocket since then (i.e., hasn't called batchLoadCalls yet)
|
||||
|
|
@ -229,7 +227,7 @@ export const joinCall = async (
|
|||
try {
|
||||
connection = await newConnection(serverUrl, channelId, () => {
|
||||
myselfLeftCall();
|
||||
}, setScreenShareURL, hasMicPermission, title);
|
||||
}, setScreenShareURL, hasMicPermission, title, rootId);
|
||||
} catch (error) {
|
||||
await forceLogoutIfNecessary(serverUrl, error);
|
||||
return {error};
|
||||
|
|
@ -271,16 +269,6 @@ export const leaveCall = () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const leaveCallPopCallScreen = async () => {
|
||||
leaveCall();
|
||||
|
||||
// Need to pop the call screen, if it's somewhere in the stack.
|
||||
if (NavigationStore.getScreensInStack().includes(Screens.CALL)) {
|
||||
await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call');
|
||||
Navigation.pop(Screens.CALL).catch(() => null);
|
||||
}
|
||||
};
|
||||
|
||||
export const muteMyself = () => {
|
||||
if (connection) {
|
||||
connection.mute();
|
||||
|
|
@ -430,7 +418,7 @@ export const stopCallRecording = async (serverUrl: string, callId: string) => {
|
|||
};
|
||||
|
||||
// handleCallsSlashCommand will return true if the slash command was handled
|
||||
export const handleCallsSlashCommand = async (value: string, serverUrl: string, channelId: string, currentUserId: string, intl: IntlShape):
|
||||
export const handleCallsSlashCommand = async (value: string, serverUrl: string, channelId: string, rootId: string, currentUserId: string, intl: IntlShape):
|
||||
Promise<{ handled?: boolean; error?: string }> => {
|
||||
const tokens = value.split(' ');
|
||||
if (tokens.length < 2 || tokens[0] !== '/call') {
|
||||
|
|
@ -451,15 +439,17 @@ export const handleCallsSlashCommand = async (value: string, serverUrl: string,
|
|||
};
|
||||
}
|
||||
const title = tokens.length > 2 ? tokens.slice(2).join(' ') : undefined;
|
||||
await leaveAndJoinWithAlert(intl, serverUrl, channelId, title);
|
||||
await leaveAndJoinWithAlert(intl, serverUrl, channelId, title, rootId);
|
||||
return {handled: true};
|
||||
}
|
||||
case 'join':
|
||||
await leaveAndJoinWithAlert(intl, serverUrl, channelId);
|
||||
case 'join': {
|
||||
const title = tokens.length > 2 ? tokens.slice(2).join(' ') : undefined;
|
||||
await leaveAndJoinWithAlert(intl, serverUrl, channelId, title, rootId);
|
||||
return {handled: true};
|
||||
}
|
||||
case 'leave':
|
||||
if (getCurrentCall()?.channelId === channelId) {
|
||||
await leaveCallPopCallScreen();
|
||||
await leaveCall();
|
||||
return {handled: true};
|
||||
}
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
|
||||
import {Alert} from 'react-native';
|
||||
|
||||
import {hasMicrophonePermission, joinCall, unmuteMyself} from '@calls/actions';
|
||||
import {leaveCallPopCallScreen} from '@calls/actions/calls';
|
||||
import {hasMicrophonePermission, joinCall, leaveCall, unmuteMyself} from '@calls/actions';
|
||||
import {hasBluetoothPermission} from '@calls/actions/permissions';
|
||||
import {
|
||||
getCallsConfig,
|
||||
|
|
@ -73,6 +72,7 @@ export const leaveAndJoinWithAlert = async (
|
|||
joinServerUrl: string,
|
||||
joinChannelId: string,
|
||||
title?: string,
|
||||
rootId?: string,
|
||||
) => {
|
||||
let leaveChannelName = '';
|
||||
let joinChannelName = '';
|
||||
|
|
@ -133,13 +133,13 @@ export const leaveAndJoinWithAlert = async (
|
|||
id: 'mobile.leave_and_join_confirmation',
|
||||
defaultMessage: 'Leave & Join',
|
||||
}),
|
||||
onPress: () => doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title),
|
||||
onPress: () => doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title, rootId),
|
||||
style: 'cancel',
|
||||
},
|
||||
],
|
||||
);
|
||||
} else {
|
||||
doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title);
|
||||
doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title, rootId);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -150,6 +150,7 @@ const doJoinCall = async (
|
|||
newCall: boolean,
|
||||
intl: IntlShape,
|
||||
title?: string,
|
||||
rootId?: string,
|
||||
) => {
|
||||
const {formatMessage} = intl;
|
||||
|
||||
|
|
@ -198,7 +199,7 @@ const doJoinCall = async (
|
|||
const hasPermission = await hasMicrophonePermission();
|
||||
setMicPermissionsGranted(hasPermission);
|
||||
|
||||
const res = await joinCall(serverUrl, channelId, user.id, hasPermission, title);
|
||||
const res = await joinCall(serverUrl, channelId, user.id, hasPermission, title, rootId);
|
||||
if (res.error) {
|
||||
const seeLogs = formatMessage({id: 'mobile.calls_see_logs', defaultMessage: 'See server logs'});
|
||||
errorAlert(res.error?.toString() || seeLogs, intl);
|
||||
|
|
@ -265,7 +266,7 @@ export const recordingAlert = (isHost: boolean, intl: IntlShape) => {
|
|||
defaultMessage: 'Leave',
|
||||
}),
|
||||
onPress: async () => {
|
||||
await leaveCallPopCallScreen();
|
||||
await leaveCall();
|
||||
},
|
||||
style: 'destructive',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export async function newConnection(
|
|||
setScreenShareURL: (url: string) => void,
|
||||
hasMicPermission: boolean,
|
||||
title?: string,
|
||||
rootId?: string,
|
||||
) {
|
||||
let peer: RTCPeer | null = null;
|
||||
let stream: MediaStream;
|
||||
|
|
@ -323,6 +324,7 @@ export async function newConnection(
|
|||
ws.send('join', {
|
||||
channelID,
|
||||
title,
|
||||
threadID: rootId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {
|
||||
DeviceEventEmitter,
|
||||
Keyboard,
|
||||
type LayoutChangeEvent,
|
||||
type LayoutRectangle,
|
||||
|
|
@ -40,7 +39,7 @@ import {getHandsRaised, makeCallsTheme, sortParticipants} from '@calls/utils';
|
|||
import CompassIcon from '@components/compass_icon';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
||||
import {Calls, Preferences, Screens, WebsocketEvents} from '@constants';
|
||||
import {Calls, Preferences, Screens} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import DatabaseManager from '@database/manager';
|
||||
|
|
@ -56,7 +55,6 @@ import {
|
|||
popTopScreen,
|
||||
setScreensOrientation,
|
||||
} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {freezeOtherScreens} from '@utils/gallery';
|
||||
import {bottomSheetSnapPoint} from '@utils/helpers';
|
||||
import {mergeNavigationOptions} from '@utils/navigation';
|
||||
|
|
@ -504,16 +502,6 @@ const CallScreen = ({
|
|||
popTopScreen(componentId);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const listener = DeviceEventEmitter.addListener(WebsocketEvents.CALLS_CALL_END, ({channelId}) => {
|
||||
if (channelId === currentCall?.channelId && NavigationStore.getVisibleScreen() === componentId) {
|
||||
Navigation.pop(componentId);
|
||||
}
|
||||
});
|
||||
|
||||
return () => listener.remove();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const didDismissListener = Navigation.events().registerComponentDidDisappearListener(async ({componentId: screen}) => {
|
||||
if (componentId === screen) {
|
||||
|
|
@ -550,13 +538,6 @@ const CallScreen = ({
|
|||
}, []);
|
||||
|
||||
if (!currentCall || !myParticipant) {
|
||||
// Note: this happens because the screen is "rendered", even after the screen has been popped, and the
|
||||
// currentCall will have already been set to null when those extra renders run. We probably don't ever need
|
||||
// to pop, but just in case.
|
||||
if (NavigationStore.getVisibleScreen() === componentId) {
|
||||
// ignore the error because the call screen has likely already been popped async
|
||||
Navigation.pop(componentId).catch(() => null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,14 @@ jest.mock('@queries/servers/thread', () => ({
|
|||
})),
|
||||
}));
|
||||
|
||||
jest.mock('react-native-navigation', () => ({
|
||||
Navigation: {
|
||||
pop: jest.fn(() => Promise.resolve({
|
||||
catch: jest.fn(),
|
||||
})),
|
||||
},
|
||||
}));
|
||||
|
||||
const call1: Call = {
|
||||
participants: {
|
||||
'user-1': {id: 'user-1', muted: false, raisedHand: 0},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {mosThreshold} from '@mattermost/calls/lib/rtc_monitor';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import {updateThreadFollowing} from '@actions/remote/thread';
|
||||
import {needsRecordingAlert} from '@calls/alerts';
|
||||
|
|
@ -27,7 +28,7 @@ import {
|
|||
DefaultCurrentCall,
|
||||
type ReactionStreamEmoji,
|
||||
} from '@calls/types/calls';
|
||||
import {Calls} from '@constants';
|
||||
import {Calls, Screens} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getChannelById} from '@queries/servers/channel';
|
||||
import {getThreadById} from '@queries/servers/thread';
|
||||
|
|
@ -217,6 +218,10 @@ export const newCurrentCall = (serverUrl: string, channelId: string, myUserId: s
|
|||
|
||||
export const myselfLeftCall = () => {
|
||||
setCurrentCall(null);
|
||||
|
||||
// Remove the call screen, and in some situations it needs to be removed twice before actually being removed.
|
||||
Navigation.pop(Screens.CALL).catch(() => null);
|
||||
Navigation.pop(Screens.CALL).catch(() => null);
|
||||
};
|
||||
|
||||
export const callStarted = async (serverUrl: string, call: Call) => {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import BottomSheetM, {BottomSheetBackdrop, type BottomSheetBackdropProps, type BottomSheetFooterProps} from '@gorhom/bottom-sheet';
|
||||
import React, {type ReactNode, useCallback, useEffect, useMemo, useRef} from 'react';
|
||||
import {DeviceEventEmitter, type Handle, InteractionManager, Keyboard, type StyleProp, View, type ViewStyle} from 'react-native';
|
||||
import {GestureHandlerRootView} from 'react-native-gesture-handler';
|
||||
|
||||
import {Events} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
|
|
@ -38,6 +39,7 @@ const PADDING_TOP_TABLET = 8;
|
|||
|
||||
export const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
container: {flex: 1},
|
||||
bottomSheet: {
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
borderTopStartRadius: 24,
|
||||
|
|
@ -197,25 +199,27 @@ const BottomSheet = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<BottomSheetM
|
||||
ref={sheetRef}
|
||||
index={initialSnapIndex}
|
||||
snapPoints={snapPoints}
|
||||
animateOnMount={true}
|
||||
backdropComponent={renderBackdrop}
|
||||
onAnimate={handleAnimationStart}
|
||||
onChange={handleChange}
|
||||
animationConfigs={animatedConfig}
|
||||
handleComponent={Indicator}
|
||||
style={styles.bottomSheet}
|
||||
backgroundStyle={bottomSheetBackgroundStyle}
|
||||
footerComponent={footerComponent}
|
||||
keyboardBehavior='extend'
|
||||
keyboardBlurBehavior='restore'
|
||||
onClose={close}
|
||||
>
|
||||
{renderContainerContent()}
|
||||
</BottomSheetM>
|
||||
<GestureHandlerRootView style={styles.container}>
|
||||
<BottomSheetM
|
||||
ref={sheetRef}
|
||||
index={initialSnapIndex}
|
||||
snapPoints={snapPoints}
|
||||
animateOnMount={true}
|
||||
backdropComponent={renderBackdrop}
|
||||
onAnimate={handleAnimationStart}
|
||||
onChange={handleChange}
|
||||
animationConfigs={animatedConfig}
|
||||
handleComponent={Indicator}
|
||||
style={styles.bottomSheet}
|
||||
backgroundStyle={bottomSheetBackgroundStyle}
|
||||
footerComponent={footerComponent}
|
||||
keyboardBehavior='extend'
|
||||
keyboardBlurBehavior='restore'
|
||||
onClose={close}
|
||||
>
|
||||
{renderContainerContent()}
|
||||
</BottomSheetM>
|
||||
</GestureHandlerRootView>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import CompassIcon from '@components/compass_icon';
|
|||
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
|
||||
import NavigationHeader from '@components/navigation_header';
|
||||
import {ITEM_HEIGHT} from '@components/option_item';
|
||||
import OtherMentionsBadge from '@components/other_mentions_badge';
|
||||
import RoundedHeaderContext from '@components/rounded_header_context';
|
||||
import {General, Screens} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
|
|
@ -23,7 +24,6 @@ import {preventDoubleTap} from '@utils/tap';
|
|||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
import OtherMentionsBadge from './other_mentions_badge';
|
||||
import QuickActions, {MARGIN, SEPARATOR_HEIGHT} from './quick_actions';
|
||||
|
||||
import type {HeaderRightButton} from '@components/navigation_header/header';
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
class ClearAfterModal extends NavigationComponent<Props, State> {
|
||||
private backListener: NativeEventSubscription | undefined;
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
super({...props, componentName: 'ClearAfterModal'});
|
||||
|
||||
const options: Options = {
|
||||
topBar: {
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@ const EditProfile = ({
|
|||
}
|
||||
|
||||
close();
|
||||
return;
|
||||
} catch (e) {
|
||||
resetScreen(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import {type Edge, SafeAreaView} from 'react-native-safe-area-context';
|
|||
|
||||
import {setGlobalThreadsTab} from '@actions/local/systems';
|
||||
import NavigationHeader from '@components/navigation_header';
|
||||
import OtherMentionsBadge from '@components/other_mentions_badge';
|
||||
import RoundedHeaderContext from '@components/rounded_header_context';
|
||||
import {Screens} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
|
|
@ -49,6 +51,14 @@ const GlobalThreads = ({componentId, globalThreadsTab}: Props) => {
|
|||
return {flex: 1, marginTop};
|
||||
}, [defaultHeight]);
|
||||
|
||||
const headerLeftComponent = useMemo(() => {
|
||||
if (isTablet) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (<OtherMentionsBadge channelId={Screens.GLOBAL_THREADS}/>);
|
||||
}, [isTablet]);
|
||||
|
||||
useEffect(() => {
|
||||
mounted.current = true;
|
||||
return () => {
|
||||
|
|
@ -85,6 +95,7 @@ const GlobalThreads = ({componentId, globalThreadsTab}: Props) => {
|
|||
defaultMessage: 'Threads',
|
||||
})
|
||||
}
|
||||
leftComponent={headerLeftComponent}
|
||||
/>
|
||||
<View style={contextStyle}>
|
||||
<RoundedHeaderContext/>
|
||||
|
|
|
|||
|
|
@ -9,12 +9,16 @@ import {DeviceEventEmitter, Platform} from 'react-native';
|
|||
import HWKeyboardEvent from 'react-native-hw-keyboard-event';
|
||||
import {enableFreeze, enableScreens} from 'react-native-screens';
|
||||
|
||||
import {autoUpdateTimezone} from '@actions/remote/user';
|
||||
import ServerVersion from '@components/server_version';
|
||||
import {Events, Screens} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useAppState} from '@hooks/device';
|
||||
import {getAllServers} from '@queries/app/servers';
|
||||
import {findChannels, popToRoot} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {handleDeepLink} from '@utils/deep_link';
|
||||
import {logError} from '@utils/log';
|
||||
import {alertChannelArchived, alertChannelRemove, alertTeamRemove} from '@utils/navigation';
|
||||
import {notificationError} from '@utils/notification';
|
||||
|
||||
|
|
@ -40,9 +44,23 @@ type HomeProps = LaunchProps & {
|
|||
|
||||
const Tab = createBottomTabNavigator();
|
||||
|
||||
const updateTimezoneIfNeeded = async () => {
|
||||
try {
|
||||
const servers = await getAllServers();
|
||||
for (const server of servers) {
|
||||
if (server.url && server.lastActiveAt > 0) {
|
||||
autoUpdateTimezone(server.url);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('Localize change', e);
|
||||
}
|
||||
};
|
||||
|
||||
export default function HomeScreen(props: HomeProps) {
|
||||
const theme = useTheme();
|
||||
const intl = useIntl();
|
||||
const appState = useAppState();
|
||||
|
||||
useEffect(() => {
|
||||
const listener = DeviceEventEmitter.addListener(Events.NOTIFICATION_ERROR, (value: 'Team' | 'Channel' | 'Post' | 'Connection') => {
|
||||
|
|
@ -95,6 +113,12 @@ export default function HomeScreen(props: HomeProps) {
|
|||
};
|
||||
}, [intl.locale]);
|
||||
|
||||
useEffect(() => {
|
||||
if (appState === 'active') {
|
||||
updateTimezoneIfNeeded();
|
||||
}
|
||||
}, [appState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.launchType === 'deeplink') {
|
||||
const deepLink = props.extra as DeepLinkWithData;
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentT
|
|||
|
||||
const viewableItemsMap = viewableItems.reduce((acc: Record<string, boolean>, {item, isViewable}) => {
|
||||
if (isViewable && item.type === 'post') {
|
||||
acc[`${Screens.MENTIONS}-${item.value.id}`] = true;
|
||||
acc[`${Screens.MENTIONS}-${item.value.currentPost.id}`] = true;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames, i
|
|||
|
||||
const viewableItemsMap = viewableItems.reduce((acc: Record<string, boolean>, {item, isViewable}) => {
|
||||
if (isViewable && item.type === 'post') {
|
||||
acc[`${Screens.SAVED_MESSAGES}-${item.value.id}`] = true;
|
||||
acc[`${Screens.SAVED_MESSAGES}-${item.value.currentPost.id}`] = true;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
break;
|
||||
case Screens.BOTTOM_SHEET:
|
||||
screen = withServerDatabase(require('@screens/bottom_sheet').default);
|
||||
break;
|
||||
Navigation.registerComponent(Screens.BOTTOM_SHEET, () =>
|
||||
withSafeAreaInsets(withManagedConfig(screen)),
|
||||
);
|
||||
return;
|
||||
case Screens.BROWSE_CHANNELS:
|
||||
screen = withServerDatabase(require('@screens/browse_channels').default);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ function SavedMessages({
|
|||
|
||||
const viewableItemsMap = viewableItems.reduce((acc: Record<string, boolean>, {item, isViewable}) => {
|
||||
if (isViewable && item.type === 'post') {
|
||||
acc[`${Screens.PINNED_MESSAGES}-${item.value.id}`] = true;
|
||||
acc[`${Screens.PINNED_MESSAGES}-${item.value.currentPost.id}`] = true;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ export function isErrorWithDetails(obj: unknown): obj is {details: Error} {
|
|||
return (
|
||||
typeof obj === 'object' &&
|
||||
obj !== null &&
|
||||
'details' in obj
|
||||
'details' in obj &&
|
||||
typeof obj.details !== 'undefined'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -495,11 +495,14 @@ export const hasWriteStoragePermission = async (intl: IntlShape) => {
|
|||
},
|
||||
{applicationName},
|
||||
);
|
||||
const text = intl.formatMessage({
|
||||
id: 'mobile.write_storage_permission_denied_description',
|
||||
defaultMessage:
|
||||
'Save files to your device. Open Settings to grant {applicationName} write access to files on this device.',
|
||||
});
|
||||
const text = intl.formatMessage(
|
||||
{
|
||||
id: 'mobile.write_storage_permission_denied_description',
|
||||
defaultMessage:
|
||||
'Save files to your device. Open Settings to grant {applicationName} write access to files on this device.',
|
||||
},
|
||||
{applicationName},
|
||||
);
|
||||
|
||||
Alert.alert(title, text, [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -952,7 +952,11 @@
|
|||
"settings.save": "Save",
|
||||
"share_extension.channel_error": "You are not a member of a team on the selected server. Select another server or open Mattermost to join a team.",
|
||||
"share_extension.channel_label": "Channel",
|
||||
"share_extension.channels_screen.title": "Select channel",
|
||||
"share_extension.count_limit": "You can only share {count, number} {count, plural, one {file} other {files}} on this server",
|
||||
"share_extension.error_screen.description": "There was an error when attempting to share the content to {applicationName}.",
|
||||
"share_extension.error_screen.label": "An error ocurred",
|
||||
"share_extension.error_screen.reason": "Reason: {reason}",
|
||||
"share_extension.file_limit.multiple": "Each file must be less than {size}",
|
||||
"share_extension.file_limit.single": "File must be less than {size}",
|
||||
"share_extension.max_resolution": "Image exceeds maximum dimensions of 7680 x 4320 px",
|
||||
|
|
@ -960,7 +964,7 @@
|
|||
"share_extension.multiple_label": "{count, number} attachments",
|
||||
"share_extension.server_label": "Server",
|
||||
"share_extension.servers_screen.title": "Select server",
|
||||
"share_extension.share_screen.title": "Share to Mattermost",
|
||||
"share_extension.share_screen.title": "Share to {applicationName}",
|
||||
"share_extension.upload_disabled": "File uploads are disabled for the selected server",
|
||||
"share_feedback.button.no": "No, thanks",
|
||||
"share_feedback.button.yes": "Yes",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ module.exports = {
|
|||
['@babel/plugin-proposal-decorators', {legacy: true}],
|
||||
['@babel/plugin-transform-flow-strip-types'],
|
||||
['@babel/plugin-proposal-class-properties', {loose: true}],
|
||||
['@babel/plugin-proposal-private-property-in-object', {loose: true}],
|
||||
['module-resolver', {
|
||||
root: ['.'],
|
||||
alias: {
|
||||
|
|
|
|||
3107
detox/package-lock.json
generated
3107
detox/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,21 +5,21 @@
|
|||
"author": "Mattermost, Inc.",
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "7.18.6",
|
||||
"@babel/plugin-transform-modules-commonjs": "7.21.2",
|
||||
"@babel/plugin-transform-runtime": "7.21.4",
|
||||
"@babel/preset-env": "7.21.4",
|
||||
"@babel/plugin-transform-modules-commonjs": "7.22.5",
|
||||
"@babel/plugin-transform-runtime": "7.22.5",
|
||||
"@babel/preset-env": "7.22.5",
|
||||
"@jest/test-sequencer": "29.5.0",
|
||||
"@types/jest": "29.5.1",
|
||||
"@types/jest": "29.5.2",
|
||||
"@types/tough-cookie": "4.0.2",
|
||||
"@types/uuid": "9.0.1",
|
||||
"aws-sdk": "2.1361.0",
|
||||
"axios": "1.3.6",
|
||||
"@types/uuid": "9.0.2",
|
||||
"aws-sdk": "2.1398.0",
|
||||
"axios": "1.4.0",
|
||||
"axios-cookiejar-support": "4.0.6",
|
||||
"babel-jest": "29.5.0",
|
||||
"babel-plugin-module-resolver": "5.0.0",
|
||||
"client-oauth2": "4.3.3",
|
||||
"deepmerge": "4.3.1",
|
||||
"detox": "20.7.0",
|
||||
"detox": "20.9.1",
|
||||
"form-data": "4.0.0",
|
||||
"jest": "29.5.0",
|
||||
"jest-circus": "29.5.0",
|
||||
|
|
@ -27,15 +27,15 @@
|
|||
"jest-html-reporters": "3.1.4",
|
||||
"jest-junit": "16.0.0",
|
||||
"jest-stare": "2.5.0",
|
||||
"junit-report-merger": "6.0.1",
|
||||
"junit-report-merger": "6.0.2",
|
||||
"moment-timezone": "0.5.43",
|
||||
"recursive-readdir": "2.2.3",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"shelljs": "0.8.5",
|
||||
"tough-cookie": "4.1.2",
|
||||
"tough-cookie": "4.1.3",
|
||||
"ts-jest": "29.1.0",
|
||||
"tslib": "2.5.0",
|
||||
"typescript": "5.0.4",
|
||||
"tslib": "2.5.3",
|
||||
"typescript": "5.1.3",
|
||||
"uuid": "9.0.0",
|
||||
"xml2js": "0.5.0"
|
||||
},
|
||||
|
|
|
|||
18
fastlane/.env.android.beta
Normal file
18
fastlane/.env.android.beta
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
## You invoke this with --env android.beta on the fastlane command
|
||||
APP_NAME="Mattermost Beta"
|
||||
APP_SCHEME=mattermost
|
||||
AWS_BUCKET_NAME=releases.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile-beta
|
||||
AWS_REGION=us-east-1
|
||||
BETA_BUILD=true
|
||||
BUILD_FOR_RELEASE=true
|
||||
MAIN_APP_IDENTIFIER=com.mattermost.rnbeta
|
||||
REPLACE_ASSETS=false
|
||||
SENTRY_ENABLED=true
|
||||
SENTRY_ORG=mattermost-mr
|
||||
SENTRY_PROJECT_ANDROID=mattermost-android-test
|
||||
SEPARATE_APKS=true
|
||||
SHOW_ONBOARDING=true
|
||||
SUPPLY_TRACK=alpha
|
||||
SUPPLY_PACKAGE_NAME=com.mattermost.rnbeta
|
||||
SUPPLY_VALIDATE_ONLY=false
|
||||
12
fastlane/.env.android.pr
Normal file
12
fastlane/.env.android.pr
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
## You invoke this with --env android.pr on the fastlane command
|
||||
APP_NAME="Mattermost Beta"
|
||||
APP_SCHEME=mattermost
|
||||
AWS_BUCKET_NAME=pr-builds.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile
|
||||
AWS_REGION=us-east-1
|
||||
BETA_BUILD=true
|
||||
BUILD_FOR_RELEASE=true
|
||||
BUILD_PR=true
|
||||
MAIN_APP_IDENTIFIER=com.mattermost.rnbeta
|
||||
REPLACE_ASSETS=false
|
||||
SHOW_ONBOARDING=true
|
||||
19
fastlane/.env.android.release
Normal file
19
fastlane/.env.android.release
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
## You invoke this with --env android.release on the fastlane command
|
||||
APP_NAME=Mattermost
|
||||
APP_SCHEME=mattermost
|
||||
AWS_BUCKET_NAME=releases.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile
|
||||
AWS_REGION=us-east-1
|
||||
BETA_BUILD=false
|
||||
BUILD_FOR_RELEASE=true
|
||||
MAIN_APP_IDENTIFIER=com.mattermost.rn
|
||||
REPLACE_ASSETS=true
|
||||
SENTRY_ENABLED=true
|
||||
SENTRY_ORG=mattermost-mr
|
||||
SENTRY_PROJECT_ANDROID=mattermost-mobile-android
|
||||
SEPARATE_APKS=true
|
||||
SHOW_ONBOARDING=true
|
||||
SHOW_REVIEW=true
|
||||
SUPPLY_PACKAGE_NAME=com.mattermost.rn
|
||||
SUPPLY_TRACK=beta
|
||||
SUPPLY_VALIDATE_ONLY=false
|
||||
4
fastlane/.env.default
Normal file
4
fastlane/.env.default
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
## This is loaded by default for all fastlane executions
|
||||
BABEL_ENV="production"
|
||||
NODE_ENV="production"
|
||||
NODE_OPTIONS="--max_old_space_size=12000"
|
||||
26
fastlane/.env.ios.beta
Normal file
26
fastlane/.env.ios.beta
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
## You invoke this with --env ios.beta on the fastlane command
|
||||
APP_NAME="Mattermost Beta"
|
||||
APP_SCHEME=mattermost
|
||||
AWS_BUCKET_NAME=releases.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile-beta
|
||||
AWS_REGION=us-east-1
|
||||
BETA_BUILD=true
|
||||
BUILD_FOR_RELEASE=true
|
||||
EXTENSION_APP_IDENTIFIER=com.mattermost.rnbeta.MattermostShare
|
||||
IOS_APP_GROUP=group.com.mattermost.rnbeta
|
||||
IOS_BUILD_EXPORT_METHOD=app-store
|
||||
IOS_ICLOUD_CONTAINER=iCloud.com.mattermost.rnbeta
|
||||
MAIN_APP_IDENTIFIER=com.mattermost.rnbeta
|
||||
MATCH_APP_IDENTIFIER=com.mattermost.rnbeta.NotificationService,com.mattermost.rnbeta.MattermostShare,com.mattermost.rnbeta
|
||||
MATCH_READONLY=true
|
||||
MATCH_SHALLOW_CLONE=true
|
||||
MATCH_SKIP_DOCS=true
|
||||
MATCH_TYPE=appstore
|
||||
NOTIFICATION_SERVICE_IDENTIFIER=com.mattermost.rnbeta.NotificationService
|
||||
PILOT_SKIP_WAITING_FOR_BUILD_PROCESSING=true
|
||||
REPLACE_ASSETS=false
|
||||
SENTRY_ENABLED=true
|
||||
SENTRY_ORG=mattermost-mr
|
||||
SENTRY_PROJECT_IOS=mattermost-ios-test
|
||||
SHOW_ONBOARDING=true
|
||||
SYNC_PROVISIONING_PROFILES=true
|
||||
24
fastlane/.env.ios.pr
Normal file
24
fastlane/.env.ios.pr
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
## You invoke this with --env ios.pr on the fastlane command
|
||||
APP_NAME="Mattermost Beta"
|
||||
APP_SCHEME=mattermost
|
||||
AWS_BUCKET_NAME=pr-builds.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile
|
||||
AWS_REGION=us-east-1
|
||||
BETA_BUILD=true
|
||||
BUILD_FOR_RELEASE=true
|
||||
BUILD_PR=true
|
||||
EXTENSION_APP_IDENTIFIER=com.mattermost.rnbeta.MattermostShare
|
||||
IOS_APP_GROUP=group.com.mattermost.rnbeta
|
||||
IOS_BUILD_EXPORT_METHOD=ad-hoc
|
||||
IOS_ICLOUD_CONTAINER=iCloud.com.mattermost.rnbeta
|
||||
MAIN_APP_IDENTIFIER=com.mattermost.rnbeta
|
||||
MATCH_APP_IDENTIFIER=com.mattermost.rnbeta.NotificationService,com.mattermost.rnbeta.MattermostShare,com.mattermost.rnbeta
|
||||
MATCH_READONLY=true
|
||||
MATCH_SHALLOW_CLONE=true
|
||||
MATCH_SKIP_DOCS=true
|
||||
MATCH_TYPE=adhoc
|
||||
NOTIFICATION_SERVICE_IDENTIFIER=com.mattermost.rnbeta.NotificationService
|
||||
PILOT_SKIP_WAITING_FOR_BUILD_PROCESSING=true
|
||||
REPLACE_ASSETS=false
|
||||
SHOW_ONBOARDING=true
|
||||
SYNC_PROVISIONING_PROFILES=true
|
||||
26
fastlane/.env.ios.release
Normal file
26
fastlane/.env.ios.release
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
## You invoke this with --env ios.release on the fastlane command
|
||||
APP_NAME=Mattermost
|
||||
APP_SCHEME=mattermost
|
||||
AWS_BUCKET_NAME=releases.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile
|
||||
AWS_REGION=us-east-1
|
||||
BUILD_FOR_RELEASE=true
|
||||
EXTENSION_APP_IDENTIFIER=com.mattermost.rn.MattermostShare
|
||||
IOS_APP_GROUP=group.com.mattermost
|
||||
IOS_BUILD_EXPORT_METHOD=app-store
|
||||
IOS_ICLOUD_CONTAINER=iCloud.com.mattermost.rn
|
||||
MAIN_APP_IDENTIFIER=com.mattermost.rn
|
||||
MATCH_APP_IDENTIFIER=com.mattermost.rn.NotificationService,com.mattermost.rn.MattermostShare,com.mattermost.rn
|
||||
MATCH_READONLY=true
|
||||
MATCH_SHALLOW_CLONE=true
|
||||
MATCH_SKIP_DOCS=true
|
||||
MATCH_TYPE=appstore
|
||||
NOTIFICATION_SERVICE_IDENTIFIER=com.mattermost.rn.NotificationService
|
||||
PILOT_SKIP_WAITING_FOR_BUILD_PROCESSING=true
|
||||
REPLACE_ASSETS=true
|
||||
SENTRY_ENABLED=true
|
||||
SENTRY_ORG=mattermost-mr
|
||||
SENTRY_PROJECT_IOS=mattermost-mobile-ios
|
||||
SHOW_ONBOARDING=true
|
||||
SHOW_REVIEW=true
|
||||
SYNC_PROVISIONING_PROFILES=true
|
||||
4
fastlane/.env.ios.simulator
Normal file
4
fastlane/.env.ios.simulator
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
## You invoke this with --env ios.simulator on the fastlane command
|
||||
AWS_BUCKET_NAME=releases.mattermost.com
|
||||
AWS_FOLDER_NAME=mattermost-mobile-beta
|
||||
AWS_REGION=us-east-1
|
||||
|
|
@ -14,11 +14,11 @@ before_all do
|
|||
ENV['SPACESHIP_SKIP_2FA_UPGRADE'] = '1'
|
||||
|
||||
is_build_pr = ENV['BUILD_PR'] == 'true'
|
||||
if is_build_pr && ENV['CIRCLECI'] == 'true'
|
||||
ENV['BRANCH_TO_BUILD'] = ENV['CIRCLE_BRANCH']
|
||||
if is_build_pr && ENV['CI'] == 'true'
|
||||
ENV['BRANCH_TO_BUILD'] = ENV['GITHUB_REF_NAME']
|
||||
end
|
||||
|
||||
if ENV['CIRCLECI'] != 'true'
|
||||
if ENV['CI'] != 'true'
|
||||
# Raises an error is git is not clean
|
||||
if ENV['COMMIT_CHANGES_TO_GIT'] == 'true'
|
||||
ensure_git_status_clean
|
||||
|
|
@ -46,9 +46,9 @@ before_all do
|
|||
end
|
||||
|
||||
after_all do |lane|
|
||||
if ENV['CIRCLECI'] != 'true'
|
||||
if ENV['CI'] != 'true'
|
||||
if ENV['RESET_GIT_BRANCH'] == 'true'
|
||||
branch = ENV['BRANCH_TO_BUILD'] || 'master'
|
||||
branch = ENV['BRANCH_TO_BUILD'] || 'main'
|
||||
package_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta'
|
||||
beta_dir = '../android/app/src/main/java/com/mattermost/rnbeta'
|
||||
release_dir = "../android/app/src/main/java/#{package_id.gsub '.', '/'}"
|
||||
|
|
@ -68,7 +68,7 @@ after_all do |lane|
|
|||
sh "git branch -D #{local_branch}"
|
||||
UI.success("Deleted working branch \"#{local_branch}\"")
|
||||
if lane.to_s == 'build_pr'
|
||||
sh 'git checkout master'
|
||||
sh 'git checkout main'
|
||||
## Remove the branch for the PR
|
||||
sh "git branch -D #{branch}"
|
||||
UI.success("Deleted PR branch \"#{branch}\"")
|
||||
|
|
@ -320,7 +320,7 @@ end
|
|||
|
||||
desc 'Create GitHub release'
|
||||
lane :github do
|
||||
tag = ENV['CIRCLE_TAG'] || ENV['TAG']
|
||||
tag = ENV['GITHUB_REF_NAME'] || ENV['TAG']
|
||||
|
||||
if tag
|
||||
version = android_get_version_name(gradle_file: './android/app/build.gradle')
|
||||
|
|
@ -350,8 +350,8 @@ end
|
|||
|
||||
platform :ios do
|
||||
before_all do
|
||||
if ENV['CIRCLECI'] == 'true'
|
||||
setup_circle_ci
|
||||
if ENV['CI'] == 'true'
|
||||
setup_ci
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ platform :ios do
|
|||
end
|
||||
|
||||
lane :update_identifiers do
|
||||
# Set the name for the app
|
||||
# Set the name for the app and share extension
|
||||
app_name = ENV['APP_NAME'] || 'Mattermost Beta'
|
||||
update_info_plist(
|
||||
xcodeproj: './ios/Mattermost.xcodeproj',
|
||||
|
|
@ -423,6 +423,12 @@ platform :ios do
|
|||
display_name: app_name
|
||||
)
|
||||
|
||||
update_info_plist(
|
||||
xcodeproj: './ios/Mattermost.xcodeproj',
|
||||
plist_path: 'MattermostShare/Info.plist',
|
||||
display_name: app_name
|
||||
)
|
||||
|
||||
# Set the notification service extension bundle identifier
|
||||
notification_bundle_id = ENV['NOTIFICATION_SERVICE_IDENTIFIER'] || 'com.mattermost.rnbeta.NotificationService'
|
||||
update_app_identifier(
|
||||
|
|
@ -563,20 +569,27 @@ platform :ios do
|
|||
json = JSON.parse(localization_file)
|
||||
|
||||
plist_strings = ''
|
||||
localized_strings = ''
|
||||
json.each do |key, value|
|
||||
if key.match?('mobile.ios.plist')
|
||||
unless value.nil? || value.empty?
|
||||
unless value.nil? || value.empty?
|
||||
if key.match?('mobile.ios.plist')
|
||||
plist_strings.concat("#{key.split('.').last} = \"#{value}\";\n")
|
||||
else
|
||||
value.gsub!('\\', '\\\\\\\\') # How to replace backslash with double backslash https://stackoverflow.com/a/6209532
|
||||
value.gsub!('"', '\"')
|
||||
localized_strings.concat("\"#{key}\" = \"#{value}\";\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
plist_strings.gsub!('{applicationName}', "#{app_name}")
|
||||
localized_strings.gsub!('{applicationName}', "#{app_name}")
|
||||
|
||||
language = item.split('.').first
|
||||
project_localization_path = "../ios/Mattermost/i18n/#{language}.lproj"
|
||||
FileUtils.mkdir_p project_localization_path
|
||||
File.write("#{project_localization_path}/InfoPlist.strings", plist_strings)
|
||||
File.write("#{project_localization_path}/Localizable.strings", localized_strings)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ source "https://rubygems.org"
|
|||
|
||||
gem "fastlane"
|
||||
gem "nokogiri"
|
||||
gem "dotenv"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), '.', 'Pluginfile')
|
||||
eval(File.read(plugins_path), binding) if File.exist?(plugins_path)
|
||||
|
|
|
|||
|
|
@ -8,17 +8,17 @@ GEM
|
|||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.752.0)
|
||||
aws-sdk-core (3.171.0)
|
||||
aws-partitions (1.777.0)
|
||||
aws-sdk-core (3.174.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.63.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sdk-kms (1.66.0)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.121.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sdk-s3 (1.123.1)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sigv4 (1.5.2)
|
||||
|
|
@ -36,7 +36,7 @@ GEM
|
|||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.8.1)
|
||||
emoji_regex (3.2.3)
|
||||
excon (0.99.0)
|
||||
excon (0.100.0)
|
||||
faraday (1.10.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
|
|
@ -65,8 +65,8 @@ GEM
|
|||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.2.6)
|
||||
fastlane (2.212.2)
|
||||
fastimage (2.2.7)
|
||||
fastlane (2.213.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
|
|
@ -90,7 +90,7 @@ GEM
|
|||
json (< 3.0.0)
|
||||
jwt (>= 2.1.0, < 3)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multipart-post (~> 2.0.0)
|
||||
multipart-post (>= 2.0.0, < 3.0.0)
|
||||
naturally (~> 2.2)
|
||||
optparse (~> 0.1.1)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
|
|
@ -111,7 +111,7 @@ GEM
|
|||
fastlane-plugin-find_replace_string (0.1.0)
|
||||
fastlane-plugin-versioning_android (0.1.1)
|
||||
gh_inspector (1.1.3)
|
||||
google-apis-androidpublisher_v3 (0.39.0)
|
||||
google-apis-androidpublisher_v3 (0.42.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.0)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
|
|
@ -159,19 +159,19 @@ GEM
|
|||
memoist (0.16.2)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.1)
|
||||
mini_portile2 (2.8.2)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.0.0)
|
||||
multipart-post (2.3.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
nokogiri (1.14.3)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
nokogiri (1.15.2)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
optparse (0.1.1)
|
||||
os (1.1.4)
|
||||
plist (3.7.0)
|
||||
public_suffix (5.0.1)
|
||||
racc (1.6.2)
|
||||
racc (1.7.0)
|
||||
rake (13.0.6)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
|
|
@ -222,6 +222,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
dotenv
|
||||
fastlane
|
||||
fastlane-plugin-android_change_package_identifier
|
||||
fastlane-plugin-android_change_string_app_name
|
||||
|
|
|
|||
|
|
@ -62,6 +62,29 @@
|
|||
672D98B029F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D988229F1927F004228D6 /* InfoPlist.strings */; };
|
||||
672D98B129F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D988529F1927F004228D6 /* InfoPlist.strings */; };
|
||||
672D98B229F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D988529F1927F004228D6 /* InfoPlist.strings */; };
|
||||
67AE0FC52A0556A500810C56 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67AE0FC32A0556A500810C56 /* Localizable.strings */; };
|
||||
67FEADD92A0E96DD00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADD62A0E96DD00DDF4AE /* Localizable.strings */; };
|
||||
67FEADDD2A12602A00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADDA2A12602A00DDF4AE /* Localizable.strings */; };
|
||||
67FEADE12A12603600DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADDE2A12603600DDF4AE /* Localizable.strings */; };
|
||||
67FEADE52A12603F00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADE22A12603F00DDF4AE /* Localizable.strings */; };
|
||||
67FEADE92A12604900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADE62A12604900DDF4AE /* Localizable.strings */; };
|
||||
67FEADED2A12608900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADEA2A12608900DDF4AE /* Localizable.strings */; };
|
||||
67FEADF12A12609300DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADEE2A12609300DDF4AE /* Localizable.strings */; };
|
||||
67FEADF52A1260A900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADF22A1260A900DDF4AE /* Localizable.strings */; };
|
||||
67FEADF92A1260B200DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADF62A1260B200DDF4AE /* Localizable.strings */; };
|
||||
67FEAE012A1260C200DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADFE2A1260C200DDF4AE /* Localizable.strings */; };
|
||||
67FEAE052A1260CA00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE022A1260C900DDF4AE /* Localizable.strings */; };
|
||||
67FEAE092A12611B00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE062A12611B00DDF4AE /* Localizable.strings */; };
|
||||
67FEAE0D2A12612500DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE0A2A12612500DDF4AE /* Localizable.strings */; };
|
||||
67FEAE112A12613000DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE0E2A12613000DDF4AE /* Localizable.strings */; };
|
||||
67FEAE152A12614F00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE122A12614F00DDF4AE /* Localizable.strings */; };
|
||||
67FEAE192A12615900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE162A12615900DDF4AE /* Localizable.strings */; };
|
||||
67FEAE1D2A12616500DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE1A2A12616500DDF4AE /* Localizable.strings */; };
|
||||
67FEAE212A12616F00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE1E2A12616F00DDF4AE /* Localizable.strings */; };
|
||||
67FEAE252A12618000DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE222A12618000DDF4AE /* Localizable.strings */; };
|
||||
67FEAE292A1261A000DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE262A1261A000DDF4AE /* Localizable.strings */; };
|
||||
67FEAE2A2A1261EA00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADFA2A1260B900DDF4AE /* Localizable.strings */; };
|
||||
67FEAE2C2A127C3600DDF4AE /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */; };
|
||||
6C9B1EFD6561083917AF06CF /* libPods-Mattermost.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DEEFB3ED6175724A2653247 /* libPods-Mattermost.a */; };
|
||||
7F0F4B0A24BA173900E14C60 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F0F4B0924BA173900E14C60 /* LaunchScreen.storyboard */; };
|
||||
7F151D3E221B062700FAD8F3 /* RuntimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F151D3D221B062700FAD8F3 /* RuntimeUtils.swift */; };
|
||||
|
|
@ -246,6 +269,29 @@
|
|||
672D988029F1927F004228D6 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
672D988329F1927F004228D6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
672D988629F1927F004228D6 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
67AE0FC42A0556A500810C56 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADD72A0E96DD00DDF4AE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADDB2A12602A00DDF4AE /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADDF2A12603600DDF4AE /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADE32A12603F00DDF4AE /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADE72A12604900DDF4AE /* en_AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en_AU; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADEB2A12608900DDF4AE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADEF2A12609300DDF4AE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADF32A1260A900DDF4AE /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADF72A1260B200DDF4AE /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADFB2A1260B900DDF4AE /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEADFF2A1260C200DDF4AE /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE032A1260C900DDF4AE /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE072A12611B00DDF4AE /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE0B2A12612500DDF4AE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE0F2A12613000DDF4AE /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE132A12614F00DDF4AE /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE172A12615900DDF4AE /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE1B2A12616500DDF4AE /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE1F2A12616F00DDF4AE /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-CN"; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE232A12618000DDF4AE /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE272A1261A000DDF4AE /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = "<group>"; };
|
||||
6BAF8296411D4657B5A0E8F8 /* libRNReactNativeDocViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNReactNativeDocViewer.a; sourceTree = "<group>"; };
|
||||
7F0F4B0924BA173900E14C60 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = SplashScreenResource/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
7F151D3D221B062700FAD8F3 /* RuntimeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RuntimeUtils.swift; path = Mattermost/RuntimeUtils.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -512,6 +558,7 @@
|
|||
672D984529F1927E004228D6 /* de.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADE22A12603F00DDF4AE /* Localizable.strings */,
|
||||
672D984629F1927E004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = de.lproj;
|
||||
|
|
@ -521,6 +568,7 @@
|
|||
672D984829F1927E004228D6 /* ja.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADFE2A1260C200DDF4AE /* Localizable.strings */,
|
||||
672D984929F1927E004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = ja.lproj;
|
||||
|
|
@ -530,6 +578,7 @@
|
|||
672D984B29F1927E004228D6 /* fa.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADEE2A12609300DDF4AE /* Localizable.strings */,
|
||||
672D984C29F1927E004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = fa.lproj;
|
||||
|
|
@ -539,6 +588,7 @@
|
|||
672D984E29F1927F004228D6 /* pl.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE0A2A12612500DDF4AE /* Localizable.strings */,
|
||||
672D984F29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = pl.lproj;
|
||||
|
|
@ -548,6 +598,7 @@
|
|||
672D985129F1927F004228D6 /* ar.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADDA2A12602A00DDF4AE /* Localizable.strings */,
|
||||
672D985229F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = ar.lproj;
|
||||
|
|
@ -557,6 +608,7 @@
|
|||
672D985429F1927F004228D6 /* sv.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE122A12614F00DDF4AE /* Localizable.strings */,
|
||||
672D985529F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = sv.lproj;
|
||||
|
|
@ -566,6 +618,7 @@
|
|||
672D985729F1927F004228D6 /* ru.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67AE0FC32A0556A500810C56 /* Localizable.strings */,
|
||||
672D985829F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = ru.lproj;
|
||||
|
|
@ -575,6 +628,7 @@
|
|||
672D985A29F1927F004228D6 /* ro.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE262A1261A000DDF4AE /* Localizable.strings */,
|
||||
672D985B29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = ro.lproj;
|
||||
|
|
@ -584,6 +638,7 @@
|
|||
672D985D29F1927F004228D6 /* bg.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADDE2A12603600DDF4AE /* Localizable.strings */,
|
||||
672D985E29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = bg.lproj;
|
||||
|
|
@ -593,6 +648,7 @@
|
|||
672D986029F1927F004228D6 /* tr.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE162A12615900DDF4AE /* Localizable.strings */,
|
||||
672D986129F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = tr.lproj;
|
||||
|
|
@ -602,6 +658,7 @@
|
|||
672D986329F1927F004228D6 /* zh-TW.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE222A12618000DDF4AE /* Localizable.strings */,
|
||||
672D986429F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = "zh-TW.lproj";
|
||||
|
|
@ -611,6 +668,7 @@
|
|||
672D986629F1927F004228D6 /* en.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADD62A0E96DD00DDF4AE /* Localizable.strings */,
|
||||
672D986729F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = en.lproj;
|
||||
|
|
@ -620,6 +678,7 @@
|
|||
672D986929F1927F004228D6 /* en_AU.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADE62A12604900DDF4AE /* Localizable.strings */,
|
||||
672D986A29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = en_AU.lproj;
|
||||
|
|
@ -629,6 +688,7 @@
|
|||
672D986C29F1927F004228D6 /* hu.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADF62A1260B200DDF4AE /* Localizable.strings */,
|
||||
672D986D29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = hu.lproj;
|
||||
|
|
@ -638,6 +698,7 @@
|
|||
672D986F29F1927F004228D6 /* fr.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADF22A1260A900DDF4AE /* Localizable.strings */,
|
||||
672D987029F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = fr.lproj;
|
||||
|
|
@ -647,6 +708,7 @@
|
|||
672D987229F1927F004228D6 /* ko.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE022A1260C900DDF4AE /* Localizable.strings */,
|
||||
672D987329F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = ko.lproj;
|
||||
|
|
@ -656,6 +718,7 @@
|
|||
672D987529F1927F004228D6 /* zh-CN.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE1E2A12616F00DDF4AE /* Localizable.strings */,
|
||||
672D987629F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = "zh-CN.lproj";
|
||||
|
|
@ -665,6 +728,7 @@
|
|||
672D987829F1927F004228D6 /* es.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADEA2A12608900DDF4AE /* Localizable.strings */,
|
||||
672D987929F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = es.lproj;
|
||||
|
|
@ -674,6 +738,7 @@
|
|||
672D987B29F1927F004228D6 /* it.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEADFA2A1260B900DDF4AE /* Localizable.strings */,
|
||||
672D987C29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = it.lproj;
|
||||
|
|
@ -683,6 +748,7 @@
|
|||
672D987E29F1927F004228D6 /* nl.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE062A12611B00DDF4AE /* Localizable.strings */,
|
||||
672D987F29F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = nl.lproj;
|
||||
|
|
@ -692,6 +758,7 @@
|
|||
672D988129F1927F004228D6 /* pt-BR.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE0E2A12613000DDF4AE /* Localizable.strings */,
|
||||
672D988229F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = "pt-BR.lproj";
|
||||
|
|
@ -701,6 +768,7 @@
|
|||
672D988429F1927F004228D6 /* uk.lproj */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE1A2A12616500DDF4AE /* Localizable.strings */,
|
||||
672D988529F1927F004228D6 /* InfoPlist.strings */,
|
||||
);
|
||||
name = uk.lproj;
|
||||
|
|
@ -784,6 +852,7 @@
|
|||
7F7E9F432864E6AF0064BFAF /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */,
|
||||
7F7E9F442864E6C60064BFAF /* Color.swift */,
|
||||
7F7E9F452864E6C60064BFAF /* View.swift */,
|
||||
7F93AAAD287725660047B89F /* Int64.swift */,
|
||||
|
|
@ -1197,8 +1266,17 @@
|
|||
672D98AA29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D989029F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D989A29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
67FEADF52A1260A900DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEADD92A0E96DD00DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEAE092A12611B00DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEADE52A12603F00DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD4825E2864DC5800A5B18B /* Metropolis-Regular.ttf in Resources */,
|
||||
67FEAE252A12618000DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEADF92A1260B200DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEAE1D2A12616500DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD4825F2864DC5800A5B18B /* Metropolis-SemiBold.ttf in Resources */,
|
||||
67FEAE0D2A12612500DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEADE92A12604900DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD482602864DC5800A5B18B /* OpenSans-Bold.ttf in Resources */,
|
||||
7FD482612864DC5800A5B18B /* OpenSans-BoldItalic.ttf in Resources */,
|
||||
672D988829F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
|
|
@ -1207,21 +1285,34 @@
|
|||
672D989429F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D98A029F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D989229F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
67FEAE292A1261A000DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD482632864DC5900A5B18B /* OpenSans-ExtraBoldItalic.ttf in Resources */,
|
||||
672D988E29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
7FD482642864DC5900A5B18B /* OpenSans-Italic.ttf in Resources */,
|
||||
672D989C29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D98A229F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D988C29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
67FEADF12A12609300DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEAE112A12613000DDF4AE /* Localizable.strings in Resources */,
|
||||
67AE0FC52A0556A500810C56 /* Localizable.strings in Resources */,
|
||||
67FEAE152A12614F00DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD482652864DC5900A5B18B /* OpenSans-Light.ttf in Resources */,
|
||||
672D98AE29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
67FEAE052A1260CA00DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEAE2A2A1261EA00DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEAE012A1260C200DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD482662864DC5900A5B18B /* OpenSans-LightItalic.ttf in Resources */,
|
||||
7FD482672864DC5900A5B18B /* OpenSans-Regular.ttf in Resources */,
|
||||
672D98B229F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
672D989829F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
67FEADE12A12603600DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEAE192A12615900DDF4AE /* Localizable.strings in Resources */,
|
||||
67FEADDD2A12602A00DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD482682864DC5900A5B18B /* OpenSans-SemiBold.ttf in Resources */,
|
||||
672D98AC29F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
67FEAE212A12616F00DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD482692864DC5900A5B18B /* OpenSans-SemiBoldItalic.ttf in Resources */,
|
||||
67FEADED2A12608900DDF4AE /* Localizable.strings in Resources */,
|
||||
7FD4825C2864DC4200A5B18B /* compass-icons.ttf in Resources */,
|
||||
7FD482292864D69700A5B18B /* Assets.xcassets in Resources */,
|
||||
672D98A829F1927F004228D6 /* InfoPlist.strings in Resources */,
|
||||
|
|
@ -1413,6 +1504,7 @@
|
|||
7F1EBFCE286F2AE200824AF1 /* MultipleAttachmentView.swift in Sources */,
|
||||
7F7E9F792864E8160064BFAF /* SearchBarView.swift in Sources */,
|
||||
7FB50D222856E1AB0035ACB5 /* ShareUIView.swift in Sources */,
|
||||
67FEAE2C2A127C3600DDF4AE /* NumberFormatter.swift in Sources */,
|
||||
7F93AAA828761FA10047B89F /* NoMembershipView.swift in Sources */,
|
||||
7F7E9F772864E8160064BFAF /* LinkPreview.swift in Sources */,
|
||||
7F7E9F782864E8160064BFAF /* OptionView.swift in Sources */,
|
||||
|
|
@ -1634,6 +1726,182 @@
|
|||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67AE0FC32A0556A500810C56 /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67AE0FC42A0556A500810C56 /* ru */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADD62A0E96DD00DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADD72A0E96DD00DDF4AE /* en */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADDA2A12602A00DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADDB2A12602A00DDF4AE /* ar */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADDE2A12603600DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADDF2A12603600DDF4AE /* bg */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADE22A12603F00DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADE32A12603F00DDF4AE /* de */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADE62A12604900DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADE72A12604900DDF4AE /* en_AU */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADEA2A12608900DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADEB2A12608900DDF4AE /* es */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADEE2A12609300DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADEF2A12609300DDF4AE /* fa */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADF22A1260A900DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADF32A1260A900DDF4AE /* fr */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADF62A1260B200DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADF72A1260B200DDF4AE /* hu */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADFA2A1260B900DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADFB2A1260B900DDF4AE /* it */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEADFE2A1260C200DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEADFF2A1260C200DDF4AE /* ja */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE022A1260C900DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE032A1260C900DDF4AE /* ko */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE062A12611B00DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE072A12611B00DDF4AE /* nl */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE0A2A12612500DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE0B2A12612500DDF4AE /* pl */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE0E2A12613000DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE0F2A12613000DDF4AE /* pt-BR */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE122A12614F00DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE132A12614F00DDF4AE /* sv */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE162A12615900DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE172A12615900DDF4AE /* tr */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE1A2A12616500DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE1B2A12616500DDF4AE /* uk */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE1E2A12616F00DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE1F2A12616F00DDF4AE /* zh-CN */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE222A12618000DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE232A12618000DDF4AE /* zh-TW */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67FEAE262A1261A000DDF4AE /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
67FEAE272A1261A000DDF4AE /* ro */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7FC5698A28563FDB000B0905 /* MainInterface.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
|
|
@ -1655,7 +1923,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 473;
|
||||
CURRENT_PROJECT_VERSION = 476;
|
||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||
ENABLE_BITCODE = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
|
|
@ -1699,7 +1967,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 473;
|
||||
CURRENT_PROJECT_VERSION = 476;
|
||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||
ENABLE_BITCODE = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
|
|
@ -1842,14 +2110,12 @@
|
|||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 473;
|
||||
CURRENT_PROJECT_VERSION = 476;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = MattermostShare/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = MattermostShare;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
|
@ -1893,14 +2159,12 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 473;
|
||||
CURRENT_PROJECT_VERSION = 476;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = MattermostShare/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = MattermostShare;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
|
@ -2066,7 +2330,7 @@
|
|||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
|
||||
requirement = {
|
||||
branch = 8.4.0;
|
||||
branch = 8.7.3;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
"package": "Sentry",
|
||||
"repositoryURL": "https://github.com/getsentry/sentry-cocoa.git",
|
||||
"state": {
|
||||
"branch": "8.4.0",
|
||||
"revision": "92a6472efc750a4e18bdee21c204942ab0bc4dcd",
|
||||
"branch": "8.7.3",
|
||||
"revision": "9cf7d2e514af1600cc2b3c5592e2848c6c5a76d6",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.5.0</string>
|
||||
<string>2.5.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>473</string>
|
||||
<string>476</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
|
|
|||
0
ios/Mattermost/i18n/ar.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ar.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/bg.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/bg.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/de.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/de.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/en.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/en.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/en_AU.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/en_AU.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/es.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/es.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/fa.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/fa.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/fr.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/fr.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/hu.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/hu.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/it.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/it.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ja.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ja.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ko.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ko.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/nl.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/nl.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/pl.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/pl.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/pt-BR.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/pt-BR.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ro.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ro.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ru.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/ru.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/sv.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/sv.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/tr.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/tr.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/uk.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/uk.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/zh-CN.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/zh-CN.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/zh-TW.lproj/Localizable.strings
Normal file
0
ios/Mattermost/i18n/zh-TW.lproj/Localizable.strings
Normal file
|
|
@ -22,10 +22,7 @@ extension Int64 {
|
|||
let i = floor(log(size) / log(k))
|
||||
|
||||
// Format number with thousands separator and everything below 1 giga with no decimal places.
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.maximumFractionDigits = i < 3 ? 0 : 1
|
||||
numberFormatter.numberStyle = .decimal
|
||||
|
||||
let numberFormatter = i < 3 ? NumberFormatter.noFractionDigitsDecimalFormatter : NumberFormatter.oneFractionDigitDecimalFormatter
|
||||
let numberString = numberFormatter.string(from: NSNumber(value: size / pow(k, i))) ?? "Unknown"
|
||||
let suffix = suffixes[Int(i)]
|
||||
return "\(numberString) \(suffix)"
|
||||
|
|
|
|||
25
ios/MattermostShare/Extensions/NumberFormatter.swift
Normal file
25
ios/MattermostShare/Extensions/NumberFormatter.swift
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// NumberFormatter.swift
|
||||
// MattermostShare
|
||||
//
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension NumberFormatter {
|
||||
static let noFractionDigitsDecimalFormatter: NumberFormatter = {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.maximumFractionDigits = 0
|
||||
numberFormatter.numberStyle = .decimal
|
||||
return numberFormatter
|
||||
}()
|
||||
|
||||
static let oneFractionDigitDecimalFormatter: NumberFormatter = {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.maximumFractionDigits = 1
|
||||
numberFormatter.numberStyle = .decimal
|
||||
return numberFormatter
|
||||
}()
|
||||
}
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.5.0</string>
|
||||
<string>2.5.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>473</string>
|
||||
<string>476</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>OpenSans-Bold.ttf</string>
|
||||
|
|
@ -77,5 +77,7 @@
|
|||
<string>$(SENTRY_DSN_IOS)</string>
|
||||
<key>SENTRY_ENABLED</key>
|
||||
<string>$(SENTRY_ENABLED)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -15,16 +15,30 @@ struct AttachmentsView: View {
|
|||
var error: String? {
|
||||
if let server = shareViewModel.server {
|
||||
if server.uploadsDisabled {
|
||||
return "File uploads are disabled for the selected server"
|
||||
return NSLocalizedString("share_extension.upload_disabled",
|
||||
value: "File uploads are disabled for the selected server",
|
||||
comment: ""
|
||||
)
|
||||
}
|
||||
let sizeError = attachments.contains { $0.sizeError(server: server)}
|
||||
let resolutionError = attachments.contains { $0.resolutionError(server: server)}
|
||||
if sizeError && attachments.count == 1 {
|
||||
return "File must be less than \(server.maxFileSize.formattedFileSize)"
|
||||
return NSLocalizedString("share_extension.file_limit.single",
|
||||
value: "File must be less than {size}",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(of: "{size}", with: server.maxFileSize.formattedFileSize)
|
||||
} else if sizeError {
|
||||
return "Each file must be less than \(server.maxFileSize.formattedFileSize)"
|
||||
return NSLocalizedString("share_extension.file_limit.multiple",
|
||||
value: "Each file must be less than {size}",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(of: "{size}", with: server.maxFileSize.formattedFileSize)
|
||||
} else if resolutionError {
|
||||
return "Image exceeds maximum dimensions of 7680 x 4320 px"
|
||||
return NSLocalizedString("share_extension.max_resolution",
|
||||
value: "Image exceeds maximum dimensions of 7680 x 4320 px",
|
||||
comment: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,10 +65,16 @@ struct MultipleAttachmentView: View {
|
|||
}
|
||||
|
||||
if (attachments.count > 1) {
|
||||
Text("\(attachments.count) attachments")
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
||||
.font(Font.custom("OpenSans", size: 12))
|
||||
.padding(.leading, 20)
|
||||
Text(
|
||||
NSLocalizedString("share_extension.multiple_label",
|
||||
value: "{count, number} attachments",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(of: "{count, number}", with: "\(attachments.count)")
|
||||
)
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
||||
.font(Font.custom("OpenSans", size: 12))
|
||||
.padding(.leading, 20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,12 @@ struct ChannelListView: View {
|
|||
SearchBarView()
|
||||
if shareViewModel.search.isEmpty {
|
||||
HStack {
|
||||
Text("RECENT")
|
||||
.font(Font.custom("OpenSans-SemiBold", size: 12))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
||||
Text(
|
||||
NSLocalizedString("mobile.channel_list.recent", value: "Recent", comment: "")
|
||||
.uppercased()
|
||||
)
|
||||
.font(Font.custom("OpenSans-SemiBold", size: 12))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
||||
Spacer()
|
||||
}
|
||||
.padding(.top, 20)
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@ struct SearchBarView: View {
|
|||
HStack {
|
||||
TextField("", text: $shareViewModel.search)
|
||||
.placeholder(when: shareViewModel.search.isEmpty) {
|
||||
Text("Find channels...")
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
||||
Text(
|
||||
NSLocalizedString("channel_list.find_channels", value: "Find channels...", comment: "")
|
||||
)
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.64))
|
||||
}
|
||||
.padding(.leading, 40)
|
||||
.padding(.trailing, 30)
|
||||
|
|
@ -59,9 +61,11 @@ struct SearchBarView: View {
|
|||
|
||||
if isEditing {
|
||||
Button(action: dismissKeyboard) {
|
||||
Text("Cancel")
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
.font(Font.custom("OpenSans", size: 14))
|
||||
Text(
|
||||
NSLocalizedString("mobile.post.cancel", value: "Cancel", comment: "")
|
||||
)
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
.font(Font.custom("OpenSans", size: 14))
|
||||
}
|
||||
.transition(.move(edge: .trailing))
|
||||
.animation(.linear(duration: 0.15))
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ struct ContentView: View {
|
|||
VStack (spacing: 0) {
|
||||
if shareViewModel.allServers.count > 1 {
|
||||
OptionView(
|
||||
navigationTitle: "Select server",
|
||||
label: "Server",
|
||||
navigationTitle: NSLocalizedString("share_extension.servers_screen.title", value: "Select server", comment: ""),
|
||||
label: NSLocalizedString("share_extension.server_label", value: "Server", comment: ""),
|
||||
value: shareViewModel.server!.displayName
|
||||
) {
|
||||
ServerListView()
|
||||
|
|
@ -51,8 +51,8 @@ struct ContentView: View {
|
|||
}
|
||||
if hasChannels {
|
||||
OptionView(
|
||||
navigationTitle: "Select channel",
|
||||
label: "Channel",
|
||||
navigationTitle: NSLocalizedString("share_extension.channels_screen.title", value: "Select channel", comment: ""),
|
||||
label: NSLocalizedString("share_extension.channel_label", value: "Channel", comment: ""),
|
||||
value: "\(shareViewModel.channel!.displayName) \(shareViewModel.channel!.formattedTeamName)"
|
||||
) {
|
||||
ChannelListView()
|
||||
|
|
@ -66,10 +66,16 @@ struct ContentView: View {
|
|||
.padding(.bottom, 10)
|
||||
|
||||
if hasChannels {
|
||||
FloatingTextField(placeholderText: "Enter a message (optional)", text: $message)
|
||||
FloatingTextField(
|
||||
placeholderText: NSLocalizedString("share_extension.message", value: "Enter a message (optional)", comment: ""),
|
||||
text: $message
|
||||
)
|
||||
} else {
|
||||
ErrorLabelView(
|
||||
error: "You are not a member of a team on the selected server. Select another server or open Mattermost to join a team."
|
||||
error: NSLocalizedString("share_extension.channel_error",
|
||||
value: "You are not a member of a team on the selected server. Select another server or open Mattermost to join a team.",
|
||||
comment: ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@ struct FloatingTextField: View {
|
|||
}
|
||||
|
||||
func formatLength(_ value: Int64) -> String {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .decimal
|
||||
formatter.maximumFractionDigits = 0
|
||||
let formatter = NumberFormatter.noFractionDigitsDecimalFormatter
|
||||
let number = NSNumber(value: value)
|
||||
return formatter.string(from: number)!
|
||||
}
|
||||
|
|
@ -64,7 +62,12 @@ struct FloatingTextField: View {
|
|||
VStack (alignment: .leading) {
|
||||
if (error) {
|
||||
ErrorLabelView(
|
||||
error: "Message must be less than \(formatLength(shareViewModel.server!.maxMessageLength)) characters"
|
||||
error: NSLocalizedString("mobile.message_length.message",
|
||||
value: "Your current message is too long. Current character count: {count}/{max}",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(of: "{count}", with: formatLength(Int64(text.count)))
|
||||
.replacingOccurrences(of: "{max}", with: formatLength(shareViewModel.server!.maxMessageLength))
|
||||
)
|
||||
}
|
||||
ZStack(alignment: .topLeading) {
|
||||
|
|
|
|||
|
|
@ -22,21 +22,40 @@ struct ErrorSharingView: View {
|
|||
NotificationCenter.default.post(name: Notification.Name("submit"), object: nil, userInfo: nil)
|
||||
}
|
||||
} else {
|
||||
Text("An error ocurred")
|
||||
.font(Font.custom("Metropolis-SemiBold", size: 20))
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
Text("There was an error when attempting to share the content to Mattermost.")
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
Text(
|
||||
NSLocalizedString("share_extension.error_screen.label", value: "An error ocurred", comment: "")
|
||||
)
|
||||
.font(Font.custom("Metropolis-SemiBold", size: 20))
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
Text(
|
||||
NSLocalizedString("share_extension.error_screen.description",
|
||||
value: "There was an error when attempting to share the content to {applicationName}.",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(
|
||||
of: "{applicationName}",
|
||||
with: Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "Mattermost Beta"
|
||||
)
|
||||
)
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.72))
|
||||
Text("Reason: \(error)")
|
||||
.font(Font.custom("OpenSans", size: 12))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.60))
|
||||
Text(
|
||||
NSLocalizedString("share_extension.error_screen.reason",
|
||||
value: "Reason: {reason}",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(of: "{reason}", with: error)
|
||||
)
|
||||
.font(Font.custom("OpenSans", size: 12))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.60))
|
||||
Button {
|
||||
retrying = true
|
||||
} label: {
|
||||
Text("Try again")
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.buttonColor)
|
||||
Text(
|
||||
NSLocalizedString("mobile.post.failed_retry", value: "Try again", comment: "")
|
||||
)
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.buttonColor)
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.tint(Color.theme.buttonBg)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,22 @@ import SwiftUI
|
|||
struct NoMembershipView: View {
|
||||
var body: some View {
|
||||
VStack (spacing: 8) {
|
||||
Text("Not a member of any team yet")
|
||||
.font(Font.custom("Metropolis-SemiBold", size: 20))
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
Text("To share content, you'll need to be a member of a team on a Mattermost server.")
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.72))
|
||||
Text(
|
||||
NSLocalizedString("extension.no_memberships.title",
|
||||
value: "Not a member of any team yet",
|
||||
comment: ""
|
||||
)
|
||||
)
|
||||
.font(Font.custom("Metropolis-SemiBold", size: 20))
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
Text(
|
||||
NSLocalizedString("extension.no_memberships.description",
|
||||
value: "To share content, you'll need to be a member of a team on a Mattermost server.",
|
||||
comment: ""
|
||||
)
|
||||
)
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.72))
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,22 @@ import SwiftUI
|
|||
struct NoServersView: View {
|
||||
var body: some View {
|
||||
VStack (spacing: 8) {
|
||||
Text("Not connected to any servers")
|
||||
.font(Font.custom("Metropolis-SemiBold", size: 20))
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
Text("To share content, you'll need to be logged in to a Mattermost server.")
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.72))
|
||||
Text(
|
||||
NSLocalizedString("extension.no_servers.title",
|
||||
value: "Not connected to any servers",
|
||||
comment: ""
|
||||
)
|
||||
)
|
||||
.font(Font.custom("Metropolis-SemiBold", size: 20))
|
||||
.foregroundColor(Color.theme.centerChannelColor)
|
||||
Text(
|
||||
NSLocalizedString("extension.no_servers.description",
|
||||
value: "To share content, you'll need to be logged in to a Mattermost server.",
|
||||
comment: ""
|
||||
)
|
||||
)
|
||||
.font(Font.custom("OpenSans", size: 16))
|
||||
.foregroundColor(Color.theme.centerChannelColor.opacity(0.72))
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,17 @@ struct InitialView: View {
|
|||
}
|
||||
}
|
||||
.accentColor(.white)
|
||||
.navigationBarTitle("Share to Mattermost", displayMode: .inline)
|
||||
.navigationBarTitle(
|
||||
NSLocalizedString("share_extension.share_screen.title",
|
||||
value: "Share to {applicationName}",
|
||||
comment: ""
|
||||
)
|
||||
.replacingOccurrences(
|
||||
of: "{applicationName}",
|
||||
with: Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "Mattermost Beta"
|
||||
),
|
||||
displayMode: .inline
|
||||
)
|
||||
.navigationBarItems(
|
||||
leading: CancelButton(attachments: attachments),
|
||||
trailing: PostButton(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue