From b568c6b49a109c7fdbfc83f5cf62f70048716fbb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:14:35 +0000 Subject: [PATCH 01/10] AUTOMATION: Changelog update --- CHANGELOG.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f1fe30066..372242a51bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,92 @@ +# UNRELEASED CHANGELOG +## Common changes for all artifacts +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-client +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-offline +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-state +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-ui-common +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-ui-components +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-compose +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + +## stream-chat-android-markdown-transformer +### 🐞 Fixed + +### ⬆️ Improved + +### ✅ Added + +### ⚠️ Changed + +### ❌ Removed + # November 21th, 2024 - 6.6.0 ## Common changes for all artifacts ### ⬆️ Improved From e838cc2373b95b84d6e96cdfdb378326319c1cbc Mon Sep 17 00:00:00 2001 From: Alexey Alter-Pesotskiy Date: Fri, 22 Nov 2024 14:04:49 +0000 Subject: [PATCH 02/10] [CI] Implement E2E tests parallelization and nightly runs (#5480) * [CI] Implement E2E tests parallelization and nightly runs * Resolve comments --- .github/actions/allure-launch/action.yml | 18 +++ .github/actions/setup-java/action.yml | 10 ++ .../{ruby-cache => setup-ruby}/action.yml | 4 +- .github/workflows/apk-s3-distribute.yml | 6 +- .github/workflows/app-distribute.yml | 12 +- .github/workflows/build-and-test.yml | 30 +---- .github/workflows/check-entities.yml | 6 +- .github/workflows/clean-detekt-baseline.yaml | 6 +- .github/workflows/e2e-build.yml | 30 +++++ .github/workflows/e2e-test-cron.yml | 86 +++++++++++++ .github/workflows/e2e-test.yml | 78 ++++++++++++ .github/workflows/e2e-tests.yml | 114 ------------------ .github/workflows/localazy-download.yml | 6 +- .github/workflows/localazy-upload.yml | 6 +- .github/workflows/pr-checks.yml | 26 +--- .github/workflows/publish-beta.yml | 6 +- .github/workflows/publish-hotfix.yml | 6 +- .github/workflows/publish-snapshot.yml | 8 +- .github/workflows/publish.yml | 9 +- .github/workflows/release-docs.yaml | 6 +- .github/workflows/release-post.yaml | 16 +-- .github/workflows/release-start.yaml | 8 +- .github/workflows/snapshot-record.yaml | 8 +- .github/workflows/snapshot-tests.yaml | 8 +- .gitignore | 2 + fastlane/Allurefile | 4 +- fastlane/Fastfile | 92 +++++++++----- 27 files changed, 323 insertions(+), 288 deletions(-) create mode 100644 .github/actions/allure-launch/action.yml create mode 100644 .github/actions/setup-java/action.yml rename .github/actions/{ruby-cache => setup-ruby}/action.yml (67%) create mode 100644 .github/workflows/e2e-build.yml create mode 100644 .github/workflows/e2e-test-cron.yml create mode 100644 .github/workflows/e2e-test.yml delete mode 100644 .github/workflows/e2e-tests.yml diff --git a/.github/actions/allure-launch/action.yml b/.github/actions/allure-launch/action.yml new file mode 100644 index 00000000000..d683ebe848b --- /dev/null +++ b/.github/actions/allure-launch/action.yml @@ -0,0 +1,18 @@ +name: 'Allure Launch' +description: 'Launches Allure TestOps job' +inputs: + allure-token: + description: 'ALLURE_TOKEN' + required: true + cron: + description: 'Is this a cron check?' + default: 'false' +runs: + using: "composite" + steps: + - name: Launch Allure TestOps + run: bundle exec fastlane allure_launch cron:${{ inputs.cron }} + shell: bash + env: + ALLURE_TOKEN: ${{ inputs.allure-token }} + GITHUB_EVENT: ${{ toJson(github.event) }} diff --git a/.github/actions/setup-java/action.yml b/.github/actions/setup-java/action.yml new file mode 100644 index 00000000000..7874bd350da --- /dev/null +++ b/.github/actions/setup-java/action.yml @@ -0,0 +1,10 @@ +name: 'Setup Java' +description: 'Setup Java' +runs: + using: "composite" + steps: + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: adopt + java-version: 17 diff --git a/.github/actions/ruby-cache/action.yml b/.github/actions/setup-ruby/action.yml similarity index 67% rename from .github/actions/ruby-cache/action.yml rename to .github/actions/setup-ruby/action.yml index 25b8a9a761f..8a56bec008d 100644 --- a/.github/actions/ruby-cache/action.yml +++ b/.github/actions/setup-ruby/action.yml @@ -1,5 +1,5 @@ -name: 'Ruby Cache' -description: 'Cache Ruby dependencies' +name: 'Setup Ruby' +description: 'Setup Ruby and cache bundler' runs: using: "composite" steps: diff --git a/.github/workflows/apk-s3-distribute.yml b/.github/workflows/apk-s3-distribute.yml index 02c59f5ab2d..b83b43873e0 100644 --- a/.github/workflows/apk-s3-distribute.yml +++ b/.github/workflows/apk-s3-distribute.yml @@ -12,11 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Prepare environment run: | git fetch --unshallow diff --git a/.github/workflows/app-distribute.yml b/.github/workflows/app-distribute.yml index 8deadc253cc..e9b51723c8f 100644 --- a/.github/workflows/app-distribute.yml +++ b/.github/workflows/app-distribute.yml @@ -12,11 +12,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Prepare environment run: | git fetch --unshallow @@ -44,11 +40,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Prepare environment run: | git fetch --unshallow diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 304a1d3872a..176a29478e6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,11 +17,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Build run: ./gradlew assembleDebug :stream-chat-android-ui-uitests:assembleDebugAndroidTest @@ -31,11 +27,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Build run: ./gradlew assembleRelease @@ -45,11 +37,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Unit tests run: ./scripts/ci-unit-tests.sh - name: Upload testDebugUnitTest results @@ -65,11 +53,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: build demo debug run: ./gradlew stream-chat-android-ui-components-sample:assembleDemoDebug - name: Upload artifact to Emerge @@ -85,11 +69,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: build debug run: ./gradlew stream-chat-android-compose-sample:assembleDebug - name: Upload artifact to Emerge diff --git a/.github/workflows/check-entities.yml b/.github/workflows/check-entities.yml index aa50c8fadc0..2c8c14738b9 100644 --- a/.github/workflows/check-entities.yml +++ b/.github/workflows/check-entities.yml @@ -11,11 +11,7 @@ jobs: uses: actions/checkout@v3.1.0 with: fetch-depth: 0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Find touched DB Entities id: touchedEntities continue-on-error: true diff --git a/.github/workflows/clean-detekt-baseline.yaml b/.github/workflows/clean-detekt-baseline.yaml index b446daab54f..620b0ba5af7 100644 --- a/.github/workflows/clean-detekt-baseline.yaml +++ b/.github/workflows/clean-detekt-baseline.yaml @@ -15,11 +15,7 @@ jobs: with: ref: develop token: ${{ secrets.STREAM_PUBLIC_BOT_TOKEN }} - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: tibdex/github-app-token@v1.7.0 id: generate-token with: diff --git a/.github/workflows/e2e-build.yml b/.github/workflows/e2e-build.yml new file mode 100644 index 00000000000..f4bdc657d01 --- /dev/null +++ b/.github/workflows/e2e-build.yml @@ -0,0 +1,30 @@ +name: E2E Build + +on: + workflow_call: + inputs: + app: + required: true + type: string + +jobs: + build: + name: ${{ inputs.app }} apks + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4.2.2 + - uses: ./.github/actions/setup-java + - uses: ./.github/actions/enable-kvm + - uses: ./.github/actions/setup-ruby + - uses: ./.github/actions/gradle-cache + with: + key-prefix: gradle-test + - name: Build apks + run: bundle exec fastlane build_e2e_test + - name: Upload apks + uses: actions/upload-artifact@v4.4.3 + with: + name: apks + path: | + stream-chat-android-${{ inputs.app }}-sample/build/outputs/apk/e2e/debug/*.apk + stream-chat-android-${{ inputs.app }}-sample/build/outputs/apk/androidTest/e2e/debug/*.apk diff --git a/.github/workflows/e2e-test-cron.yml b/.github/workflows/e2e-test-cron.yml new file mode 100644 index 00000000000..76be02538e6 --- /dev/null +++ b/.github/workflows/e2e-test-cron.yml @@ -0,0 +1,86 @@ +name: E2E Tests Nightly + +on: + schedule: + # Runs "At 01:00 every night except weekends" + - cron: '0 1 * * 1-5' + + workflow_dispatch: + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + build-compose-apks: + name: Build + uses: ./.github/workflows/e2e-build.yml + with: + app: compose + + run-compose-tests-nightly: + name: Test compose + runs-on: ubuntu-24.04 + needs: build-compose-apks + strategy: + matrix: + include: + - android_api_level: 35 + - android_api_level: 34 + - android_api_level: 33 + - android_api_level: 32 + - android_api_level: 31 + - android_api_level: 29 + - android_api_level: 28 + fail-fast: false + env: + ANDROID_API_LEVEL: ${{ matrix.android_api_level }} + steps: + - name: Connect Bot + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.BOT_SSH_PRIVATE_KEY }} + - uses: actions/checkout@v4.2.2 + - uses: actions/download-artifact@v4.1.8 + continue-on-error: true + with: + name: apks + - uses: ./.github/actions/setup-java + - uses: ./.github/actions/enable-kvm + - uses: ./.github/actions/setup-ruby + - uses: ./.github/actions/allure-launch + with: + allure-token: ${{ secrets.ALLURE_TOKEN }} + cron: true + - name: Run tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ env.ANDROID_API_LEVEL }} + disable-animations: true + profile: pixel + arch : x86_64 + emulator-options: ${{ vars.EMULATOR_OPTIONS }} + script: bundle exec fastlane run_e2e_test + - name: Allure TestOps Upload + run: bundle exec fastlane allure_upload + if: success() || failure() + env: + ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} + LAUNCH_ID: ${{ env.LAUNCH_ID }} + - name: Allure TestOps Launch Removal + run: bundle exec fastlane allure_launch_removal + if: cancelled() + env: + ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} + LAUNCH_ID: ${{ env.LAUNCH_ID }} + - name: Upload test results + uses: actions/upload-artifact@v4.4.3 + if: failure() + with: + name: test_report + path: | + ./**/build/reports/androidTests/* + fastlane/stream-chat-test-mock-server/logs/* diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml new file mode 100644 index 00000000000..07ff7722dc3 --- /dev/null +++ b/.github/workflows/e2e-test.yml @@ -0,0 +1,78 @@ +name: E2E Tests + +on: + pull_request: + + workflow_dispatch: + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PR_NUM: ${{ github.event.pull_request.number }} + +jobs: + build-compose-apks: + name: Build + uses: ./.github/workflows/e2e-build.yml + with: + app: compose + + run-compose-tests: + name: Test compose + runs-on: ubuntu-24.04 + needs: build-compose-apks + strategy: + matrix: + include: + - batch: 0 + - batch: 1 + env: + ANDROID_API_LEVEL: 35 + steps: + - name: Connect Bot + uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.BOT_SSH_PRIVATE_KEY }} + - uses: actions/checkout@v4.2.2 + - uses: actions/download-artifact@v4.1.8 + continue-on-error: true + with: + name: apks + - uses: ./.github/actions/setup-java + - uses: ./.github/actions/enable-kvm + - uses: ./.github/actions/setup-ruby + - uses: ./.github/actions/allure-launch + with: + allure-token: ${{ secrets.ALLURE_TOKEN }} + - name: Run tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ env.ANDROID_API_LEVEL }} + disable-animations: true + profile: pixel + arch : x86_64 + emulator-options: ${{ vars.EMULATOR_OPTIONS }} + script: bundle exec fastlane run_e2e_test batch:${{ matrix.batch }} batch_count:${{ strategy.job-total }} + - name: Allure TestOps Upload + if: success() || failure() + run: bundle exec fastlane allure_upload + env: + ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} + LAUNCH_ID: ${{ env.LAUNCH_ID }} + - name: Allure TestOps Launch Removal + if: cancelled() + run: bundle exec fastlane allure_launch_removal + env: + ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} + LAUNCH_ID: ${{ env.LAUNCH_ID }} + - name: Upload test results + uses: actions/upload-artifact@v4.4.3 + if: failure() + with: + name: test_report + path: | + ./**/build/reports/androidTests/* + fastlane/stream-chat-test-mock-server/logs/* diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml deleted file mode 100644 index adf5098558c..00000000000 --- a/.github/workflows/e2e-tests.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: E2E Tests - -on: - pull_request: - - workflow_dispatch: - -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_PR_NUM: ${{ github.event.pull_request.number }} - -jobs: - build-apks: - name: Build - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4.2.2 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: adopt - java-version: 17 - - uses: ./.github/actions/enable-kvm - - uses: ./.github/actions/ruby-cache - - uses: ./.github/actions/gradle-cache - with: - key-prefix: gradle-test - - name: Build apks - run: bundle exec fastlane build_e2e_test - - name: Upload apks - uses: actions/upload-artifact@v4.4.0 - with: - name: apks - path: | - stream-chat-android-compose-sample/build/outputs/apk/e2e/debug/*.apk - stream-chat-android-compose-sample/build/outputs/apk/androidTest/e2e/debug/*.apk - - allure_testops_launch: - name: Launch Allure TestOps - runs-on: ubuntu-24.04 - needs: build-apks - outputs: - launch_id: ${{ steps.get_launch_id.outputs.launch_id }} - steps: - - uses: actions/checkout@v4.1.1 - - uses: ./.github/actions/ruby-cache - - name: Launch Allure TestOps - run: bundle exec fastlane allure_launch - env: - ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} - GITHUB_EVENT: ${{ toJson(github.event) }} - - id: get_launch_id - run: echo "launch_id=${{env.LAUNCH_ID}}" >> $GITHUB_OUTPUT - if: env.LAUNCH_ID != '' - - run-tests: - name: Test - runs-on: ubuntu-24.04 - needs: - - build-apks - - allure_testops_launch - env: - LAUNCH_ID: ${{ needs.allure_testops_launch.outputs.launch_id }} - steps: - - name: Connect Bot - uses: webfactory/ssh-agent@v0.9.0 - with: - ssh-private-key: ${{ secrets.BOT_SSH_PRIVATE_KEY }} - - uses: actions/checkout@v4.2.2 - - uses: actions/download-artifact@v4.1.8 - continue-on-error: true - with: - name: apks - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: adopt - java-version: 17 - - uses: ./.github/actions/enable-kvm - - uses: ./.github/actions/ruby-cache - - uses: ./.github/actions/gradle-cache - with: - key-prefix: gradle-test - - name: Run tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 34 - disable-animations: true - profile: pixel - arch : x86_64 - emulator-options: -no-snapshot-save -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -camera-back none -camera-front none - script: bundle exec fastlane run_e2e_test - - name: Allure TestOps Upload - if: env.LAUNCH_ID != '' && (success() || failure()) - run: bundle exec fastlane allure_upload launch_id:$LAUNCH_ID - env: - ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} - - name: Allure TestOps Launch Removal - if: env.LAUNCH_ID != '' && cancelled() - run: bundle exec fastlane allure_launch_removal launch_id:$LAUNCH_ID - env: - ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} - - name: Upload test results - uses: actions/upload-artifact@v3.1.0 - if: failure() - with: - name: test_report - path: | - ./**/build/reports/androidTests/* - fastlane/stream-chat-test-mock-server/logs/* diff --git a/.github/workflows/localazy-download.yml b/.github/workflows/localazy-download.yml index e2189b65821..cc6aa7f4c9a 100644 --- a/.github/workflows/localazy-download.yml +++ b/.github/workflows/localazy-download.yml @@ -13,11 +13,7 @@ jobs: - uses: actions/checkout@v3.1.0 with: ref: develop - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: tibdex/github-app-token@v1.7.0 id: generate-token with: diff --git a/.github/workflows/localazy-upload.yml b/.github/workflows/localazy-upload.yml index 97df812fecc..a83c6793602 100644 --- a/.github/workflows/localazy-upload.yml +++ b/.github/workflows/localazy-upload.yml @@ -15,11 +15,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v1 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: localazy/upload@v1 with: read_key: ${{ secrets.LOCALAZY_READ_KEY }} diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 391fa206ed1..580ebf4e5e4 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -19,11 +19,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: ./.github/actions/gradle-cache with: key-prefix: gradle-lint @@ -39,11 +35,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: ./.github/actions/gradle-cache with: key-prefix: gradle-APICheck @@ -56,11 +48,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: ./.github/actions/gradle-cache with: key-prefix: gradle-build @@ -73,11 +61,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: ./.github/actions/gradle-cache with: key-prefix: gradle-test @@ -95,5 +79,5 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4.2.2 - - uses: ./.github/actions/ruby-cache + - uses: ./.github/actions/setup-ruby - run: bundle exec fastlane rubocop diff --git a/.github/workflows/publish-beta.yml b/.github/workflows/publish-beta.yml index 6e34578bbf8..31fa96f1806 100644 --- a/.github/workflows/publish-beta.yml +++ b/.github/workflows/publish-beta.yml @@ -12,11 +12,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Release build # assembleRelease for all modules, excluding non-library modules: samples, docs run: ./gradlew assembleRelease -x :stream-chat-android-ui-components-sample:assembleRelease -x :stream-chat-android-compose-sample:assembleRelease -x :stream-chat-android-docs:assembleRelease diff --git a/.github/workflows/publish-hotfix.yml b/.github/workflows/publish-hotfix.yml index 43865ce665c..79d4c10ae84 100644 --- a/.github/workflows/publish-hotfix.yml +++ b/.github/workflows/publish-hotfix.yml @@ -12,11 +12,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Release build # assembleRelease for all modules, excluding non-library modules: samples, docs run: ./gradlew assembleRelease -x :stream-chat-android-ui-components-sample:assembleRelease -x :stream-chat-android-compose-sample:assembleRelease -x :stream-chat-android-docs:assembleRelease diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 3dbac60ac52..a1a79c12c8b 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -5,7 +5,7 @@ on: branches: - develop workflow_dispatch: - + jobs: publish: name: Snapshot build and publish @@ -13,11 +13,7 @@ jobs: steps: - name: Check out code uses: actions/checkout@v3.1.0 - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Release build # assembleRelease for all modules, excluding non-library modules: samples, docs run: ./gradlew assembleRelease -x :stream-chat-android-ui-components-sample:assembleRelease -x :stream-chat-android-compose-sample:assembleRelease -x :stream-chat-android-docs:assembleRelease diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 986b51482c5..0ddd486e43d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,10 +3,11 @@ name: Publish on: workflow_run: workflows: ["ReleaseStart"] - workflow_dispatch: types: - completed + workflow_dispatch: + jobs: publish: name: Release build and publish @@ -18,11 +19,7 @@ jobs: with: ref: release persist-credentials: false - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Release build # assembleRelease for all modules, excluding non-library modules: samples, docs run: ./gradlew assembleRelease -x :stream-chat-android-ui-components-sample:assembleRelease -x :stream-chat-android-compose-sample:assembleRelease -x :stream-chat-android-docs:assembleRelease diff --git a/.github/workflows/release-docs.yaml b/.github/workflows/release-docs.yaml index 37281384021..0baf5f7e87d 100644 --- a/.github/workflows/release-docs.yaml +++ b/.github/workflows/release-docs.yaml @@ -14,11 +14,7 @@ jobs: uses: actions/checkout@v3.1.0 with: ref: main - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Generate Dokka HTML docs run: ./gradlew dokkaHtmlMultimodule - name: Deploy to GitHub pages diff --git a/.github/workflows/release-post.yaml b/.github/workflows/release-post.yaml index 172ad42a21f..77f2094ec82 100644 --- a/.github/workflows/release-post.yaml +++ b/.github/workflows/release-post.yaml @@ -11,19 +11,15 @@ jobs: name: Sync main with release runs-on: ubuntu-22.04 if: ${{ github.event.workflow_run.conclusion == 'success' }} - steps: + steps: - name: Check out code uses: actions/checkout@v3.1.0 with: ref: main persist-credentials: false - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Sync main - run: | + run: | git fetch origin release git merge --ff-only origin/release - name: Push changes @@ -42,11 +38,7 @@ jobs: ref: main fetch-depth: 0 persist-credentials: false - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Update changelog run: ./gradlew changelog-add-model-section - name: Commit CHANGELOG.md and merge to develop diff --git a/.github/workflows/release-start.yaml b/.github/workflows/release-start.yaml index 8c363aee0d6..34f032a2c4a 100644 --- a/.github/workflows/release-start.yaml +++ b/.github/workflows/release-start.yaml @@ -3,7 +3,7 @@ name: ReleaseStart on: workflow_dispatch: inputs: - force_bump_minor_version: + force_bump_minor_version: type: boolean skip_version_bump: type: boolean @@ -19,11 +19,7 @@ jobs: with: ref: develop persist-credentials: false - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - name: Minor version bump if: "${{ github.event.inputs.force_bump_minor_version == 'true' && github.event.inputs.skip_version_bump != 'true' }}" run: ./gradlew minor-bump diff --git a/.github/workflows/snapshot-record.yaml b/.github/workflows/snapshot-record.yaml index 32053da2fd8..5d3f2aa24ea 100644 --- a/.github/workflows/snapshot-record.yaml +++ b/.github/workflows/snapshot-record.yaml @@ -11,11 +11,7 @@ jobs: uses: actions/checkout@v3.1.0 with: ref: develop - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: ./.github/actions/gradle-cache with: key-prefix: gradle-test @@ -26,7 +22,7 @@ jobs: disable-animations: true profile: pixel arch : x86_64 - emulator-options: -no-snapshot-save -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -camera-back none -camera-front none + emulator-options: ${{ vars.EMULATOR_OPTIONS }} script: ./gradlew stream-chat-android-ui-uitests:executeScreenshotTests -Precord -Pandroid.testInstrumentationRunnerArguments.filter=io.getstream.chat.android.uitests.util.SnapshotTestFilter - name: Upload screnshots uses: actions/upload-artifact@v3.1.0 diff --git a/.github/workflows/snapshot-tests.yaml b/.github/workflows/snapshot-tests.yaml index a5157f57a73..baf1f4bd079 100644 --- a/.github/workflows/snapshot-tests.yaml +++ b/.github/workflows/snapshot-tests.yaml @@ -15,11 +15,7 @@ jobs: uses: actions/checkout@v3.1.0 with: ref: develop - - name: Set up JDK 17 - uses: actions/setup-java@v3.6.0 - with: - distribution: adopt - java-version: 17 + - uses: ./.github/actions/setup-java - uses: ./.github/actions/gradle-cache with: key-prefix: gradle-test @@ -30,7 +26,7 @@ jobs: disable-animations: true profile: pixel arch : x86_64 - emulator-options: -no-snapshot-save -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -camera-back none -camera-front none + emulator-options: ${{ vars.EMULATOR_OPTIONS }} script: ./gradlew stream-chat-android-ui-uitests:executeScreenshotTests -Pandroid.testInstrumentationRunnerArguments.filter=io.getstream.chat.android.uitests.util.SnapshotTestFilter - name: Upload screnshot results if: always() diff --git a/.gitignore b/.gitignore index 50d420ca7f8..ad21726cf67 100644 --- a/.gitignore +++ b/.gitignore @@ -114,5 +114,7 @@ fastlane/screenshots fastlane/test_output fastlane/allurectl fastlane/recordings +fastlane/test-parser.jar +fastlane/AllTests.txt allure-results stream-chat-test-mock-server diff --git a/fastlane/Allurefile b/fastlane/Allurefile index 574e4ea1eac..a9b973e206e 100755 --- a/fastlane/Allurefile +++ b/fastlane/Allurefile @@ -9,8 +9,9 @@ allure_results_path = 'allure-results' desc 'Upload test results to Allure TestOps' lane :allure_upload do |options| remove_duplicated_allure_results + options[:launch_id] ||= ENV.fetch('LAUNCH_ID', nil) allure_args = "-e #{allure_url} --project-id #{allure_project_id} --launch-id #{options[:launch_id]}" - sh("./allurectl launch reopen #{options[:launch_id]} || true") # to prevent allure from uploading results to a closed launch + sh("./allurectl launch reopen #{options[:launch_id]} -e #{allure_url} || true") # to prevent allure from uploading results to a closed launch sh("env BRANCH_NAME='#{current_branch}' ./allurectl upload #{allure_args} #{allure_results_path} || true") UI.success("Check out test results in Allure TestOps: #{allure_url}/launch/#{options[:launch_id]} 🎉") end @@ -30,6 +31,7 @@ end desc 'Remove launch on Allure TestOps' lane :allure_launch_removal do |options| + options[:launch_id] ||= ENV.fetch('LAUNCH_ID', nil) allure_api(url: allure_api_url, path: "launch/#{options[:launch_id]}", http_method: 'DELETE') end diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 75eba3b21f8..cb24f018640 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -7,9 +7,6 @@ import 'Allurefile' github_repo = ENV['GITHUB_REPOSITORY'] || 'GetStream/stream-chat-android' test_flavor = 'stream-chat-android-compose-sample' -androidx_test_orchestrator_version = '1.5.1' -androidx_test_services_version = '1.5.0' -allure_ctl_version = '2.15.1' mock_server_driver_port = 4567 is_localhost = !is_ci @force_check = false @@ -39,7 +36,7 @@ end lane :build_and_run_e2e_test do |options| build_e2e_test - run_e2e_test + run_e2e_test(batch: options[:batch], batch_count: options[:batch_count]) end lane :build_e2e_test do @@ -48,7 +45,7 @@ lane :build_e2e_test do gradle(tasks: [":#{test_flavor}:assembleE2eDebugAndroidTest", ":#{test_flavor}:assembleE2eDebug"]) end -lane :run_e2e_test do +lane :run_e2e_test do |options| next unless is_check_required(sources: sources_matrix[:e2e], force_check: @force_check) allure_results_path = 'allure-results' @@ -59,11 +56,11 @@ lane :run_e2e_test do start_mock_server install_test_services - Dir.chdir('..') do - stream_apk_path = is_ci ? '.' : "#{test_flavor}/build/outputs/apk" - sh("adb install -r '#{stream_apk_path}/e2e/debug/stream-chat-android-compose-sample-e2e-debug.apk'") - sh("adb install -r '#{stream_apk_path}/androidTest/e2e/debug/stream-chat-android-compose-sample-e2e-debug-androidTest.apk'") - end + stream_apk_folder_path = is_ci ? '..' : "../#{test_flavor}/build/outputs/apk" + stream_app_path = "#{stream_apk_folder_path}/e2e/debug/stream-chat-android-compose-sample-e2e-debug.apk" + stream_test_path = "#{stream_apk_folder_path}/androidTest/e2e/debug/stream-chat-android-compose-sample-e2e-debug-androidTest.apk" + sh("adb install -r #{stream_app_path}") + sh("adb install -r #{stream_test_path}") app_package_name = 'io.getstream.chat.android.compose.sample.e2etest.debug' test_package_name = "#{app_package_name}.test" @@ -71,40 +68,42 @@ lane :run_e2e_test do orchestrator_package_name = 'androidx.test.orchestrator/.AndroidTestOrchestrator' androidx_test_services_path = sh('adb shell pm path androidx.test.services').strip + run_tests_in_batches = batch_tests( + batch: options[:batch], + batch_count: options[:batch_count], + test_apk_path: stream_test_path + ) + result = sh( - "adb shell 'CLASSPATH=#{androidx_test_services_path}' app_process / " \ - 'androidx.test.services.shellexecutor.ShellMain am instrument -w -e clearPackageData true ' \ - "-e targetInstrumentation #{test_package_name}/#{runner_package_name} #{orchestrator_package_name}" + "adb shell 'CLASSPATH=#{androidx_test_services_path}' " \ + 'app_process / androidx.test.services.shellexecutor.ShellMain am instrument -w -e clearPackageData true ' \ + "-e targetInstrumentation #{test_package_name}/#{runner_package_name} #{run_tests_in_batches} #{orchestrator_package_name}" ) - sh("adb exec-out sh -c 'cd #{adb_test_results_path} && tar cf - #{allure_results_path}' | tar xvf - -C .") + sh("adb exec-out sh -c 'cd #{adb_test_results_path} && tar cf - #{allure_results_path}' | tar xvf - -C .") if is_ci stop_mock_server UI.user_error!('Tests have failed!') if result.include?('Failures') end -private_lane :install_test_services do - orchestrator_apk_path = "apks/orchestrator.apk" - test_services_apk_path = "apks/test-services.apk" - allure_ctl_path = "allurectl" - allure_ctl_arch = RbConfig::CONFIG['host_os'].include?('darwin') ? 'darwin_amd64' : 'linux_amd64' - maven_repo = 'https://dl.google.com/dl/android/maven2/androidx/test' - - if [orchestrator_apk_path, test_services_apk_path, allure_ctl_path].any? { |f| !File.exist?(f) } - FileUtils.mkdir_p('apks') - sh("wget -O #{orchestrator_apk_path} '#{maven_repo}" \ - "/orchestrator/#{androidx_test_orchestrator_version}/orchestrator-#{androidx_test_orchestrator_version}.apk' 2>/dev/null") - sh("wget -O #{test_services_apk_path} '#{maven_repo}" \ - "/services/test-services/#{androidx_test_services_version}/test-services-#{androidx_test_services_version}.apk' 2>/dev/null") - sh("wget -O #{allure_ctl_path} " \ - "'https://github.com/allure-framework/allurectl/releases/download/#{allure_ctl_version}/allurectl_#{allure_ctl_arch}' 2>/dev/null") - sh('chmod +x allurectl') +private_lane :batch_tests do |options| + if options[:batch] && options[:batch_count] + install(tool: :test_parser) + sh("java -jar test-parser.jar #{options[:test_apk_path]} ./") + test_names = File.read('AllTests.txt').split + current_batch = test_names.each_slice((test_names.size.to_f / options[:batch_count].to_i).ceil).to_a[options[:batch].to_i] + "-e class #{current_batch.join(',')}" + else + '' end +end +private_lane :install_test_services do + FileUtils.mkdir_p('apks') device_api_level = sh('adb shell getprop ro.build.version.sdk').strip.to_i - force_queryable_option = device_api_level >= 30 ? '--force-queryable' : '' - sh("adb install #{force_queryable_option} -r #{orchestrator_apk_path}") - sh("adb install #{force_queryable_option} -r #{test_services_apk_path}") + install(tool: :test_orchestrator, api_level: device_api_level) + install(tool: :test_services, api_level: device_api_level) + install(tool: :allurectl, chmod: true) if is_ci end desc 'Run fastlane linting' @@ -120,3 +119,30 @@ private_lane :sources_matrix do ruby: ['fastlane', 'Gemfile', 'Gemfile.lock'] } end + +private_lane :install do |options| + case options[:tool] + when :test_orchestrator + v = '1.5.1' + output = 'apks/orchestrator.apk' + url = "https://dl.google.com/dl/android/maven2/androidx/test//orchestrator/#{v}/orchestrator-#{v}.apk" + when :test_services + v = '1.5.0' + output = 'apks/test-services.apk' + url = "https://dl.google.com/dl/android/maven2/androidx/test/services/test-services/#{v}/test-services-#{v}.apk" + when :test_parser + v = '2.2.1' + output = 'test-parser.jar' + url = "https://linkedin.jfrog.io/artifactory/open-source/com/linkedin/dextestparser/parser/#{v}/parser-#{v}-all.jar" + when :allurectl + v = '2.15.1' + output = 'allurectl' + arch = RbConfig::CONFIG['host_os'].include?('darwin') ? 'darwin_amd64' : 'linux_386' + url = "https://github.com/allure-framework/allurectl/releases/download/#{v}/allurectl_#{arch}" + else + UI.user_error!('Provide a correct tool name.') + end + sh("wget -O #{output} '#{url}' 2>/dev/null") unless File.exist?(output) + sh("adb install #{options[:api_level] >= 30 ? '--force-queryable' : ''} -r #{output}") if options[:api_level] + sh("chmod +x #{output}") if options[:chmod] +end From 0a15c2e3137c0e0c23d7feb276c3997d27d46e55 Mon Sep 17 00:00:00 2001 From: Alexey Alter-Pesotskiy Date: Tue, 26 Nov 2024 09:11:47 +0000 Subject: [PATCH 03/10] [CI] Make snapshot tests great again (#5486) --- .github/workflows/e2e-build.yml | 1 + .github/workflows/e2e-test-cron.yml | 1 + .github/workflows/e2e-test.yml | 3 +- .github/workflows/snapshot-record.yaml | 39 -------------- .github/workflows/snapshot-test.yaml | 54 +++++++++++++++++++ .github/workflows/snapshot-tests.yaml | 36 ------------- .../io/getstream/chat/android/Dependencies.kt | 2 +- fastlane/Fastfile | 16 +++++- 8 files changed, 74 insertions(+), 78 deletions(-) delete mode 100644 .github/workflows/snapshot-record.yaml create mode 100644 .github/workflows/snapshot-test.yaml delete mode 100644 .github/workflows/snapshot-tests.yaml diff --git a/.github/workflows/e2e-build.yml b/.github/workflows/e2e-build.yml index f4bdc657d01..235b92113f3 100644 --- a/.github/workflows/e2e-build.yml +++ b/.github/workflows/e2e-build.yml @@ -21,6 +21,7 @@ jobs: key-prefix: gradle-test - name: Build apks run: bundle exec fastlane build_e2e_test + timeout-minutes: 30 - name: Upload apks uses: actions/upload-artifact@v4.4.3 with: diff --git a/.github/workflows/e2e-test-cron.yml b/.github/workflows/e2e-test-cron.yml index 76be02538e6..852bd909b79 100644 --- a/.github/workflows/e2e-test-cron.yml +++ b/.github/workflows/e2e-test-cron.yml @@ -57,6 +57,7 @@ jobs: cron: true - name: Run tests uses: reactivecircus/android-emulator-runner@v2 + timeout-minutes: 120 with: api-level: ${{ env.ANDROID_API_LEVEL }} disable-animations: true diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 07ff7722dc3..9b508514c1b 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -30,7 +30,7 @@ jobs: - batch: 0 - batch: 1 env: - ANDROID_API_LEVEL: 35 + ANDROID_API_LEVEL: 34 steps: - name: Connect Bot uses: webfactory/ssh-agent@v0.9.0 @@ -49,6 +49,7 @@ jobs: allure-token: ${{ secrets.ALLURE_TOKEN }} - name: Run tests uses: reactivecircus/android-emulator-runner@v2 + timeout-minutes: 45 with: api-level: ${{ env.ANDROID_API_LEVEL }} disable-animations: true diff --git a/.github/workflows/snapshot-record.yaml b/.github/workflows/snapshot-record.yaml deleted file mode 100644 index 5d3f2aa24ea..00000000000 --- a/.github/workflows/snapshot-record.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: Snapshot-Record - -on: workflow_dispatch - -jobs: - record_snapshots: - name: Record snapshots - runs-on: macos-latest - steps: - - name: Check out code - uses: actions/checkout@v3.1.0 - with: - ref: develop - - uses: ./.github/actions/setup-java - - uses: ./.github/actions/gradle-cache - with: - key-prefix: gradle-test - - name: Snapshot tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 26 - disable-animations: true - profile: pixel - arch : x86_64 - emulator-options: ${{ vars.EMULATOR_OPTIONS }} - script: ./gradlew stream-chat-android-ui-uitests:executeScreenshotTests -Precord -Pandroid.testInstrumentationRunnerArguments.filter=io.getstream.chat.android.uitests.util.SnapshotTestFilter - - name: Upload screnshots - uses: actions/upload-artifact@v3.1.0 - with: - name: screenshots - path: ${{ github.workspace }}/stream-chat-android-ui-uitests/screenshots/ - - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - commit-message: "Update screenshots" - title: "Update screenshots" - delete-branch: true - reviewers: GetStream/android-developers-ui - branch: update-screenshots diff --git a/.github/workflows/snapshot-test.yaml b/.github/workflows/snapshot-test.yaml new file mode 100644 index 00000000000..ae712b88caa --- /dev/null +++ b/.github/workflows/snapshot-test.yaml @@ -0,0 +1,54 @@ +name: Snapshot Tests + +on: + # pull_request: # FIXME: https://github.com/pedrovgs/Shot/issues/326 + + workflow_dispatch: + inputs: + record: + description: 'Should Snapshots be recorded on CI?' + type: boolean + required: false + default: false + +jobs: + run_snapshot_tests: + name: Run + runs-on: ubuntu-24.04 + steps: + - name: Check out code + uses: actions/checkout@v4.2.2 + - uses: ./.github/actions/setup-java + - uses: ./.github/actions/setup-ruby + - uses: ./.github/actions/gradle-cache + with: + key-prefix: gradle-test + + - name: Snapshot tests + uses: reactivecircus/android-emulator-runner@v2 + timeout-minutes: 60 + with: + api-level: 27 + disable-animations: true + profile: pixel + arch : x86_64 + emulator-options: ${{ vars.EMULATOR_OPTIONS }} + script: bundle exec fastlane run_snapshot_test record:${{ github.event.inputs.record }} + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4.4.3 + continue-on-error: true + with: + name: report + path: ./**/build/reports/* + + - name: Create Pull Request + if: ${{ github.event.inputs.record == 'true' }} + uses: peter-evans/create-pull-request@v4 + with: + commit-message: "Update screenshots" + title: "Update screenshots" + delete-branch: true + reviewers: GetStream/android-developers-ui + branch: update-screenshots diff --git a/.github/workflows/snapshot-tests.yaml b/.github/workflows/snapshot-tests.yaml deleted file mode 100644 index baf1f4bd079..00000000000 --- a/.github/workflows/snapshot-tests.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Snapshot-Test - -on: - workflow_dispatch: - schedule: - # Every midnight - - cron: '0 0 * * *' - -jobs: - run_snapshot_tests: - name: Verify snapshots - runs-on: macos-latest - steps: - - name: Check out code - uses: actions/checkout@v3.1.0 - with: - ref: develop - - uses: ./.github/actions/setup-java - - uses: ./.github/actions/gradle-cache - with: - key-prefix: gradle-test - - name: Snapshot tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 26 - disable-animations: true - profile: pixel - arch : x86_64 - emulator-options: ${{ vars.EMULATOR_OPTIONS }} - script: ./gradlew stream-chat-android-ui-uitests:executeScreenshotTests -Pandroid.testInstrumentationRunnerArguments.filter=io.getstream.chat.android.uitests.util.SnapshotTestFilter - - name: Upload screnshot results - if: always() - uses: actions/upload-artifact@v3.1.0 - with: - name: screenshots_reports - path: ${{ github.workspace }}/stream-chat-android-ui-uitests/build/reports/* diff --git a/buildSrc/src/main/kotlin/io/getstream/chat/android/Dependencies.kt b/buildSrc/src/main/kotlin/io/getstream/chat/android/Dependencies.kt index 2b9c099c2f8..0cb34a89d13 100644 --- a/buildSrc/src/main/kotlin/io/getstream/chat/android/Dependencies.kt +++ b/buildSrc/src/main/kotlin/io/getstream/chat/android/Dependencies.kt @@ -76,7 +76,7 @@ object Versions { internal const val REORDERABLE = "2.4.0" internal const val ROOM = "2.6.1" internal const val SHIMMER = "0.5.0" - internal const val SHOT = "5.14.1" + internal const val SHOT = "6.1.0" internal const val SPOTLESS = "6.20.0" internal const val STREAM_LOG = "1.3.1" internal const val STREAM_PUSH = "1.1.9" diff --git a/fastlane/Fastfile b/fastlane/Fastfile index cb24f018640..7a99578df1f 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -34,6 +34,19 @@ lane :stop_mock_server do Net::HTTP.get_response(URI("http://localhost:#{mock_server_driver_port}/stop")) rescue nil end +lane :run_snapshot_test do |options| + next unless is_check_required(sources: sources_matrix[:ui], force_check: @force_check) + + cmd = [ + './gradlew', + 'stream-chat-android-ui-uitests:executeScreenshotTests', + '-Pandroid.testInstrumentationRunnerArguments.filter=io.getstream.chat.android.uitests.util.SnapshotTestFilter', + '-Dorg.gradle.jvmargs="--add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.nio.channels=ALL-UNNAMED --add-exports java.base/sun.nio.ch=ALL-UNNAMED"' + ] + cmd << '-Precord' unless options[:record].to_s.empty? + Dir.chdir('..') { sh(cmd.join(' ')) } +end + lane :build_and_run_e2e_test do |options| build_e2e_test run_e2e_test(batch: options[:batch], batch_count: options[:batch_count]) @@ -115,7 +128,8 @@ end private_lane :sources_matrix do { - e2e: ['buildSrc', 'stream-chat-android', '.github/workflows/e2e-tests'], + ui: ['stream-chat-android-ui', '.github/workflows/snapshot-test'], + e2e: ['buildSrc', 'stream-chat-android', '.github/workflows/e2e-test'], ruby: ['fastlane', 'Gemfile', 'Gemfile.lock'] } end From 403c09617e4d996b4ce3a71856135481d93e653d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 09:35:31 +0000 Subject: [PATCH 04/10] Bump sinatra from 4.0.0 to 4.1.0 (#5482) --- Gemfile.lock | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5223ce95a2a..b9092ab280c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -164,6 +164,7 @@ GEM json (2.8.1) jwt (2.9.3) base64 + logger (1.6.1) mini_magick (4.13.2) mini_mime (1.1.5) multi_json (1.15.0) @@ -186,8 +187,9 @@ GEM nio4r (~> 2.0) racc (1.8.1) rack (3.1.8) - rack-protection (4.0.0) + rack-protection (4.1.0) base64 (>= 0.1.0) + logger (>= 1.6.0) rack (>= 3.0.0, < 4) rack-session (2.0.0) rack (>= 3.0.0) @@ -232,10 +234,11 @@ GEM simctl (1.6.10) CFPropertyList naturally - sinatra (4.0.0) + sinatra (4.1.0) + logger (>= 1.6.0) mustermann (~> 3.0) rack (>= 3.0.0, < 4) - rack-protection (= 4.0.0) + rack-protection (= 4.1.0) rack-session (>= 2.0.0, < 3) tilt (~> 2.0) sysrandom (1.0.5) From 750f97e01e7ad61c93b4523fef0a70c8113a3d31 Mon Sep 17 00:00:00 2001 From: Petar Velikov Date: Tue, 26 Nov 2024 10:51:14 +0100 Subject: [PATCH 05/10] [AND-145] Fix pinned message list initial loading (#5483) * [AND-145] Use correct 'BeforeDate' argument for initial loading of pinned messages. * [AND-145] Extract common initial state. * [AND-145] Update CHANGELOG.md. --------- Co-authored-by: PetarVelikov --- CHANGELOG.md | 1 + .../pinned/PinnedMessageListController.kt | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 372242a51bc..462e384ad91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ ## stream-chat-android-ui-common ### 🐞 Fixed +- Fix wrong timestamp used for the initial loading of pinned messages in `PinnedMessageListController`. [#5483](https://github.com/GetStream/stream-chat-android/pull/5483) ### ⬆️ Improved diff --git a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/pinned/PinnedMessageListController.kt b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/pinned/PinnedMessageListController.kt index 3de8aa44bee..622b849e57b 100644 --- a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/pinned/PinnedMessageListController.kt +++ b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/pinned/PinnedMessageListController.kt @@ -54,19 +54,12 @@ public class PinnedMessageListController( private companion object { private const val QUERY_LIMIT = 30 - - private val INITIAL_STATE = PinnedMessageListState( - results = emptyList(), - isLoading = true, - canLoadMore = true, - nextDate = Date(), - ) } /** * Exposes the current pinned messages list state. */ - private val _state: MutableStateFlow = MutableStateFlow(INITIAL_STATE) + private val _state: MutableStateFlow = MutableStateFlow(initialState()) public val state: StateFlow get() = _state @@ -85,6 +78,8 @@ public class PinnedMessageListController( */ public fun load() { scope.launch { + // Ensure the state is updated with the current date(timestamp) for initial loading + _state.value = initialState() loadPinnedMessages() } } @@ -130,6 +125,7 @@ public class PinnedMessageListController( ) } } + is Result.Failure -> { logger.d { "Loading pinned messages failed: ${result.value.message}" } _state.update { current -> @@ -147,11 +143,20 @@ public class PinnedMessageListController( logger.d { "No more messages to load" } false } + currentState.isLoading -> { logger.d { "Already loading" } false } + else -> true } } + + private fun initialState() = PinnedMessageListState( + results = emptyList(), + isLoading = true, + canLoadMore = true, + nextDate = Date(), + ) } From 9c5da81ccee2e8d45ae4c75342e345e2745ca9e5 Mon Sep 17 00:00:00 2001 From: Petar Velikov Date: Wed, 27 Nov 2024 16:51:21 +0100 Subject: [PATCH 06/10] Load thread data in MessageListController if initially opened for a thread (#5489) * Load thread data in MessageListController first when opening for a thread. * FIx detekt findings. * Add MessageListController thread improvements to changelog. --------- Co-authored-by: PetarVelikov --- CHANGELOG.md | 1 + .../compose/sample/ui/ChannelsActivity.kt | 18 ++++-- .../messages/list/MessageListController.kt | 56 +++++++++---------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 462e384ad91..d3523a3fa40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ - Fix wrong timestamp used for the initial loading of pinned messages in `PinnedMessageListController`. [#5483](https://github.com/GetStream/stream-chat-android/pull/5483) ### ⬆️ Improved +- Improve performance of opening a thread or message in a thread via `MessageListController`. [#5489](https://github.com/GetStream/stream-chat-android/pull/5489) ### ✅ Added diff --git a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt index fbdc17cf2c6..d01f93a2519 100644 --- a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt +++ b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt @@ -70,6 +70,7 @@ import io.getstream.chat.android.compose.viewmodel.threads.ThreadListViewModel import io.getstream.chat.android.compose.viewmodel.threads.ThreadsViewModelFactory import io.getstream.chat.android.models.Channel import io.getstream.chat.android.models.Message +import io.getstream.chat.android.models.Thread import io.getstream.chat.android.models.User import io.getstream.chat.android.models.querysort.QuerySortByField import io.getstream.chat.android.state.extensions.globalState @@ -162,12 +163,7 @@ class ChannelsActivity : BaseConnectedActivity() { modifier = Modifier .fillMaxSize() .background(ChatTheme.colors.appBackground), - onThreadClick = { thread -> - val lastMessageInThread = thread.latestReplies.lastOrNull() - if (lastMessageInThread != null) { - openMessages(lastMessageInThread) - } - }, + onThreadClick = ::openThread, ) } @@ -317,6 +313,16 @@ class ChannelsActivity : BaseConnectedActivity() { ) } + private fun openThread(thread: Thread) { + startActivity( + MessagesActivity.createIntent( + context = this, + channelId = thread.parentMessage.cid, + parentMessageId = thread.parentMessageId, + ), + ) + } + private fun openUserLogin() { finish() startActivity(UserLoginActivity.createIntent(this)) diff --git a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt index 74192532fc8..37c159086fc 100644 --- a/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt +++ b/stream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/messages/list/MessageListController.kt @@ -146,8 +146,8 @@ import io.getstream.chat.android.ui.common.state.messages.Flag as FlagMessage * @param clipboardHandler [ClipboardHandler] used to copy messages. * @param threadLoadOrderOlderToNewer Determines the order in which the thread messages are loaded. * @param messageId The message id to which we want to scroll to when opening the message list. - * @param parentMessageId The ID of the parent [Message] if the message we want to scroll to is in a thread. If the - * message we want to scroll to is not in a thread, you can pass in a null value. + * @param parentMessageId The ID of the parent message for which we want to initially load the thread. (Must be supplied + * if we want to scroll to a message inside a thread). * @param messageLimit The limit of messages being fetched with each page od data. * @param chatClient The client used to communicate with the API. * @param clientState The current state of the SDK. @@ -418,13 +418,20 @@ public class MessageListController( } /** - * We start observing messages and if the message list screen was started after searching for a message, it will - * load the message if it is not in the list and scroll to it. + * Starts observing the message list state. + * If the controller was started for a the purpose of showing a thread (parentMessageId != null), it will load the + * thread data initially. + * If the controller was started with a messageId, the given message will be highlighted(focused). */ init { logger.i { " cid: $cid, messageId: $messageId, messageLimit: $messageLimit" } - observeMessagesListState() - processMessageId() + scope.launch { + if (parentMessageId != null) { + enterThreadSequential(parentMessageId) + } + observeMessagesListState() + initialFocusMessage() + } } /** @@ -593,30 +600,23 @@ public class MessageListController( disableUnreadLabelButton() } - private fun processMessageId() { - messageId - ?.takeUnless { it.isBlank() } - ?.let { messageId -> - logger.d { "[processMessageId] messageId: $messageId, parentMessageId: $parentMessageId" } - scope.launch { - if (parentMessageId != null) { - enterThreadSequential(parentMessageId) + private fun initialFocusMessage() { + messageId ?: return // No initial focus if no message id is provided + scope.launch { + listState + .onCompletion { + logger.v { "[initialFocusMessage] mode: ${_mode.value}" } + when { + _mode.value is MessageMode.Normal -> focusChannelMessage(messageId) + _mode.value is MessageMode.MessageThread && parentMessageId != null -> + focusThreadMessage( + threadMessageId = messageId, + parentMessageId = parentMessageId, + ) } - listState - .onCompletion { - logger.v { "[processMessageId] mode: ${_mode.value}" } - when { - _mode.value is MessageMode.Normal -> focusChannelMessage(messageId) - _mode.value is MessageMode.MessageThread && parentMessageId != null -> - focusThreadMessage( - threadMessageId = messageId, - parentMessageId = parentMessageId, - ) - } - } - .first { it.messageItems.isNotEmpty() } } - } + .first { it.messageItems.isNotEmpty() } + } } private fun List.focusUnreadMessage(lastReadMessageId: String) { From 7b4956a4fe4893cbf82c66d9337aac4646d9f4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jc=20Mi=C3=B1arro?= Date: Wed, 27 Nov 2024 16:59:11 +0100 Subject: [PATCH 07/10] Feature/poll styles (#5479) * Create PollViewStyle class * Create transformer lambda to transform PollViewStyle * Add styles for poll title and subtitle * Apply styles to Poll Header * Add styles for poll options * Add styles for pollClose button * Add styles for Poll End Vote button * Add styles for show all options button * Add default styles for polls * Update CHANGELOG.md --- CHANGELOG.md | 1 + .../api/stream-chat-android-ui-components.api | 27 +++ .../list/adapter/view/PollViewStyle.kt | 200 ++++++++++++++++++ .../list/adapter/view/internal/PollView.kt | 46 +++- .../chat/android/ui/helper/TransformStyle.kt | 4 + .../layout/stream_ui_fragment_create_poll.xml | 1 + .../res/layout/stream_ui_item_poll_answer.xml | 1 - .../res/layout/stream_ui_item_poll_close.xml | 1 + .../layout/stream_ui_item_poll_results.xml | 1 + .../stream_ui_item_poll_show_all_options.xml | 1 + .../src/main/res/values/attrs.xml | 1 + .../src/main/res/values/attrs_poll_view.xml | 129 +++++++++++ .../src/main/res/values/styles.xml | 25 +++ 13 files changed, 430 insertions(+), 8 deletions(-) create mode 100644 stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle.kt create mode 100644 stream-chat-android-ui-components/src/main/res/values/attrs_poll_view.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index d3523a3fa40..3cc7b8ba249 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -156,6 +156,7 @@ ### ✅ Added - Add `MessageListViewModel.flagUser()` and `MessageListViewModel.unflagUser()` methods for flagging/un-flagging users. [#5478](https://github.com/GetStream/stream-chat-android/pull/5478) - Add edge-to-edge support for apps targeting Android 15. [#5469](https://github.com/GetStream/stream-chat-android/pull/5469) +- Add styles for polls. [#5479](https://github.com/GetStream/stream-chat-android/pull/5479) ## stream-chat-android-compose ### ✅ Added diff --git a/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api b/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api index bb7b5dc55d3..5714fd3d46a 100644 --- a/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api +++ b/stream-chat-android-ui-components/api/stream-chat-android-ui-components.api @@ -3062,6 +3062,31 @@ public final class io/getstream/chat/android/ui/feature/messages/list/adapter/vi public final fun setMessage (Lio/getstream/chat/android/models/Message;ZLio/getstream/chat/android/ui/feature/messages/list/MessageReplyStyle;)V } +public final class io/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle : io/getstream/chat/android/ui/helper/ViewStyle { + public fun (Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Landroid/graphics/drawable/Drawable;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;)V + public final fun component1 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component2 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component3 ()Landroid/graphics/drawable/Drawable; + public final fun component4 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component5 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component6 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component7 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun component8 ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun copy (Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Landroid/graphics/drawable/Drawable;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;)Lio/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle; + public static synthetic fun copy$default (Lio/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Landroid/graphics/drawable/Drawable;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;Lio/getstream/chat/android/ui/font/TextStyle;ILjava/lang/Object;)Lio/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle; + public fun equals (Ljava/lang/Object;)Z + public final fun getPollCloseTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun getPollOptionCheckDrawable ()Landroid/graphics/drawable/Drawable; + public final fun getPollOptionTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun getPollOptionVotesTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun getPollResultsTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun getPollShowAllOptionsTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun getPollSubtitleTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public final fun getPollTitleTextStyle ()Lio/getstream/chat/android/ui/font/TextStyle; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/chat/android/ui/feature/messages/list/adapter/view/internal/GiphyMediaAttachmentView : androidx/constraintlayout/widget/ConstraintLayout { public fun (Landroid/content/Context;)V public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V @@ -3881,6 +3906,7 @@ public final class io/getstream/chat/android/ui/helper/TransformStyle { public static final fun getMessageListStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; public static final fun getMessageReplyStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; public static final fun getPinnedMessageListViewStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; + public static final fun getPollViewStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; public static final fun getScrollButtonStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; public static final fun getSearchInputViewStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; public static final fun getSearchResultListViewStyleTransformer ()Lio/getstream/chat/android/ui/helper/StyleTransformer; @@ -3910,6 +3936,7 @@ public final class io/getstream/chat/android/ui/helper/TransformStyle { public static final fun setMessageListStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V public static final fun setMessageReplyStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V public static final fun setPinnedMessageListViewStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V + public static final fun setPollViewStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V public static final fun setScrollButtonStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V public static final fun setSearchInputViewStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V public static final fun setSearchResultListViewStyleTransformer (Lio/getstream/chat/android/ui/helper/StyleTransformer;)V diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle.kt new file mode 100644 index 00000000000..9b1c0d1cbaf --- /dev/null +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/PollViewStyle.kt @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-chat-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.getstream.chat.android.ui.feature.messages.list.adapter.view + +import android.content.Context +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import io.getstream.chat.android.ui.R +import io.getstream.chat.android.ui.font.TextStyle +import io.getstream.chat.android.ui.helper.TransformStyle +import io.getstream.chat.android.ui.helper.ViewStyle +import io.getstream.chat.android.ui.utils.extensions.getColorCompat +import io.getstream.chat.android.ui.utils.extensions.getDimension +import io.getstream.chat.android.ui.utils.extensions.getDrawableCompat +import io.getstream.chat.android.ui.utils.extensions.use + +public data class PollViewStyle( + public val pollTitleTextStyle: TextStyle, + public val pollSubtitleTextStyle: TextStyle, + public val pollOptionCheckDrawable: Drawable, + public val pollOptionTextStyle: TextStyle, + public val pollOptionVotesTextStyle: TextStyle, + public val pollCloseTextStyle: TextStyle, + public val pollResultsTextStyle: TextStyle, + public val pollShowAllOptionsTextStyle: TextStyle, +) : ViewStyle { + + internal companion object { + @Suppress("LongMethod") + internal operator fun invoke(context: Context, attrs: AttributeSet?): PollViewStyle { + context.obtainStyledAttributes( + attrs, + R.styleable.PollView, + R.attr.streamUiMessageListPollStyle, + R.style.StreamUi_MessageList_Poll, + ).use { a -> + val pollTitleTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollTitleTextSize, + context.getDimension(R.dimen.stream_ui_text_large), + ) + .color( + R.styleable.PollView_streamUiPollTitleTextColor, + context.getColorCompat(R.color.stream_ui_text_color_primary), + ) + .font( + R.styleable.PollView_streamUiPollTitleFontAssets, + R.styleable.PollView_streamUiPollTitleTextFont, + ) + .style( + R.styleable.PollView_streamUiPollTitleTextStyle, + Typeface.NORMAL, + ) + .build() + + val pollOptionCheckDrawable = a.getDrawable(R.styleable.PollView_streamUiPollOptionCheckDrawable) + ?: context.getDrawableCompat(R.drawable.stream_ui_poll_option_selector)!! + + val pollSubtitleTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollSubtitleTextSize, + context.getDimension(R.dimen.stream_ui_text_medium), + ) + .color( + R.styleable.PollView_streamUiPollSubtitleTextColor, + context.getColorCompat(R.color.stream_ui_text_color_secondary), + ) + .font( + R.styleable.PollView_streamUiPollSubtitleFontAssets, + R.styleable.PollView_streamUiPollSubtitleTextFont, + ) + .style( + R.styleable.PollView_streamUiPollSubtitleTextStyle, + Typeface.NORMAL, + ) + .build() + + val pollOptionTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollOptionTextSize, + context.getDimension(R.dimen.stream_ui_text_medium), + ) + .color( + R.styleable.PollView_streamUiPollOptionTextColor, + context.getColorCompat(R.color.stream_ui_text_color_primary), + ) + .font( + R.styleable.PollView_streamUiPollOptionFontAssets, + R.styleable.PollView_streamUiPollOptionTextFont, + ) + .style( + R.styleable.PollView_streamUiPollOptionTextStyle, + Typeface.NORMAL, + ) + .build() + + val pollVotesTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollVotesTextSize, + context.getDimension(R.dimen.stream_ui_text_medium), + ) + .color( + R.styleable.PollView_streamUiPollVotesTextColor, + context.getColorCompat(R.color.stream_ui_text_color_primary), + ) + .font( + R.styleable.PollView_streamUiPollVotesFontAssets, + R.styleable.PollView_streamUiPollVotesTextFont, + ) + .style( + R.styleable.PollView_streamUiPollVotesTextStyle, + Typeface.NORMAL, + ) + .build() + + val pollCloseTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollCloseTextSize, + context.getDimension(R.dimen.stream_ui_text_large), + ) + .color( + R.styleable.PollView_streamUiPollCloseTextColor, + context.getColorCompat(R.color.stream_ui_accent_blue), + ) + .font( + R.styleable.PollView_streamUiPollCloseFontAssets, + R.styleable.PollView_streamUiPollCloseTextFont, + ) + .style( + R.styleable.PollView_streamUiPollCloseTextStyle, + Typeface.NORMAL, + ) + .build() + + val pollResultsTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollResultsTextSize, + context.getDimension(R.dimen.stream_ui_text_large), + ) + .color( + R.styleable.PollView_streamUiPollResultsTextColor, + context.getColorCompat(R.color.stream_ui_accent_blue), + ) + .font( + R.styleable.PollView_streamUiPollResultsFontAssets, + R.styleable.PollView_streamUiPollResultsTextFont, + ) + .style( + R.styleable.PollView_streamUiPollResultsTextStyle, + Typeface.NORMAL, + ) + .build() + + val pollShowAllOptionsTextStyle = TextStyle.Builder(a) + .size( + R.styleable.PollView_streamUiPollShowAllOptionsTextSize, + context.getDimension(R.dimen.stream_ui_text_large), + ) + .color( + R.styleable.PollView_streamUiPollShowAllOptionsTextColor, + context.getColorCompat(R.color.stream_ui_accent_blue), + ) + .font( + R.styleable.PollView_streamUiPollShowAllOptionsFontAssets, + R.styleable.PollView_streamUiPollShowAllOptionsTextFont, + ) + .style( + R.styleable.PollView_streamUiPollShowAllOptionsTextStyle, + Typeface.NORMAL, + ) + .build() + return PollViewStyle( + pollTitleTextStyle = pollTitleTextStyle, + pollSubtitleTextStyle = pollSubtitleTextStyle, + pollOptionCheckDrawable = pollOptionCheckDrawable, + pollOptionTextStyle = pollOptionTextStyle, + pollOptionVotesTextStyle = pollVotesTextStyle, + pollCloseTextStyle = pollCloseTextStyle, + pollResultsTextStyle = pollResultsTextStyle, + pollShowAllOptionsTextStyle = pollShowAllOptionsTextStyle, + ).let(TransformStyle.pollViewStyleTransformer::transform) + } + } + } +} diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/internal/PollView.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/internal/PollView.kt index 7f4e7c5ef19..4f2b8c98568 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/internal/PollView.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/feature/messages/list/adapter/view/internal/PollView.kt @@ -34,6 +34,8 @@ import io.getstream.chat.android.ui.databinding.StreamUiItemPollCloseBinding import io.getstream.chat.android.ui.databinding.StreamUiItemPollHeaderBinding import io.getstream.chat.android.ui.databinding.StreamUiItemPollResultsBinding import io.getstream.chat.android.ui.databinding.StreamUiItemPollShowAllOptionsBinding +import io.getstream.chat.android.ui.feature.messages.list.adapter.view.PollViewStyle +import io.getstream.chat.android.ui.font.setTextStyle import io.getstream.chat.android.ui.utils.extensions.createStreamThemeWrapper import io.getstream.chat.android.ui.utils.extensions.streamThemeInflater import io.getstream.log.taggedLogger @@ -42,7 +44,7 @@ internal class PollView : RecyclerView { private val logger by taggedLogger("PollView") - // private lateinit var style: FileAttachmentViewStyle + private lateinit var style: PollViewStyle private lateinit var pollAdapter: PollAdapter var onOptionClick: ((Option) -> Unit) = { _ -> } @@ -68,13 +70,14 @@ internal class PollView : RecyclerView { } private fun init(attrs: AttributeSet?) { - /** not implemented yet */ + style = PollViewStyle(context, attrs) } fun setPoll(poll: Poll, isMine: Boolean) { logger.d { "[setPoll] poll: $poll" } if (!::pollAdapter.isInitialized) { pollAdapter = PollAdapter( + pollViewStyle = style, onOptionClick = { option -> onOptionClick(option) }, onClosePollClick = { onClosePollClick(poll) }, onViewPollResultsClick = { onViewPollResultsClick(poll) }, @@ -121,6 +124,7 @@ internal class PollView : RecyclerView { } private class PollAdapter( + private val pollViewStyle: PollViewStyle, private val onOptionClick: (Option) -> Unit, private val onClosePollClick: () -> Unit, private val onViewPollResultsClick: () -> Unit, @@ -138,22 +142,27 @@ private class PollAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PollItemViewHolder { return when (viewType) { VIEW_TYPE_HEADER -> HeaderViewHolder( - StreamUiItemPollHeaderBinding.inflate(parent.streamThemeInflater, parent, false), + StreamUiItemPollHeaderBinding.inflate(parent.streamThemeInflater, parent, false) + .applyStyle(pollViewStyle), ) VIEW_TYPE_ANSWER -> AnswerViewHolder( - StreamUiItemPollAnswerBinding.inflate(parent.streamThemeInflater, parent, false), + StreamUiItemPollAnswerBinding.inflate(parent.streamThemeInflater, parent, false) + .applyStyle(pollViewStyle), onOptionClick, ) VIEW_TYPE_CLOSE -> CloseViewHolder( - StreamUiItemPollCloseBinding.inflate(parent.streamThemeInflater, parent, false), + StreamUiItemPollCloseBinding.inflate(parent.streamThemeInflater, parent, false) + .applyStyle(pollViewStyle), onClosePollClick, ) VIEW_TYPE_RESULTS -> ViewResultsViewHolder( - StreamUiItemPollResultsBinding.inflate(parent.streamThemeInflater, parent, false), + StreamUiItemPollResultsBinding.inflate(parent.streamThemeInflater, parent, false) + .applyStyle(pollViewStyle), onViewPollResultsClick, ) VIEW_TYPE_SHOW_ALL_OPTIONS -> ShowAllOptionsViewHolder( - StreamUiItemPollShowAllOptionsBinding.inflate(parent.streamThemeInflater, parent, false), + StreamUiItemPollShowAllOptionsBinding.inflate(parent.streamThemeInflater, parent, false) + .applyStyle(pollViewStyle), onShowAllOptionsClick, ) else -> throw IllegalArgumentException("Unknown view type: $viewType") @@ -301,3 +310,26 @@ private class ViewResultsViewHolder( binding.root.setOnClickListener { onViewPollResultsClick() } } } + +private fun StreamUiItemPollHeaderBinding.applyStyle(style: PollViewStyle) = this.apply { + title.setTextStyle(style.pollTitleTextStyle) + subtitle.setTextStyle(style.pollSubtitleTextStyle) +} + +private fun StreamUiItemPollAnswerBinding.applyStyle(style: PollViewStyle) = this.apply { + check.setImageDrawable(style.pollOptionCheckDrawable.constantState?.newDrawable()) + option.setTextStyle(style.pollOptionTextStyle) + votes.setTextStyle(style.pollOptionVotesTextStyle) +} + +private fun StreamUiItemPollCloseBinding.applyStyle(style: PollViewStyle) = this.apply { + pollClose.setTextStyle(style.pollCloseTextStyle) +} + +private fun StreamUiItemPollResultsBinding.applyStyle(style: PollViewStyle) = this.apply { + pollResults.setTextStyle(style.pollResultsTextStyle) +} + +private fun StreamUiItemPollShowAllOptionsBinding.applyStyle(style: PollViewStyle) = this.apply { + pollShowAllOptions.setTextStyle(style.pollShowAllOptionsTextStyle) +} diff --git a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/helper/TransformStyle.kt b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/helper/TransformStyle.kt index 3650261e729..cf384d10607 100644 --- a/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/helper/TransformStyle.kt +++ b/stream-chat-android-ui-components/src/main/kotlin/io/getstream/chat/android/ui/helper/TransformStyle.kt @@ -37,6 +37,7 @@ import io.getstream.chat.android.ui.feature.messages.list.ScrollButtonViewStyle import io.getstream.chat.android.ui.feature.messages.list.UnreadLabelButtonStyle import io.getstream.chat.android.ui.feature.messages.list.UnsupportedAttachmentViewStyle import io.getstream.chat.android.ui.feature.messages.list.adapter.view.MediaAttachmentViewStyle +import io.getstream.chat.android.ui.feature.messages.list.adapter.view.PollViewStyle import io.getstream.chat.android.ui.feature.messages.list.reactions.edit.EditReactionsViewStyle import io.getstream.chat.android.ui.feature.messages.list.reactions.user.SingleReactionViewStyle import io.getstream.chat.android.ui.feature.messages.list.reactions.view.ViewReactionsViewStyle @@ -87,6 +88,9 @@ public object TransformStyle { @JvmStatic public var mediaAttachmentStyleTransformer: StyleTransformer = noopTransformer() + @JvmStatic + public var pollViewStyleTransformer: StyleTransformer = noopTransformer() + @JvmStatic public var messageReplyStyleTransformer: StyleTransformer = noopTransformer() diff --git a/stream-chat-android-ui-components/src/main/res/layout/stream_ui_fragment_create_poll.xml b/stream-chat-android-ui-components/src/main/res/layout/stream_ui_fragment_create_poll.xml index 33b7522fbdf..5890e3bfc2e 100644 --- a/stream-chat-android-ui-components/src/main/res/layout/stream_ui_fragment_create_poll.xml +++ b/stream-chat-android-ui-components/src/main/res/layout/stream_ui_fragment_create_poll.xml @@ -106,6 +106,7 @@ android:textAppearance="@style/StreamUiTextAppearance.Headline" android:background="@drawable/stream_ui_poll_input_bg" android:gravity="center_vertical" + android:textColor="@color/stream_ui_text_color_secondary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/optionList" diff --git a/stream-chat-android-ui-components/src/main/res/layout/stream_ui_item_poll_answer.xml b/stream-chat-android-ui-components/src/main/res/layout/stream_ui_item_poll_answer.xml index b6cc8bd692a..6fbca33bf33 100644 --- a/stream-chat-android-ui-components/src/main/res/layout/stream_ui_item_poll_answer.xml +++ b/stream-chat-android-ui-components/src/main/res/layout/stream_ui_item_poll_answer.xml @@ -30,7 +30,6 @@ android:layout_height="24dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" - app:srcCompat="@drawable/stream_ui_poll_option_selector" /> + diff --git a/stream-chat-android-ui-components/src/main/res/values/attrs_poll_view.xml b/stream-chat-android-ui-components/src/main/res/values/attrs_poll_view.xml new file mode 100644 index 00000000000..81f252de844 --- /dev/null +++ b/stream-chat-android-ui-components/src/main/res/values/attrs_poll_view.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stream-chat-android-ui-components/src/main/res/values/styles.xml b/stream-chat-android-ui-components/src/main/res/values/styles.xml index affe5a819f2..56cb341e76b 100644 --- a/stream-chat-android-ui-components/src/main/res/values/styles.xml +++ b/stream-chat-android-ui-components/src/main/res/values/styles.xml @@ -544,6 +544,31 @@ normal + +