Compare commits
436 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87b3a5d2f0 | ||
|
|
1e67c2f77b | ||
|
|
0e2213a199 | ||
|
|
1f3d848c79 | ||
|
|
0aaa80cbdc | ||
|
|
7b93bfbba9 | ||
|
|
6cef5cec1b | ||
|
|
f447560665 | ||
|
|
1f6824d285 | ||
|
|
8a4ff4c456 | ||
|
|
3df85017af | ||
|
|
b31dad4b26 | ||
|
|
6e74446209 | ||
|
|
afa2a824b5 | ||
|
|
94c3bb9c41 | ||
|
|
fe6a17e977 | ||
|
|
4876b7c930 | ||
|
|
a158da1d18 | ||
|
|
aa92bb61c1 | ||
|
|
bb2779549e | ||
|
|
5277382e6d | ||
|
|
bcad1f9dce | ||
|
|
00efd9a01c | ||
|
|
d6ef505260 | ||
|
|
7e42dd1529 | ||
|
|
989201eb68 | ||
|
|
5be14df828 | ||
|
|
88a90aeb5a | ||
|
|
4526563668 | ||
|
|
4607681c5f | ||
|
|
eed183be53 | ||
|
|
b4f23d9d9e | ||
|
|
19397b6fa7 | ||
|
|
dea808ce8d | ||
|
|
c3a4d64ec6 | ||
|
|
0c3c9f48bb | ||
|
|
44df2d2c17 | ||
|
|
a33d717aa0 | ||
|
|
933b18f6c2 | ||
|
|
4641ae666e | ||
|
|
bd01b27517 | ||
|
|
0725c16471 | ||
|
|
df9a3fe9c2 | ||
|
|
c2e357cbcd | ||
|
|
5b2970f789 | ||
|
|
620f1865e8 | ||
|
|
42566b4b1f | ||
|
|
67c668990e | ||
|
|
260ea4a7d2 | ||
|
|
3d85cf4fd2 | ||
|
|
64d9336901 | ||
|
|
42c141109f | ||
|
|
94392f3ebd | ||
|
|
dc05388cca | ||
|
|
52f12031c8 | ||
|
|
5dd897dae8 | ||
|
|
900b888044 | ||
|
|
1473f5e806 | ||
|
|
33c7c75550 | ||
|
|
75feaa7ee7 | ||
|
|
18bc6a27c4 | ||
|
|
a6f7c05458 | ||
|
|
c59b96de66 | ||
|
|
2248cd20f3 | ||
|
|
53fe12bdda | ||
|
|
882d5577a7 | ||
|
|
5af57906b5 | ||
|
|
28d4985435 | ||
|
|
20d0d115d4 | ||
|
|
d8793ca8f6 | ||
|
|
f373c73e60 | ||
|
|
2f406eaf41 | ||
|
|
c94ba068ed | ||
|
|
6cc2e59436 | ||
|
|
e3d1a811d5 | ||
|
|
4e3853a718 | ||
|
|
1774d1d39a | ||
|
|
828337b343 | ||
|
|
174a6cad0d | ||
|
|
07668502fa | ||
|
|
1111315c6a | ||
|
|
653d9861dc | ||
|
|
2771ce9442 | ||
|
|
fb17fc7e8a | ||
|
|
efa61f1d24 | ||
|
|
458405b29f | ||
|
|
9b1735e0e9 | ||
|
|
668edbc679 | ||
|
|
2954174c56 | ||
|
|
e6c3a8ff1d | ||
|
|
a89d37297f | ||
|
|
1c317d1ffd | ||
|
|
ef7d1a10bf | ||
|
|
dcc67f9fc6 | ||
|
|
cbc677b80d | ||
|
|
432a7712c4 | ||
|
|
486754602d | ||
|
|
e563fc7919 | ||
|
|
5e577e2360 | ||
|
|
68d0cad3b7 | ||
|
|
c1fcb0f6f6 | ||
|
|
4823267013 | ||
|
|
7e6d3c60d2 | ||
|
|
d770a47904 | ||
|
|
31d06391ed | ||
|
|
737882d35e | ||
|
|
c959f50d53 | ||
|
|
960ff0fb75 | ||
|
|
2ea23bcc3e | ||
|
|
e8f1bf0085 | ||
|
|
3ca06d71ef | ||
|
|
9eac27515e | ||
|
|
bad934d329 | ||
|
|
b4305b1749 | ||
|
|
9ca0b9e898 | ||
|
|
3f02f527f0 | ||
|
|
ae50f6b897 | ||
|
|
c68e1b8845 | ||
|
|
2d4d4cdf25 | ||
|
|
d299b722e3 | ||
|
|
f04c836371 | ||
|
|
c30fee7f14 | ||
|
|
3234931d3c | ||
|
|
b11fcec985 | ||
|
|
9326c30f05 | ||
|
|
72be7ff1f9 | ||
|
|
77b444581d | ||
|
|
a227b830be | ||
|
|
11476c73cf | ||
|
|
5e5e0bbc6e | ||
|
|
1ffc09e046 | ||
|
|
6bc8cd84e4 | ||
|
|
7f545079ad | ||
|
|
90ce30d6e7 | ||
|
|
c5a054b9e3 | ||
|
|
a478d87fc3 | ||
|
|
f0f5e8be25 | ||
|
|
9ce8253086 | ||
|
|
9a8046c02d | ||
|
|
4437d4d9df | ||
|
|
885d0f2cb9 | ||
|
|
f05ceb9f5d | ||
|
|
e49e183178 | ||
|
|
0c657c258a | ||
|
|
071d98c66b | ||
|
|
4a4b3e07ef | ||
|
|
245c30c18a | ||
|
|
14096f3837 | ||
|
|
d50c04a420 | ||
|
|
4497d7da36 | ||
|
|
cc65a0f114 | ||
|
|
63edcd6989 | ||
|
|
0cb1a9fb14 | ||
|
|
95dac66869 | ||
|
|
7e3acc03b9 | ||
|
|
a6bee757b4 | ||
|
|
a7c9fedc8f | ||
|
|
0abb04ea62 | ||
|
|
022d21b097 | ||
|
|
80a46fdb3d | ||
|
|
790c30ca1f | ||
|
|
866c8375b3 | ||
|
|
ae044607c7 | ||
|
|
d18b529285 | ||
|
|
d558371798 | ||
|
|
5269b9787e | ||
|
|
44baa4a383 | ||
|
|
668b03f8bc | ||
|
|
90918cbb9d | ||
|
|
bc60512e10 | ||
|
|
94d37c68d5 | ||
|
|
8799dda471 | ||
|
|
61374bca4e | ||
|
|
2f45ca8835 | ||
|
|
861de339d8 | ||
|
|
4948497be2 | ||
|
|
b19a2c5a44 | ||
|
|
0349162694 | ||
|
|
a27278da20 | ||
|
|
a7c4a2b404 | ||
|
|
223dd1f6b0 | ||
|
|
a77c2c0c7e | ||
|
|
15162e4e32 | ||
|
|
2a694f6dfd | ||
|
|
6ef9315468 | ||
|
|
9b91fabbd6 | ||
|
|
f4cf704335 | ||
|
|
34f001d22c | ||
|
|
70452842d3 | ||
|
|
f0b9ce567a | ||
|
|
bcc2eb3d34 | ||
|
|
1fd02be0f4 | ||
|
|
47ca5a5f2f | ||
|
|
a7711b7d52 | ||
|
|
65ddc4355e | ||
|
|
3b3b4813b6 | ||
|
|
384c806131 | ||
|
|
54a6666988 | ||
|
|
28e1062eed | ||
|
|
0a9259604b | ||
|
|
2d203e83b9 | ||
|
|
a12b519155 | ||
|
|
51bcaca9db | ||
|
|
c40f916b4f | ||
|
|
ab85c554ff | ||
|
|
d7be603bfc | ||
|
|
6897cc5721 | ||
|
|
54525d855e | ||
|
|
26fe5b6492 | ||
|
|
61f074ddc1 | ||
|
|
e8e5a2d454 | ||
|
|
18fbe91fc7 | ||
|
|
a0646717a3 | ||
|
|
27869c0e04 | ||
|
|
5733c3149a | ||
|
|
e81ab35f5b | ||
|
|
0d2f71643a | ||
|
|
715402d178 | ||
|
|
194945c49e | ||
|
|
65a9a97735 | ||
|
|
6c7c48da69 | ||
|
|
e21276f323 | ||
|
|
85ef12a401 | ||
|
|
4e38846342 | ||
|
|
11b9efa2c9 | ||
|
|
30fd90abb9 | ||
|
|
13775f4fbd | ||
|
|
b8995e4356 | ||
|
|
0b04dec85c | ||
|
|
d6f8c13c3f | ||
|
|
b1890de26a | ||
|
|
8188ef1463 | ||
|
|
562e36b5ea | ||
|
|
97cada7432 | ||
|
|
5e963fc743 | ||
|
|
dcd0a98c0c | ||
|
|
4e46f12a12 | ||
|
|
70583fc3fc | ||
|
|
9912d763d4 | ||
|
|
0c333235f8 | ||
|
|
0a99b28963 | ||
|
|
b815aaabc9 | ||
|
|
f5737e9d2b | ||
|
|
e5d134cd3b | ||
|
|
f4b3ddfa0b | ||
|
|
efe611eb4f | ||
|
|
be22ac8de9 | ||
|
|
795299ed0c | ||
|
|
c9bc8791e9 | ||
|
|
fabdcee520 | ||
|
|
4a79b272ef | ||
|
|
078e942a28 | ||
|
|
4d0be69b4c | ||
|
|
b50969437d | ||
|
|
c8773c890f | ||
|
|
3dd2a60b3a | ||
|
|
35a3a0ba06 | ||
|
|
8b8eedb419 | ||
|
|
8512279d96 | ||
|
|
29e0a08dd9 | ||
|
|
c1e908a8e6 | ||
|
|
a76b55e580 | ||
|
|
da36323006 | ||
|
|
7940b8f865 | ||
|
|
6ba4679908 | ||
|
|
66f68fdccb | ||
|
|
531d9b3d47 | ||
|
|
6154816796 | ||
|
|
a6622c6787 | ||
|
|
f0dc4eeace | ||
|
|
026c448e48 | ||
|
|
3b21d698ee | ||
|
|
d215354e64 | ||
|
|
1eeabb1e64 | ||
|
|
6de6e13f25 | ||
|
|
367995303d | ||
|
|
c750fd102f | ||
|
|
083fc5c5fb | ||
|
|
7dd81dc838 | ||
|
|
1d03cbfc06 | ||
|
|
3fd2f0991a | ||
|
|
7d27ff3c59 | ||
|
|
7080cf77e6 | ||
|
|
fd69bbc57a | ||
|
|
723b7486bc | ||
|
|
997227b020 | ||
|
|
90ed385745 | ||
|
|
cd61c6b3f0 | ||
|
|
5c9d8d917c | ||
|
|
5508442222 | ||
|
|
5e8db74003 | ||
|
|
fff27ff3f1 | ||
|
|
3878ce000c | ||
|
|
5bb0b92eeb | ||
|
|
4bb33fc36a | ||
|
|
944d8965f6 | ||
|
|
2bcf10dd0b | ||
|
|
8860647477 | ||
|
|
21cae089ae | ||
|
|
dca2dba938 | ||
|
|
e289ec2af7 | ||
|
|
a35236b8b0 | ||
|
|
0d078a41ca | ||
|
|
09ff3294d5 | ||
|
|
bf57223d05 | ||
|
|
14054344f4 | ||
|
|
9a2ad3928a | ||
|
|
3c51732d35 | ||
|
|
22ef9f1a5e | ||
|
|
fb50fce649 | ||
|
|
c283f0109b | ||
|
|
10c9112e03 | ||
|
|
5929806137 | ||
|
|
de7b4002d8 | ||
|
|
a276e67ce6 | ||
|
|
1c229e7229 | ||
|
|
112dc93fff | ||
|
|
3379c61ad1 | ||
|
|
289dfff50a | ||
|
|
92ee479e91 | ||
|
|
e37083669e | ||
|
|
09e0d2d166 | ||
|
|
bbb4a47eff | ||
|
|
e036250539 | ||
|
|
9dd61bbd37 | ||
|
|
2c6f1888f4 | ||
|
|
d9080f5465 | ||
|
|
b4f1627748 | ||
|
|
92add85883 | ||
|
|
b12a9ff2b9 | ||
|
|
7bbdecc7a8 | ||
|
|
c9b48d32b0 | ||
|
|
c1678f22e6 | ||
|
|
769341e4f2 | ||
|
|
630b0c8098 | ||
|
|
1e39736797 | ||
|
|
83b4bfad96 | ||
|
|
61a8d06a6a | ||
|
|
3199a7dd8b | ||
|
|
24b24e511a | ||
|
|
0224c7e2a5 | ||
|
|
61c68f8d4a | ||
|
|
a0632b216c | ||
|
|
1e04a7345f | ||
|
|
91d265e6bf | ||
|
|
d38ef5ba10 | ||
|
|
5d270068d6 | ||
|
|
79afb1d9e0 | ||
|
|
97ae775df5 | ||
|
|
f6ed0a645a | ||
|
|
75db550ca8 | ||
|
|
54efb46294 | ||
|
|
f3dd7b86d8 | ||
|
|
283fd2970a | ||
|
|
2d4ed98738 | ||
|
|
a662a5a045 | ||
|
|
7f198155f2 | ||
|
|
064c606b53 | ||
|
|
b080c01388 | ||
|
|
66ed52dee8 | ||
|
|
c343df8351 | ||
|
|
434e592fed | ||
|
|
168782e049 | ||
|
|
3c06e0a260 | ||
|
|
8eb5a55673 | ||
|
|
af47e2b405 | ||
|
|
e158be86aa | ||
|
|
b0e9073efb | ||
|
|
e5f85592d9 | ||
|
|
96cbe7664b | ||
|
|
51733ec6fe | ||
|
|
e1b7171839 | ||
|
|
f80a140cf9 | ||
|
|
8853f160e2 | ||
|
|
05e1048d20 | ||
|
|
8611b9c690 | ||
|
|
c35b5811d0 | ||
|
|
447f4e5134 | ||
|
|
f7eaedf805 | ||
|
|
18d4924171 | ||
|
|
58bde16b81 | ||
|
|
09e57e077a | ||
|
|
09720a01c9 | ||
|
|
41f86b492c | ||
|
|
5fb0b3a93d | ||
|
|
ae94e0c746 | ||
|
|
3b813f137b | ||
|
|
8182a149d0 | ||
|
|
269d367130 | ||
|
|
a341a1a59e | ||
|
|
4e5542396f | ||
|
|
d7963ddb5a | ||
|
|
6a4fed2baf | ||
|
|
47a430978f | ||
|
|
98ececf3d0 | ||
|
|
6d134375f6 | ||
|
|
efe76281ad | ||
|
|
a1c9994385 | ||
|
|
f661ccf25a | ||
|
|
5b3f91ff78 | ||
|
|
555d7acbd3 | ||
|
|
2966ccc96d | ||
|
|
3f9b8b822e | ||
|
|
fbfeeae084 | ||
|
|
6b933b6506 | ||
|
|
704ddc9132 | ||
|
|
67729f87c9 | ||
|
|
11866afb03 | ||
|
|
f5683f9c8b | ||
|
|
f7cfa6cda8 | ||
|
|
e85b532d6a | ||
|
|
580e85d232 | ||
|
|
537063d899 | ||
|
|
0e9af5f42a | ||
|
|
7c3b9523df | ||
|
|
9ba8798175 | ||
|
|
d6999b5334 | ||
|
|
fd92a2eef2 | ||
|
|
43bef7f1df | ||
|
|
f19295d63d | ||
|
|
5e6a6af409 | ||
|
|
4e0165458a | ||
|
|
4586ee31ea | ||
|
|
9a81ec5569 | ||
|
|
104ae4752a | ||
|
|
d0dcbab750 | ||
|
|
37da07a720 | ||
|
|
55d043788b | ||
|
|
a7e254cc84 | ||
|
|
d9a54fb716 | ||
|
|
4a5662a5e2 | ||
|
|
bf7ab31517 | ||
|
|
b082f59f9c | ||
|
|
a22c9871e3 | ||
|
|
cea003a929 | ||
|
|
a96c146d30 |
2471 changed files with 28166 additions and 26919 deletions
|
|
@ -1,40 +0,0 @@
|
||||||
# .forgejo/workflows/gitleaks.yml
|
|
||||||
#
|
|
||||||
# Sulkta canonical gitleaks workflow. Drop a copy into every public repo at
|
|
||||||
# `.forgejo/workflows/gitleaks.yml` after the Forgejo act_runner is registered
|
|
||||||
# (task #295).
|
|
||||||
#
|
|
||||||
# Pairs with the pre-receive hook installed on every bare repo — that one is
|
|
||||||
# the strict enforcement layer (rejects the push); this one provides the
|
|
||||||
# per-PR red ✗ that branch-protection rules can require before merge.
|
|
||||||
#
|
|
||||||
# Layer 1 (this workflow): visible per-PR status, can be a required check.
|
|
||||||
# Layer 2 (pre-receive hook): strict enforcement at the server.
|
|
||||||
# Layer 3 (johnny5 cron sweep): nightly full-history sweep across all repos.
|
|
||||||
|
|
||||||
name: gitleaks
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
scan:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
# Full history — gitleaks needs depth to scan a commit range.
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: install gitleaks
|
|
||||||
run: |
|
|
||||||
curl -sSL -o gl.tar.gz \
|
|
||||||
https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz
|
|
||||||
tar xzf gl.tar.gz gitleaks
|
|
||||||
chmod +x gitleaks
|
|
||||||
./gitleaks version
|
|
||||||
|
|
||||||
- name: scan
|
|
||||||
run: |
|
|
||||||
./gitleaks detect --source . --no-banner --redact --verbose
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
name: Upstream sync
|
|
||||||
|
|
||||||
# Daily check against the upstream mirror. Fast-forwards `main` to
|
|
||||||
# `upstream/develop` when upstream has advanced, then pings the Infra
|
|
||||||
# Matrix room so we know the wallet branch is due for a rebase.
|
|
||||||
#
|
|
||||||
# See SYNC.md on the wallet branch for the full topology + procedure
|
|
||||||
# this job implements.
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
# 12:00 UTC daily — quiet time for all our time zones, avoids the
|
|
||||||
# morning-meeting window where an unexpected Matrix ping is noise.
|
|
||||||
- cron: '0 12 * * *'
|
|
||||||
workflow_dispatch: # manual trigger from the Actions UI too
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync-main:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
# The repo's .gitattributes (inherited from upstream) routes the
|
|
||||||
# screenshots/ tree through git-lfs. Gitea's LFS store doesn't hold
|
|
||||||
# those blobs, so on checkout the smudge filter tries to 404-download
|
|
||||||
# them and wedges git state for subsequent fetches. We don't need
|
|
||||||
# the image bytes here — leave LFS pointers as-is.
|
|
||||||
GIT_LFS_SKIP_SMUDGE: '1'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout main
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
fetch-depth: 0
|
|
||||||
lfs: false
|
|
||||||
# Gitea's built-in GITEA_TOKEN is read-only by default.
|
|
||||||
# GIT_PUSH_TOKEN is a repo secret with a write-scoped PAT, so
|
|
||||||
# the subsequent `git push origin main` actually lands.
|
|
||||||
token: ${{ secrets.GIT_PUSH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Fetch upstream + wallet
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
# Fetch directly from GitHub. We also have a Gitea pull-mirror
|
|
||||||
# at Sulkta-Coop/element-x-upstream that tracks this same repo,
|
|
||||||
# but sourcing from GitHub keeps the workflow independent of
|
|
||||||
# the mirror's health — one less moving part to diagnose.
|
|
||||||
git remote add upstream https://github.com/element-hq/element-x-android.git
|
|
||||||
git fetch --depth=500 upstream develop
|
|
||||||
git fetch origin wallet:refs/remotes/origin/wallet
|
|
||||||
|
|
||||||
- name: Fast-forward main
|
|
||||||
id: ff
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
git config user.name "sulkta-bot"
|
|
||||||
git config user.email "bot@sulkta.com"
|
|
||||||
# git-lfs pre-push hook refuses incomplete pushes — which triggers
|
|
||||||
# here because we skipped LFS smudge on checkout, so local LFS
|
|
||||||
# objects are absent. We're only pushing branch pointers (no new
|
|
||||||
# LFS content), so allow incomplete.
|
|
||||||
git config lfs.allowincompletepush true
|
|
||||||
OLD=$(git rev-parse --short HEAD)
|
|
||||||
echo "main was at $OLD"
|
|
||||||
if git merge --ff-only upstream/develop; then
|
|
||||||
NEW=$(git rev-parse --short HEAD)
|
|
||||||
if [ "$OLD" = "$NEW" ]; then
|
|
||||||
echo "main already up to date with upstream/develop"
|
|
||||||
echo "advanced=false" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "main advanced: $OLD -> $NEW"
|
|
||||||
git push origin main
|
|
||||||
echo "advanced=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "old=$OLD" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "new=$NEW" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "::warning::main could not fast-forward to upstream/develop — someone committed to main directly?"
|
|
||||||
echo "advanced=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Measure wallet drift
|
|
||||||
if: steps.ff.outputs.advanced == 'true'
|
|
||||||
id: drift
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
MB=$(git merge-base refs/remotes/origin/wallet main)
|
|
||||||
BEHIND=$(git rev-list --count "$MB..main")
|
|
||||||
NEW_ADDED=$(git rev-list --count "$MB..upstream/develop")
|
|
||||||
echo "behind=$BEHIND" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "new_added=$NEW_ADDED" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "wallet is $BEHIND commits behind main now; $NEW_ADDED new upstream commits this run"
|
|
||||||
|
|
||||||
- name: Matrix notification (Infra room)
|
|
||||||
# Best-effort — if the target bot isn't in the room or Matrix is
|
|
||||||
# flapping, don't fail the whole run. The advance + push is the
|
|
||||||
# critical path; notify is a convenience ping.
|
|
||||||
if: steps.ff.outputs.advanced == 'true'
|
|
||||||
continue-on-error: true
|
|
||||||
env:
|
|
||||||
MATRIX_TOKEN: ${{ secrets.MATRIX_HOUSE_BOT_TOKEN }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
TXN=$(date +%s%N)
|
|
||||||
ROOM='!rvxiUrWpgvMTAwzjGm:sulkta.com' # Infra
|
|
||||||
BODY="element-x upstream advanced · main ${{ steps.ff.outputs.old }} → ${{ steps.ff.outputs.new }} (${{ steps.drift.outputs.new_added }} commits). wallet is ${{ steps.drift.outputs.behind }} commits behind — rebase before next build."
|
|
||||||
|
|
||||||
# jq keeps the body properly JSON-escaped; safer than shell interp
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
PAYLOAD=$(printf '%s' "$BODY" | jq -Rs '{msgtype: "m.text", body: .}')
|
|
||||||
|
|
||||||
curl --fail -s -X PUT \
|
|
||||||
-H "Authorization: Bearer $MATRIX_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
"https://chat.sulkta.com/_matrix/client/v3/rooms/${ROOM}/send/m.room.message/${TXN}" \
|
|
||||||
-d "$PAYLOAD"
|
|
||||||
echo "notified"
|
|
||||||
7
.github/renovate.json5
vendored
7
.github/renovate.json5
vendored
|
|
@ -34,6 +34,13 @@
|
||||||
"/^org.jetbrains.kotlinx:kotlinx-datetime/",
|
"/^org.jetbrains.kotlinx:kotlinx-datetime/",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Keep Guava on the Android variant and ignore jre-only upgrades.
|
||||||
|
"matchPackageNames": [
|
||||||
|
"com.google.guava:guava",
|
||||||
|
],
|
||||||
|
"allowedVersions": "/-android$/",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Limit PostHog Android upgrade to one PR per month, the first day of the month
|
// Limit PostHog Android upgrade to one PR per month, the first day of the month
|
||||||
"matchPackageNames": [
|
"matchPackageNames": [
|
||||||
|
|
|
||||||
110
.github/workflows/build.yml
vendored
Normal file
110
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
name: APK Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
push:
|
||||||
|
branches: [ develop ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build APKs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# For NejcZdovc/comment-pr
|
||||||
|
pull-requests: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
variant: [debug, release, nightly]
|
||||||
|
fail-fast: false
|
||||||
|
# Allow all jobs on develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/develop' && format('build-develop-{0}-{1}', matrix.variant, github.sha) || format('build-{0}-{1}', matrix.variant, github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Assemble debug APKs
|
||||||
|
if: ${{ matrix.variant == 'debug' }}
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
|
||||||
|
ELEMENT_SDK_SENTRY_DSN: ${{ secrets.ELEMENT_SDK_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
|
||||||
|
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
|
||||||
|
run: ./gradlew :app:assembleGplayDebug app:assembleFDroidDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload debug APKs
|
||||||
|
if: ${{ matrix.variant == 'debug' }}
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-debug
|
||||||
|
path: |
|
||||||
|
app/build/outputs/apk/gplay/debug/*-universal-debug.apk
|
||||||
|
app/build/outputs/apk/fdroid/debug/*-universal-debug.apk
|
||||||
|
- uses: rnkdsh/action-upload-diawi@4e1421305be7cfc510d05f47850262eeaf345108 # v1.5.12
|
||||||
|
id: diawi
|
||||||
|
# Do not fail the whole build if Diawi upload fails
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
token: ${{ secrets.DIAWI_TOKEN }}
|
||||||
|
if: ${{ matrix.variant == 'debug' && github.event_name == 'pull_request' && env.token != '' }}
|
||||||
|
with:
|
||||||
|
token: ${{ env.token }}
|
||||||
|
file: app/build/outputs/apk/gplay/debug/app-gplay-arm64-v8a-debug.apk
|
||||||
|
- name: Add or update PR comment with QR Code to download APK.
|
||||||
|
if: ${{ matrix.variant == 'debug' && github.event_name == 'pull_request' && steps.diawi.conclusion == 'success' }}
|
||||||
|
uses: NejcZdovc/comment-pr@a423635d183a8259308e80593c96fecf31539c26 # v2.1.0
|
||||||
|
with:
|
||||||
|
message: |
|
||||||
|
:iphone: Scan the QR code below to install the build (arm64 only) for this PR.
|
||||||
|

|
||||||
|
If you can't scan the QR code you can install the build via this link: ${{ steps.diawi.outputs['url'] }}
|
||||||
|
# Enables to identify and update existing Ad-hoc release message on new commit in the PR
|
||||||
|
identifier: "GITHUB_COMMENT_QR_CODE"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Compile release sources
|
||||||
|
if: ${{ matrix.variant == 'release' }}
|
||||||
|
run: ./gradlew bundleGplayRelease -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Compile nightly sources
|
||||||
|
if: ${{ matrix.variant == 'nightly' }}
|
||||||
|
run: ./gradlew compileGplayNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
|
||||||
92
.github/workflows/build_enterprise.yml
vendored
Normal file
92
.github/workflows/build_enterprise.yml
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
name: Enterprise APK Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
push:
|
||||||
|
branches: [ develop ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build Enterprise APKs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
variant: [debug, release, nightly]
|
||||||
|
fail-fast: false
|
||||||
|
# Allow all jobs on develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/develop' && format('build-develop-enterprise-{0}-{1}', matrix.variant, github.sha) || format('build-enterprise-{0}-{1}', matrix.variant, github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Assemble debug Gplay Enterprise APK
|
||||||
|
if: ${{ matrix.variant == 'debug' }}
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
|
||||||
|
ELEMENT_SDK_SENTRY_DSN: ${{ secrets.ELEMENT_SDK_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
|
||||||
|
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
|
||||||
|
run: ./gradlew :app:assembleGplayDebug -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload debug Enterprise APKs
|
||||||
|
if: ${{ matrix.variant == 'debug' }}
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-enterprise-debug
|
||||||
|
path: |
|
||||||
|
app/build/outputs/apk/gplay/debug/*-universal-debug.apk
|
||||||
|
- name: Compile nightly and release sources
|
||||||
|
if: ${{ matrix.variant == 'release' }}
|
||||||
|
run: ./gradlew compileReleaseSources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Compile nightly sources
|
||||||
|
if: ${{ matrix.variant == 'nightly' }}
|
||||||
|
run: ./gradlew compileGplayNightlySources -PallWarningsAsErrors=true $CI_GRADLE_ARG_PROPERTIES
|
||||||
33
.github/workflows/danger.yml
vendored
Normal file
33
.github/workflows/danger.yml
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
name: Danger CI
|
||||||
|
|
||||||
|
on: [pull_request, merge_group]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Danger main check
|
||||||
|
# Skip in forks, it doesn't work even with the fallback token
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- run: |
|
||||||
|
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||||
|
- name: Danger
|
||||||
|
uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5
|
||||||
|
with:
|
||||||
|
args: "--dangerfile ./tools/danger/dangerfile.js"
|
||||||
|
env:
|
||||||
|
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
|
# Fallback for forks
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
38
.github/workflows/fork-pr-notice.yml
vendored
Normal file
38
.github/workflows/fork-pr-notice.yml
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
name: Community PR notice
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request_target: # zizmor: ignore[dangerous-triggers]
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
welcome:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# Require to comment the PR.
|
||||||
|
pull-requests: write
|
||||||
|
name: Welcome comment
|
||||||
|
# Only display it if base repo (upstream) is different from HEAD repo (possibly a fork)
|
||||||
|
if: github.event.pull_request.base.repo.full_name != github.event.pull_request.head.repo.full_name
|
||||||
|
steps:
|
||||||
|
- name: Add auto-generated commit warning
|
||||||
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: `Thank you for your contribution! Here are a few things to check in the PR to ensure it's reviewed as quickly as possible:
|
||||||
|
|
||||||
|
- If your pull request adds a feature or modifies the UI, this should have an equivalent pull request in the [Element X iOS repo](https://github.com/element-hq/element-x-ios) unless it only affects an Android-only behaviour or is behind a disabled feature flag, since we need parity in both clients to consider a feature done. It will also need to be approved by our product and design teams before being merged, so it's usually a good idea to discuss the changes in a Github issue first and then start working on them once the approach has been validated.
|
||||||
|
- Your branch should be based on \`origin/develop\`, at least when it was created.
|
||||||
|
- The title of the PR will be used for release notes, so it needs to describe the change visible to the user.
|
||||||
|
- The test pass locally running \`./gradlew test\`.
|
||||||
|
- The code quality check suite pass locally running \`./gradlew runQualityChecks\`.
|
||||||
|
- If you modified anything related to the UI, including previews, you'll have to run the \`Record screenshots\` GH action in your forked repo: that will generate compatible new screenshots. However, given Github Actions limitations, **it will prevent the CI from running temporarily**, until you upload a new commit after that one. To do so, just pull the latest changes and push [an empty commit](https://coderwall.com/p/vkdekq/git-commit-allow-empty).`
|
||||||
|
})
|
||||||
42
.github/workflows/generate_github_pages.yml
vendored
Normal file
42
.github/workflows/generate_github_pages.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
name: Generate GitHub Pages
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# At 00:00 on every Tuesday UTC
|
||||||
|
- cron: '0 0 * * 2'
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate-github-pages:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: ⏬ Checkout with LFS
|
||||||
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Set up Python 3.12
|
||||||
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.14
|
||||||
|
- name: Run World screenshots generation script
|
||||||
|
run: |
|
||||||
|
./tools/test/generateWorldScreenshots.py
|
||||||
|
mkdir -p screenshots/en
|
||||||
|
cp tests/uitests/src/test/snapshots/images/* screenshots/en
|
||||||
|
- name: Deploy GitHub Pages
|
||||||
|
uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4.1.0
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: ./screenshots
|
||||||
30
.github/workflows/gradle-wrapper-update.yml
vendored
Normal file
30
.github/workflows/gradle-wrapper-update.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
name: Update Gradle Wrapper
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-gradle-wrapper:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
name: Use JDK 21
|
||||||
|
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Update Gradle Wrapper
|
||||||
|
uses: gradle-update/update-gradle-wrapper-action@512b1875f3b6270828abfe77b247d5895a2da1e5 # v2.1.0
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
|
target-branch: develop
|
||||||
|
labels: PR-Build
|
||||||
149
.github/workflows/maestro-local.yml
vendored
Normal file
149
.github/workflows/maestro-local.yml
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
name: Maestro (local)
|
||||||
|
|
||||||
|
# Run this flow only when APK Build workflow completes
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
ARCH: x86_64
|
||||||
|
DEVICE: pixel_7_pro
|
||||||
|
API_LEVEL: 33
|
||||||
|
TARGET: google_apis
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-apk:
|
||||||
|
name: Build APK
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ${{ format('maestro-build-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
name: Use JDK 21
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Assemble debug APK
|
||||||
|
run: ./gradlew :app:assembleGplayDebug $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
- name: Upload APK as artifact
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-apk-maestro
|
||||||
|
path: |
|
||||||
|
app/build/outputs/apk/gplay/debug/app-gplay-x86_64-debug.apk
|
||||||
|
retention-days: 5
|
||||||
|
overwrite: true
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
maestro-cloud:
|
||||||
|
name: Maestro test suite
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [ build-apk ]
|
||||||
|
# Allow only one to run at a time, since they use the same environment.
|
||||||
|
# Otherwise, tests running in parallel can break each other.
|
||||||
|
concurrency:
|
||||||
|
group: maestro-test
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch'
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Download APK artifact from previous job
|
||||||
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-apk-maestro
|
||||||
|
- name: Enable KVM group perms
|
||||||
|
run: |
|
||||||
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
- name: Install maestro
|
||||||
|
run: curl -fsSL "https://get.maestro.mobile.dev" | bash
|
||||||
|
- name: Run Maestro tests in emulator
|
||||||
|
id: maestro_test
|
||||||
|
uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2.37.0
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
MAESTRO_USERNAME: maestroelement
|
||||||
|
MAESTRO_PASSWORD: ${{ secrets.MATRIX_MAESTRO_ACCOUNT_PASSWORD }}
|
||||||
|
MAESTRO_RECOVERY_KEY: ${{ secrets.MATRIX_MAESTRO_ACCOUNT_RECOVERY_KEY }}
|
||||||
|
MAESTRO_ROOM_NAME: MyRoom
|
||||||
|
MAESTRO_INVITEE1_MXID: "@maestroelement2:matrix.org"
|
||||||
|
MAESTRO_INVITEE2_MXID: "@maestroelement3:matrix.org"
|
||||||
|
MAESTRO_APP_ID: io.element.android.x.debug
|
||||||
|
with:
|
||||||
|
api-level: ${{ env.API_LEVEL }}
|
||||||
|
arch: ${{ env.ARCH }}
|
||||||
|
profile: ${{ env.DEVICE }}
|
||||||
|
target: ${{ env.TARGET }}
|
||||||
|
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||||
|
disable-animations: true
|
||||||
|
disk-size: 3G
|
||||||
|
script: |
|
||||||
|
.github/workflows/scripts/maestro/maestro-local-with-screen-recording.sh app-gplay-x86_64-debug.apk
|
||||||
|
- name: Upload test results
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: test-results
|
||||||
|
path: |
|
||||||
|
~/.maestro/tests/**
|
||||||
|
retention-days: 5
|
||||||
|
overwrite: true
|
||||||
|
if-no-files-found: error
|
||||||
|
- name: Update summary (success)
|
||||||
|
if: steps.maestro_test.outcome == 'success'
|
||||||
|
run: |
|
||||||
|
echo "### Maestro tests worked :rocket:!" >> $GITHUB_STEP_SUMMARY
|
||||||
|
- name: Update summary (failure)
|
||||||
|
if: steps.maestro_test.outcome != 'success'
|
||||||
|
run: |
|
||||||
|
LOG_FILE=$(find ~/.maestro/tests/ -name maestro.log)
|
||||||
|
echo "Log file: $LOG_FILE"
|
||||||
|
LOG_LINES="$(tail -n 30 $LOG_FILE)"
|
||||||
|
echo "### :x: Maestro tests failed...
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
$LOG_LINES
|
||||||
|
\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||||
|
- name: Fail the workflow in case of error in test
|
||||||
|
if: steps.maestro_test.outcome != 'success'
|
||||||
|
run: |
|
||||||
|
echo "Maestro tests failed. Please check the logs."
|
||||||
|
exit 1
|
||||||
66
.github/workflows/nightly.yml
vendored
Normal file
66
.github/workflows/nightly.yml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
name: Build and release nightly application
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# Every nights at 4
|
||||||
|
- cron: "0 4 * * *"
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nightly:
|
||||||
|
name: Build and publish nightly bundle to Firebase
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.repository == 'element-hq/element-x-android' }}
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Build and upload Nightly application
|
||||||
|
run: |
|
||||||
|
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
|
||||||
|
ELEMENT_SDK_SENTRY_DSN: ${{ secrets.ELEMENT_SDK_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
|
||||||
|
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
|
||||||
|
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
|
||||||
|
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
|
||||||
|
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}
|
||||||
|
FIREBASE_TOKEN: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_FIREBASE_TOKEN }}
|
||||||
|
- name: Additionally upload Nightly APK to browserstack for testing
|
||||||
|
continue-on-error: true # don't block anything by this upload failing (for now)
|
||||||
|
run: |
|
||||||
|
curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_PASSWORD" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@app/build/outputs/apk/gplay/nightly/app-gplay-universal-nightly.apk" -F "custom_id=element-x-android-nightly"
|
||||||
|
env:
|
||||||
|
BROWSERSTACK_USERNAME: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_USERNAME }}
|
||||||
|
BROWSERSTACK_PASSWORD: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_ACCESS_KEY }}
|
||||||
98
.github/workflows/nightlyReports.yml
vendored
Normal file
98
.github/workflows/nightlyReports.yml
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
name: Nightly reports
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# Every nights at 5
|
||||||
|
- cron: "0 5 * * *"
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nightlyReports:
|
||||||
|
name: Create kover report artifact and upload sonar result.
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.repository == 'element-hq/element-x-android' }}
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- name: ⏬ Checkout with LFS
|
||||||
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: false
|
||||||
|
|
||||||
|
- name: ⚙️ Run unit tests, debug and release
|
||||||
|
run: ./gradlew test $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
|
||||||
|
- name: 📸 Run screenshot tests
|
||||||
|
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
|
||||||
|
- name: 📈 Generate kover report and verify coverage
|
||||||
|
run: ./gradlew :app:koverXmlReportGplayDebug :app:koverHtmlReportGplayDebug :app:koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
|
||||||
|
- name: ✅ Upload kover report
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: kover-results
|
||||||
|
path: |
|
||||||
|
**/build/reports/kover
|
||||||
|
|
||||||
|
- name: 🔊 Publish results to Sonar
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
if: ${{ always() && env.SONAR_TOKEN != '' && env.ORG_GRADLE_PROJECT_SONAR_LOGIN != '' }}
|
||||||
|
run: ./gradlew assembleDebug createFullJarDebugTestFixtures :app:createFullJarGplayDebugTestFixtures $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
|
||||||
|
# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
|
||||||
|
dependency-analysis:
|
||||||
|
name: Dependency analysis
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Dependency analysis
|
||||||
|
run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload dependency analysis
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: dependency-analysis
|
||||||
|
path: build/reports/dependency-check-report.html
|
||||||
30
.github/workflows/post-release.yml
vendored
Normal file
30
.github/workflows/post-release.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
name: Post-release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
post-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: github.repository == 'element-hq/element-x-android'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Trigger pipeline
|
||||||
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.ENTERPRISE_ACTIONS_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const tag = context.ref.replace('refs/tags/', '');
|
||||||
|
const inputs = { git_tag: tag };
|
||||||
|
await github.rest.actions.createWorkflowDispatch({
|
||||||
|
owner: 'element-hq',
|
||||||
|
repo: 'element-enterprise',
|
||||||
|
workflow_id: 'pipeline-android.yml',
|
||||||
|
ref: 'main',
|
||||||
|
inputs: inputs
|
||||||
|
});
|
||||||
82
.github/workflows/pull_request.yml
vendored
Normal file
82
.github/workflows/pull_request.yml
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
name: Pull Request
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [ opened, edited, labeled, unlabeled, synchronize ]
|
||||||
|
workflow_call: # zizmor: ignore[dangerous-triggers]
|
||||||
|
secrets:
|
||||||
|
ELEMENT_BOT_TOKEN:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
prevent-blocked:
|
||||||
|
name: Prevent blocked
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: read
|
||||||
|
steps:
|
||||||
|
- name: Add notice
|
||||||
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||||
|
if: contains(github.event.pull_request.labels.*.name, 'X-Blocked')
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.setFailed("PR has been labeled with X-Blocked; it cannot be merged.");
|
||||||
|
|
||||||
|
community-prs:
|
||||||
|
name: Label Community PRs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.action == 'opened'
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Check membership
|
||||||
|
if: github.event.pull_request.user.login != 'renovate[bot]'
|
||||||
|
uses: tspascoal/get-user-teams-membership@818140d631d5f29f26b151afbe4179f87d9ceb5e # v4.0.1
|
||||||
|
id: teams
|
||||||
|
with:
|
||||||
|
username: ${{ github.event.pull_request.user.login }}
|
||||||
|
organization: element-hq
|
||||||
|
team: Vector Core
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN_READ_ORG }}
|
||||||
|
- name: Add label
|
||||||
|
if: steps.teams.outputs.isTeamMember == 'false'
|
||||||
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.issues.addLabels({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: ['Z-Community-PR']
|
||||||
|
});
|
||||||
|
|
||||||
|
close-if-fork-develop:
|
||||||
|
name: Forbid develop branch fork contributions
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# Require to comment and close the PR.
|
||||||
|
pull-requests: write
|
||||||
|
if: >
|
||||||
|
github.event.action == 'opened' &&
|
||||||
|
github.event.pull_request.head.ref == 'develop' &&
|
||||||
|
github.event.pull_request.head.repo.full_name != github.repository
|
||||||
|
steps:
|
||||||
|
- name: Close pull request
|
||||||
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: "Thanks for opening this pull request, unfortunately we do not accept contributions from the main" +
|
||||||
|
" branch of your fork, please re-open once you switch to an alternative branch for everyone's sanity.",
|
||||||
|
});
|
||||||
|
|
||||||
|
github.rest.pulls.update({
|
||||||
|
pull_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'closed'
|
||||||
|
});
|
||||||
369
.github/workflows/quality.yml
vendored
Normal file
369
.github/workflows/quality.yml
vendored
Normal file
|
|
@ -0,0 +1,369 @@
|
||||||
|
name: Code Quality Checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
checkScript:
|
||||||
|
name: Search for forbidden patterns
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Run code quality check suite
|
||||||
|
run: ./tools/check/check_code_quality.sh
|
||||||
|
|
||||||
|
checkScreenshot:
|
||||||
|
name: Search for invalid screenshot files
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Set up Python 3.12
|
||||||
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.14
|
||||||
|
- name: Search for invalid screenshot files
|
||||||
|
run: ./tools/test/checkInvalidScreenshots.py
|
||||||
|
|
||||||
|
checkDependencies:
|
||||||
|
name: Search for invalid dependencies
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Set up Python 3.12
|
||||||
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.14
|
||||||
|
- name: Search for invalid dependencies
|
||||||
|
run: ./tools/dependencies/checkDependencies.py
|
||||||
|
|
||||||
|
# Code checks
|
||||||
|
konsist:
|
||||||
|
name: Konsist tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-konsist-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-konsist-develop-{0}', github.sha) || format('check-konsist-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Run Konsist tests
|
||||||
|
run: ./gradlew :tests:konsist:testDebugUnitTest $CI_GRADLE_ARG_PROPERTIES --no-daemon
|
||||||
|
- name: Upload reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: konsist-report
|
||||||
|
path: |
|
||||||
|
**/build/reports/**/*.*
|
||||||
|
|
||||||
|
compose:
|
||||||
|
name: Compose tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-compose-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-compose-develop-{0}', github.sha) || format('check-compose-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Run compose tests
|
||||||
|
run: ./tools/compose/check_stability.sh
|
||||||
|
|
||||||
|
lint:
|
||||||
|
name: Android lint check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-lint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-lint-develop-{0}', github.sha) || format('check-lint-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Build Gplay Debug
|
||||||
|
run: ./gradlew :app:compileGplayDebugKotlin $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Build Fdroid Debug
|
||||||
|
run: ./gradlew :app:compileFdroidDebugKotlin $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Run lint
|
||||||
|
run: ./gradlew :app:lintGplayDebug :app:lintFdroidDebug lintDebug $CI_GRADLE_ARG_PROPERTIES --continue
|
||||||
|
- name: Upload reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: linting-report
|
||||||
|
path: |
|
||||||
|
**/build/reports/**/*.*
|
||||||
|
|
||||||
|
detekt:
|
||||||
|
name: Detekt checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-detekt-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-detekt-develop-{0}', github.sha) || format('check-detekt-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Run Detekt
|
||||||
|
run: ./gradlew detekt $CI_GRADLE_ARG_PROPERTIES --no-daemon
|
||||||
|
- name: Upload reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: detekt-report
|
||||||
|
path: |
|
||||||
|
**/build/reports/**/*.*
|
||||||
|
|
||||||
|
ktlint:
|
||||||
|
name: Ktlint checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-ktlint-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-ktlint-develop-{0}', github.sha) || format('check-ktlint-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Run Ktlint check
|
||||||
|
run: ./gradlew ktlintCheck $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: ktlint-report
|
||||||
|
path: |
|
||||||
|
**/build/reports/**/*.*
|
||||||
|
|
||||||
|
docs:
|
||||||
|
name: Doc checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-docs-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-docs-develop-{0}', github.sha) || format('check-docs-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Run docs check
|
||||||
|
# This is equivalent to `./gradlew checkDocs`, but we avoid having to install java and gradle
|
||||||
|
run: python3 ./tools/docs/generate_toc.py --verify ./*.md docs/**/*.md
|
||||||
|
|
||||||
|
# Note: to auto fix issues you can use the following command:
|
||||||
|
# shellcheck -f diff <files> | git apply
|
||||||
|
shellcheck:
|
||||||
|
name: Check shell scripts
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Run shellcheck
|
||||||
|
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0
|
||||||
|
with:
|
||||||
|
severity: warning
|
||||||
|
|
||||||
|
zizmor:
|
||||||
|
name: Run zizmor
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
|
||||||
|
|
||||||
|
upload_reports:
|
||||||
|
name: Project Check Suite
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [konsist, lint, ktlint, detekt]
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Download reports from previous jobs
|
||||||
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
|
- name: Prepare Danger
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
npm install --save-dev @babel/core
|
||||||
|
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||||
|
yarn add danger-plugin-lint-report --dev
|
||||||
|
- name: Danger lint
|
||||||
|
if: always()
|
||||||
|
uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5
|
||||||
|
with:
|
||||||
|
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
||||||
|
env:
|
||||||
|
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
|
# Fallback for forks
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
72
.github/workflows/recordScreenshots.yml
vendored
Normal file
72
.github/workflows/recordScreenshots.yml
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
name: Record screenshots
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
types: [ labeled ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g -Dsonar.gradle.skipCompile=true
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
record:
|
||||||
|
permissions:
|
||||||
|
# Need write permissions on PRs to remove the label "Record-Screenshots"
|
||||||
|
pull-requests: write
|
||||||
|
contents: write
|
||||||
|
name: Record screenshots on branch ${{ github.event.pull_request.head.ref || github.ref_name }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Record-Screenshots'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- name: Remove Record-Screenshots label
|
||||||
|
if: github.event.label.name == 'Record-Screenshots'
|
||||||
|
uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1.3.0
|
||||||
|
with:
|
||||||
|
labels: Record-Screenshots
|
||||||
|
- name: ⏬ Checkout with LFS (PR)
|
||||||
|
if: github.event.label.name == 'Record-Screenshots'
|
||||||
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref }}
|
||||||
|
- name: ⏬ Checkout with LFS (Branch)
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: ☕️ Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
# Add gradle cache, this should speed up the process
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Record screenshots
|
||||||
|
id: record
|
||||||
|
run: ./.github/workflows/scripts/recordScreenshots.sh
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN || secrets.GITHUB_TOKEN }}
|
||||||
|
GITHUB_REPOSITORY: ${{ secrets.GITHUB_REPOSITORY }}
|
||||||
|
GRADLE_ARGS: ${{ env.CI_GRADLE_ARG_PROPERTIES }}
|
||||||
146
.github/workflows/release.yml
vendored
Normal file
146
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
name: Create release App Bundle and APKs
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
gplay:
|
||||||
|
name: Create App Bundle (Gplay)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ${{ format('build-release-main-gplay-{0}', github.sha) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
- name: Create app bundle
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_SENTRY_DSN: ${{ secrets.ELEMENT_ANDROID_SENTRY_DSN }}
|
||||||
|
ELEMENT_SDK_SENTRY_DSN: ${{ secrets.ELEMENT_SDK_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_SENTRY_DSN: ${{ secrets.ELEMENT_CALL_SENTRY_DSN }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_HOST: ${{ secrets.ELEMENT_CALL_POSTHOG_API_HOST }}
|
||||||
|
ELEMENT_CALL_POSTHOG_API_KEY: ${{ secrets.ELEMENT_CALL_POSTHOG_API_KEY }}
|
||||||
|
ELEMENT_CALL_RAGESHAKE_URL: ${{ secrets.ELEMENT_CALL_RAGESHAKE_URL }}
|
||||||
|
run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload bundle as artifact
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-app-gplay-bundle-unsigned
|
||||||
|
path: |
|
||||||
|
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
|
||||||
|
|
||||||
|
enterprise:
|
||||||
|
name: Create App Bundle Enterprise
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
concurrency:
|
||||||
|
group: ${{ format('build-release-main-enterprise-{0}', github.sha) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
- name: Create Enterprise app bundle
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
run: ./gradlew bundleGplayRelease $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload bundle as artifact
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-enterprise-app-gplay-bundle-unsigned
|
||||||
|
path: |
|
||||||
|
app/build/outputs/bundle/gplayRelease/app-gplay-release.aab
|
||||||
|
|
||||||
|
fdroid:
|
||||||
|
name: Create APKs (FDroid)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ${{ format('build-release-main-fdroid-{0}', github.sha) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
- name: Create APKs
|
||||||
|
env:
|
||||||
|
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_LIGHT_MAP_ID: ${{ secrets.MAPTILER_LIGHT_MAP_ID }}
|
||||||
|
ELEMENT_ANDROID_MAPTILER_DARK_MAP_ID: ${{ secrets.MAPTILER_DARK_MAP_ID }}
|
||||||
|
run: ./gradlew assembleFdroidRelease $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload apks as artifact
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: elementx-app-fdroid-apks-unsigned
|
||||||
|
path: |
|
||||||
|
app/build/outputs/apk/fdroid/release/*.apk
|
||||||
20
.github/workflows/scripts/maestro/local-recording.sh
vendored
Executable file
20
.github/workflows/scripts/maestro/local-recording.sh
vendored
Executable file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
# Copyright 2024 New Vector Ltd.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only.
|
||||||
|
# Please see LICENSE in the repository root for full details.
|
||||||
|
#
|
||||||
|
|
||||||
|
COUNT=0
|
||||||
|
mkdir -p /data/local/tmp/recordings;
|
||||||
|
FILENAME=/data/local/tmp/recordings/testRecording$COUNT.mp4
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
COUNT=$((COUNT+1))
|
||||||
|
FILENAME=/data/local/tmp/recordings/testRecording$COUNT.mp4
|
||||||
|
printf "\nRecording video file #%d\n" $COUNT
|
||||||
|
screenrecord --bugreport --bit-rate=16m --size 720x1280 $FILENAME
|
||||||
|
done
|
||||||
46
.github/workflows/scripts/maestro/maestro-local-with-screen-recording.sh
vendored
Executable file
46
.github/workflows/scripts/maestro/maestro-local-with-screen-recording.sh
vendored
Executable file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
# Copyright 2024 New Vector Ltd.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only.
|
||||||
|
# Please see LICENSE in the repository root for full details.
|
||||||
|
#
|
||||||
|
|
||||||
|
# First we disable the onboarding flow on Chrome, which is a source of issues
|
||||||
|
# (see https://stackoverflow.com/a/64629745)
|
||||||
|
echo "Disabling Chrome onboarding flow"
|
||||||
|
adb shell am set-debug-app --persistent com.android.chrome
|
||||||
|
adb shell 'echo "chrome --disable-fre --no-default-browser-check --no-first-run" > /data/local/tmp/chrome-command-line'
|
||||||
|
adb shell am start -n com.android.chrome/com.google.android.apps.chrome.Main
|
||||||
|
|
||||||
|
adb install -r $1
|
||||||
|
echo "Starting the screen recording..."
|
||||||
|
adb push .github/workflows/scripts/maestro/local-recording.sh /data/local/tmp/
|
||||||
|
adb shell "chmod +x /data/local/tmp/local-recording.sh"
|
||||||
|
mkdir -p ~/.maestro/tests
|
||||||
|
# Start logcat in the background and save the output to a file, use `org.matrix.rust.sdk` tag since the SDK handles the logging
|
||||||
|
adb logcat 'org.matrix.rust.sdk:D *:S' > ~/.maestro/tests/logcat.txt &
|
||||||
|
adb shell "/data/local/tmp/local-recording.sh & echo \$! > /data/local/tmp/screenrecord_pid.txt" &
|
||||||
|
set +e
|
||||||
|
~/.maestro/bin/maestro test .maestro/allTests.yaml
|
||||||
|
TEST_STATUS=$?
|
||||||
|
echo "Test run completed with status $TEST_STATUS"
|
||||||
|
|
||||||
|
# Stop the screen recording loop
|
||||||
|
SCRIPT_PID=$(adb shell "cat /data/local/tmp/screenrecord_pid.txt")
|
||||||
|
adb shell "kill -2 $SCRIPT_PID"
|
||||||
|
|
||||||
|
# Get the PID of the screen recording process
|
||||||
|
SCREENRECORD_PID=$(adb shell ps | grep screenrecord | awk '{print $2}')
|
||||||
|
# Wait for the screen recording process to exit
|
||||||
|
while [ ! -z $SCREENRECORD_PID ]; do
|
||||||
|
echo "Waiting for screen recording ($SCREENRECORD_PID) to finish..."
|
||||||
|
adb shell "kill -2 $SCREENRECORD_PID"
|
||||||
|
sleep 1
|
||||||
|
SCREENRECORD_PID=$(adb shell ps | grep screenrecord | awk '{print $2}')
|
||||||
|
done
|
||||||
|
|
||||||
|
adb pull /data/local/tmp/recordings/ ~/.maestro/tests/
|
||||||
|
exit $TEST_STATUS
|
||||||
77
.github/workflows/scripts/parse_test_failures.py
vendored
Normal file
77
.github/workflows/scripts/parse_test_failures.py
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import sys
|
||||||
|
import glob
|
||||||
|
|
||||||
|
screenshot_test_failures = []
|
||||||
|
output = []
|
||||||
|
|
||||||
|
def parse_test_failures(xml_file):
|
||||||
|
"""Parse XML test results and print failures."""
|
||||||
|
tree = ET.parse(xml_file)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
# Find all testcase elements with failure children
|
||||||
|
if root.get("failures", "0") == "0":
|
||||||
|
return
|
||||||
|
|
||||||
|
name = root.get('name', 'Test Suite')
|
||||||
|
is_screenshot_test = name.startswith('ui.Preview')
|
||||||
|
|
||||||
|
if not is_screenshot_test:
|
||||||
|
output.append(f"## {name}")
|
||||||
|
|
||||||
|
for testcase in root.findall('.//testcase'):
|
||||||
|
failure = testcase.find('failure')
|
||||||
|
if failure is not None:
|
||||||
|
# Get testcase attributes
|
||||||
|
classname = testcase.get('classname', '')
|
||||||
|
name = testcase.get('name', '')
|
||||||
|
|
||||||
|
if is_screenshot_test:
|
||||||
|
# For screenshot tests, we want to display the classname as well
|
||||||
|
screenshot_test_failures.append(f"{classname}.{name}")
|
||||||
|
else:
|
||||||
|
# Get failure content (text inside the failure element)
|
||||||
|
failure_message = failure.get('message', '')
|
||||||
|
failure_content = failure.text if failure.text else ''
|
||||||
|
|
||||||
|
# Print in the requested format
|
||||||
|
output.append(f"### {name}")
|
||||||
|
output.append("```")
|
||||||
|
output.append(failure_message)
|
||||||
|
output.append("```")
|
||||||
|
output.append("<details><summary>Stacktrace</summary>")
|
||||||
|
output.append(f"<pre><code>{failure_content}</code></pre>")
|
||||||
|
output.append("</details>")
|
||||||
|
output.append("\n")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
output.append("Usage: parse_test_failures.py <file>", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
file = sys.argv[1]
|
||||||
|
|
||||||
|
if file.endswith('xml'):
|
||||||
|
parse_test_failures(file)
|
||||||
|
else:
|
||||||
|
files = glob.glob("**/build/test-results/*UnitTest/*.xml", root_dir = file, recursive = True)
|
||||||
|
for file in files:
|
||||||
|
parse_test_failures(file)
|
||||||
|
|
||||||
|
if screenshot_test_failures:
|
||||||
|
output.append("## Screenshot Test Failures")
|
||||||
|
output.append("```")
|
||||||
|
for failure in screenshot_test_failures:
|
||||||
|
output.append(failure)
|
||||||
|
output.append("```")
|
||||||
|
|
||||||
|
text_output = '\n'.join(output)
|
||||||
|
# Trim output larger than 1MB to avoid GitHub Action log limits
|
||||||
|
while len(text_output.encode('utf-8')) > 1_040_000:
|
||||||
|
output.pop(-2)
|
||||||
|
output.append("## !!! Truncated output due to size limits. !!!")
|
||||||
|
text_output = '\n'.join(output)
|
||||||
|
|
||||||
|
print(text_output)
|
||||||
90
.github/workflows/scripts/recordScreenshots.sh
vendored
Executable file
90
.github/workflows/scripts/recordScreenshots.sh
vendored
Executable file
|
|
@ -0,0 +1,90 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
# Copyright 2023-2024 New Vector Ltd.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
# Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TOKEN=$GITHUB_TOKEN
|
||||||
|
REPO=$GITHUB_REPOSITORY
|
||||||
|
|
||||||
|
SHORT=t:,r:
|
||||||
|
LONG=token:,repo:
|
||||||
|
OPTS=$(getopt -a -n recordScreenshots --options $SHORT --longoptions $LONG -- "$@")
|
||||||
|
|
||||||
|
eval set -- "$OPTS"
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-t | --token )
|
||||||
|
TOKEN="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-r | --repo )
|
||||||
|
REPO="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift;
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unexpected option: $1"
|
||||||
|
help
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
echo Branch used: $BRANCH
|
||||||
|
|
||||||
|
if [[ -z ${TOKEN} ]]; then
|
||||||
|
echo "No token specified, either set the env var GITHUB_TOKEN or use the --token option"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${REPO} ]]; then
|
||||||
|
echo "No repo specified, either set the env var GITHUB_REPOSITORY or use the --repo option"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Deleting previous screenshots"
|
||||||
|
./gradlew removeOldSnapshots --stacktrace --warn $GRADLE_ARGS
|
||||||
|
|
||||||
|
echo "Record screenshots"
|
||||||
|
./gradlew recordPaparazziDebug --stacktrace $GRADLE_ARGS
|
||||||
|
|
||||||
|
echo "Deleting previous screenshots"
|
||||||
|
./gradlew removeOldScreenshots --stacktrace --warn $GRADLE_ARGS
|
||||||
|
|
||||||
|
echo "Record screenshots (Compound)"
|
||||||
|
./gradlew :libraries:compound:recordRoborazziDebug --stacktrace -PpreDexEnable=false --max-workers 4 --warn $GRADLE_ARGS
|
||||||
|
|
||||||
|
echo "Committing changes"
|
||||||
|
git config http.sslVerify false
|
||||||
|
|
||||||
|
if [[ -z ${INPUT_AUTHOR_NAME} ]]; then
|
||||||
|
git config user.name "ElementBot"
|
||||||
|
else
|
||||||
|
git config --local user.name "${INPUT_AUTHOR_NAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${INPUT_AUTHOR_EMAIL} ]]; then
|
||||||
|
git config user.email "android@element.io"
|
||||||
|
else
|
||||||
|
git config --local user.name "${INPUT_AUTHOR_EMAIL}"
|
||||||
|
fi
|
||||||
|
git add -A
|
||||||
|
git commit -m "Update screenshots"
|
||||||
|
|
||||||
|
GITHUB_REPO="https://$GITHUB_ACTOR:$TOKEN@github.com/$REPO.git"
|
||||||
|
echo "Pushing changes"
|
||||||
|
if [[ -z ${GITHUB_ACTOR} ]]; then
|
||||||
|
echo "No GITHUB_ACTOR env var"
|
||||||
|
GITHUB_REPO="https://$TOKEN@github.com/$REPO.git"
|
||||||
|
fi
|
||||||
|
git push $GITHUB_REPO "$BRANCH"
|
||||||
|
echo "Done!"
|
||||||
63
.github/workflows/sonar.yml
vendored
Normal file
63
.github/workflows/sonar.yml
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
name: Sonar
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -Dkotlin.daemon.jvm.options=-Xmx4g
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace --warn -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
GROUP: ${{ format('sonar-{0}', github.ref) }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sonar:
|
||||||
|
name: Sonar Quality Checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ format('sonar-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Build debug code and test fixtures
|
||||||
|
run: ./gradlew assembleGplayDebug createFullJarDebugTestFixtures :app:createFullJarGplayDebugTestFixtures $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: 🔊 Publish results to Sonar
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
if: ${{ always() && env.SONAR_TOKEN != '' && env.ORG_GRADLE_PROJECT_SONAR_LOGIN != '' }}
|
||||||
|
run: ./gradlew sonar $CI_GRADLE_ARG_PROPERTIES
|
||||||
24
.github/workflows/stale-issues.yml
vendored
Normal file
24
.github/workflows/stale-issues.yml
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
name: Close stale issues that are missing info.
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 1 * * *"
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||||
|
with:
|
||||||
|
only-labels: "X-Needs-Info"
|
||||||
|
days-before-issue-stale: 30
|
||||||
|
days-before-issue-close: 7
|
||||||
|
days-before-pr-stale: -1
|
||||||
|
stale-issue-label: "stale"
|
||||||
|
labels-to-remove-when-unstale: "X-Needs-Info"
|
||||||
|
stale-issue-message: "This issue has been awaiting further information for the past 30 days so will now be marked as stale. Please provide the requested information within the next 7 days to keep it open."
|
||||||
|
close-issue-message: "This issue is being closed due to inactivity after further information was requested."
|
||||||
52
.github/workflows/sync-localazy.yml
vendored
Normal file
52
.github/workflows/sync-localazy.yml
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
name: Sync Localazy
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# At 00:00 on every Monday UTC
|
||||||
|
- cron: '0 0 * * 1'
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-localazy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
- name: Set up Python 3.12
|
||||||
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.14
|
||||||
|
- name: Setup Localazy
|
||||||
|
run: |
|
||||||
|
curl -sS https://dist.localazy.com/debian/pubkey.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/localazy.gpg
|
||||||
|
echo "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/localazy.gpg] https://maven.localazy.com/repository/apt/ stable main" | sudo tee /etc/apt/sources.list.d/localazy.list
|
||||||
|
sudo apt-get update && sudo apt-get install localazy
|
||||||
|
- name: Run Localazy script
|
||||||
|
run: |
|
||||||
|
./tools/localazy/downloadStrings.sh --all
|
||||||
|
./tools/localazy/importSupportedLocalesFromLocalazy.py
|
||||||
|
./tools/test/generateAllScreenshots.py
|
||||||
|
- name: Create Pull Request for Strings
|
||||||
|
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
|
commit-message: Sync Strings from Localazy
|
||||||
|
title: Sync Strings
|
||||||
|
body: |
|
||||||
|
- Update Strings from Localazy
|
||||||
|
branch: sync-localazy
|
||||||
|
base: develop
|
||||||
|
labels: PR-i18n
|
||||||
40
.github/workflows/sync-sas-strings.yml
vendored
Normal file
40
.github/workflows/sync-sas-strings.yml
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
name: Sync SAS strings
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# At 00:00 on every Monday UTC
|
||||||
|
- cron: '0 0 * * 1'
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-sas-strings:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
# No concurrency required, runs every time on a schedule.
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Set up Python 3.12
|
||||||
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
|
with:
|
||||||
|
python-version: 3.14
|
||||||
|
- name: Install Prerequisite dependencies
|
||||||
|
run: |
|
||||||
|
pip install requests
|
||||||
|
- name: Run SAS String script
|
||||||
|
run: ./tools/sas/import_sas_strings.py
|
||||||
|
- name: Create Pull Request for SAS Strings
|
||||||
|
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||||
|
with:
|
||||||
|
commit-message: Sync SAS Strings
|
||||||
|
title: Sync SAS Strings
|
||||||
|
body: |
|
||||||
|
- Update SAS Strings from matrix-doc.
|
||||||
|
branch: sync-sas-strings
|
||||||
|
base: develop
|
||||||
|
labels: PR-Misc
|
||||||
|
|
||||||
|
|
||||||
116
.github/workflows/tests.yml
vendored
Normal file
116
.github/workflows/tests.yml
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
merge_group:
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx7g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options=-Xmx2g -XX:+UseG1GC
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace --no-daemon -Dsonar.gradle.skipCompile=true --no-configuration-cache
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
name: Runs unit tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Free Disk Space (Ubuntu)
|
||||||
|
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
|
||||||
|
with:
|
||||||
|
# This might remove tools that are actually needed, if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: true
|
||||||
|
# All of these default to true, but we should only need the 'android' one (and maybe swap-storage?)
|
||||||
|
android: false
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
# This takes way too long to run (~2 minutes) and it saves only ~5.5GB
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: false
|
||||||
|
|
||||||
|
# Increase swapfile size to prevent screenshot tests getting terminated
|
||||||
|
# https://github.com/actions/runner-images/discussions/7188#discussioncomment-6750749
|
||||||
|
- name: 💽 Increase swapfile size
|
||||||
|
run: |
|
||||||
|
sudo swapoff -a
|
||||||
|
sudo fallocate -l 8G /mnt/swapfile
|
||||||
|
sudo chmod 600 /mnt/swapfile
|
||||||
|
sudo mkswap /mnt/swapfile
|
||||||
|
sudo swapon /mnt/swapfile
|
||||||
|
sudo swapon --show
|
||||||
|
- name: ⏬ Checkout with LFS
|
||||||
|
uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
with:
|
||||||
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
|
# https://github.com/actions/checkout/issues/881
|
||||||
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
|
- name: Add SSH private keys for submodule repositories
|
||||||
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
with:
|
||||||
|
ssh-private-key: ${{ secrets.ELEMENT_ENTERPRISE_DEPLOY_KEY }}
|
||||||
|
- name: Clone submodules
|
||||||
|
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }}
|
||||||
|
run: git submodule update --init --recursive
|
||||||
|
- name: ☕️ Use JDK 21
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
||||||
|
with:
|
||||||
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
java-version: '21'
|
||||||
|
- name: Configure gradle
|
||||||
|
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||||
|
|
||||||
|
- name: ⚙️ Check coverage for debug variant (includes unit & screenshot tests)
|
||||||
|
run: ./gradlew testDebugUnitTest :tests:uitests:verifyPaparazziDebug :koverXmlReportMerged :koverHtmlReportMerged :koverVerifyAll $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
|
||||||
|
- name: 🚫 Upload kover failed coverage reports
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: kover-error-report
|
||||||
|
path: |
|
||||||
|
app/build/reports/kover
|
||||||
|
|
||||||
|
- name: ✅ Upload kover report (disabled)
|
||||||
|
if: always()
|
||||||
|
run: echo "This is now done only once a day, see nightlyReports.yml"
|
||||||
|
|
||||||
|
- name: 🚫 Upload test results on error
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: tests-and-screenshot-tests-results
|
||||||
|
path: |
|
||||||
|
**/build/paparazzi/failures/
|
||||||
|
**/build/roborazzi/failures/
|
||||||
|
**/build/reports/tests/*UnitTest/
|
||||||
|
|
||||||
|
- name: 🚫 Modify summary on error
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo """## Tests failed!
|
||||||
|
|
||||||
|
""" >> $GITHUB_STEP_SUMMARY
|
||||||
|
python3 .github/workflows/scripts/parse_test_failures.py . >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "---" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# https://github.com/codecov/codecov-action
|
||||||
|
- name: ☂️ Upload coverage reports to codecov
|
||||||
|
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||||
|
with:
|
||||||
|
fail_ci_if_error: true
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
files: build/reports/kover/reportMerged.xml
|
||||||
|
verbose: true
|
||||||
16
.github/workflows/triage-incoming.yml
vendored
Normal file
16
.github/workflows/triage-incoming.yml
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
name: Move new issues onto issue triage board v2
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [ opened ]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
triage-new-issues:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/91
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
87
.github/workflows/triage-labelled.yml
vendored
Normal file
87
.github/workflows/triage-labelled.yml
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
name: Move labelled issues to correct boards and columns
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [labeled]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
move_element_x_issues:
|
||||||
|
name: ElementX issues to ElementX project board
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Skip in forks
|
||||||
|
if: >
|
||||||
|
github.repository == 'element-hq/element-x-android'
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/43
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
move_needs_info:
|
||||||
|
name: Move triaged needs info issues on board
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
id: addItem
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/91
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
labeled: X-Needs-Info
|
||||||
|
- name: Print itemId
|
||||||
|
run: echo ${STEPS_ADDITEM_OUTPUTS_ITEMID}
|
||||||
|
env:
|
||||||
|
STEPS_ADDITEM_OUTPUTS_ITEMID: ${{ steps.addItem.outputs.itemId }}
|
||||||
|
- uses: kalgurn/update-project-item-status@31e54df46a2cdaef4f85c31ac839fbcd2fd7c3a2 # 0.0.3
|
||||||
|
if: ${{ steps.addItem.outputs.itemId }}
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/91
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
item-id: ${{ steps.addItem.outputs.itemId }}
|
||||||
|
status: "Needs info"
|
||||||
|
|
||||||
|
ex_plorers:
|
||||||
|
name: Add labelled issues to X-Plorer project
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'Team: Element X Feature')
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/73
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
verticals_feature:
|
||||||
|
name: Add labelled issues to Verticals Feature project
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'Team: Verticals Feature')
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/57
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
qa:
|
||||||
|
name: Add labelled issues to QA project
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'Team: QA') ||
|
||||||
|
contains(github.event.issue.labels.*.name, 'X-Needs-Signoff')
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/69
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
signoff:
|
||||||
|
name: Add labelled issues to signoff project
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'X-Needs-Signoff')
|
||||||
|
steps:
|
||||||
|
- uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2
|
||||||
|
with:
|
||||||
|
project-url: https://github.com/orgs/element-hq/projects/89
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
15
.github/workflows/validate-lfs.yml
vendored
Normal file
15
.github/workflows/validate-lfs.yml
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
name: Validate Git LFS
|
||||||
|
|
||||||
|
on: [pull_request, merge_group]
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Validate
|
||||||
|
steps:
|
||||||
|
- uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5
|
||||||
|
|
||||||
|
- run: |
|
||||||
|
./tools/git/validate_lfs.sh
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
# gitleaks config — element-x-ada
|
|
||||||
#
|
|
||||||
# Element X is a Matrix client fork with Cardano ADA integration.
|
|
||||||
# Patterns flagged are all public-by-design or doc/test fixtures:
|
|
||||||
# - PostHog apiKey: client-side analytics token, public on every PostHog-
|
|
||||||
# integrated mobile app. Identifies the project, doesn't grant write.
|
|
||||||
# - MapTiler API_KEY: client-side maps token, ships in every release
|
|
||||||
# - google-services.json: Firebase config — Google explicitly documents
|
|
||||||
# this as public-by-design (all real auth goes through FirebaseAuth)
|
|
||||||
# - Segment readKey: client-side write key
|
|
||||||
# - user_signing_key in KDoc comments: example values in doc-strings
|
|
||||||
# - docs/ + *Test.kt files: scratch + test fixtures, never live credentials
|
|
||||||
|
|
||||||
[extend]
|
|
||||||
useDefault = true
|
|
||||||
|
|
||||||
[allowlist]
|
|
||||||
description = "Public client keys (PostHog, MapTiler, Firebase, Segment) + docs + test fixtures"
|
|
||||||
paths = [
|
|
||||||
'''docs/.*''',
|
|
||||||
'''.*/google-services\.json''',
|
|
||||||
'''.*Test\.kt''',
|
|
||||||
'''localazy\.json''',
|
|
||||||
'''tools/localazy/.*''',
|
|
||||||
]
|
|
||||||
regexTarget = "line"
|
|
||||||
regexes = [
|
|
||||||
# PostHog client keys — match any variable name ending in apiKey
|
|
||||||
'''[a-zA-Z]*[Aa]piKey\s*=\s*"phc_[A-Za-z0-9_-]{20,}"''',
|
|
||||||
# MapTiler / similar public client keys named API_KEY constant
|
|
||||||
'''const\s+val\s+API_KEY\s*=\s*"''',
|
|
||||||
# Segment write keys (Kotlin style)
|
|
||||||
'''readKey\s*=\s*"''',
|
|
||||||
# Localazy / Segment readKey (JSON style)
|
|
||||||
'''"readKey"\s*:\s*"''',
|
|
||||||
# Matrix protocol KDoc examples (* prefix is the KDoc comment shape)
|
|
||||||
'''^\s*\*\s*"user_signing_key"\s*:\s*"''',
|
|
||||||
]
|
|
||||||
3
.idea/kotlinc.xml
generated
3
.idea/kotlinc.xml
generated
|
|
@ -1,6 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="2.3.20" />
|
<option name="externalSystemId" value="Gradle" />
|
||||||
|
<option name="version" value="2.3.21" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ appId: ${MAESTRO_APP_ID}
|
||||||
- tapOn:
|
- tapOn:
|
||||||
text: ${MAESTRO_INVITEE1_MXID}
|
text: ${MAESTRO_INVITEE1_MXID}
|
||||||
index: 1
|
index: 1
|
||||||
- tapOn: "Send invite"
|
- tapOn: "Continue"
|
||||||
- takeScreenshot: build/maestro/330-createAndDeleteDM
|
- takeScreenshot: build/maestro/330-createAndDeleteDM
|
||||||
- tapOn: "maestroelement2"
|
- tapOn: "maestroelement2"
|
||||||
- scroll
|
- scroll
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,16 @@ appId: ${MAESTRO_APP_ID}
|
||||||
text: ${MAESTRO_INVITEE2_MXID}
|
text: ${MAESTRO_INVITEE2_MXID}
|
||||||
index: 1
|
index: 1
|
||||||
- tapOn: "Invite"
|
- tapOn: "Invite"
|
||||||
|
- runFlow:
|
||||||
|
when:
|
||||||
|
visible: 'Invite new contact to this room?'
|
||||||
|
commands:
|
||||||
|
- tapOn:
|
||||||
|
id: "confirm_invite_unknown"
|
||||||
|
# Close the keyboard if it's still open
|
||||||
|
- tapOn: "Back"
|
||||||
|
# Go back to the room details screen
|
||||||
- tapOn: "Back"
|
- tapOn: "Back"
|
||||||
- tapOn: "aRoomName"
|
|
||||||
- scrollUntilVisible:
|
- scrollUntilVisible:
|
||||||
direction: DOWN
|
direction: DOWN
|
||||||
element:
|
element:
|
||||||
|
|
|
||||||
221
BLOCKERS.md
221
BLOCKERS.md
|
|
@ -1,221 +0,0 @@
|
||||||
# BLOCKERS.md - Phase 1 Implementation Status
|
|
||||||
|
|
||||||
## Task 1: Module Scaffolding ✅ COMPLETE
|
|
||||||
|
|
||||||
### Completed
|
|
||||||
- ✅ Module structure created (api/impl/test)
|
|
||||||
- ✅ Metro DI setup following Element X patterns
|
|
||||||
- ✅ WalletEntryPoint and WalletState APIs defined
|
|
||||||
- ✅ PaymentFlowNode placeholder with Appyx navigation
|
|
||||||
- ✅ FakeWalletEntryPoint for testing
|
|
||||||
- ✅ Cardano client library dependencies added
|
|
||||||
- ✅ ProGuard rules configured
|
|
||||||
- ✅ Basic unit tests added
|
|
||||||
- ✅ Pushed to Gitea phase1-dev branch
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 2: Key Generation + Storage ✅ COMPLETE
|
|
||||||
|
|
||||||
### Completed
|
|
||||||
- ✅ **CardanoNetworkConfig.kt** - Single object for testnet/mainnet config swap
|
|
||||||
- Currently configured for TESTNET (preprod)
|
|
||||||
- Change `NETWORK` to `CardanoNetwork.MAINNET` for production
|
|
||||||
- All derived values (Koios URL, explorer URL, address prefix) auto-switch
|
|
||||||
|
|
||||||
- ✅ **CardanoKeyStorage** (interface + implementation)
|
|
||||||
- Per-session wallet isolation (key alias: `cardano_wallet_{sessionId}`)
|
|
||||||
- 24-word BIP-39 mnemonic generation using cardano-client-lib
|
|
||||||
- AES-GCM-256 encryption with Android Keystore-backed key
|
|
||||||
- `setUserAuthenticationRequired(true)` - biometric/PIN for every operation
|
|
||||||
- `setUserAuthenticationValidityDurationSeconds(-1)` - no grace period
|
|
||||||
- `setInvalidatedByBiometricEnrollment(true)` - invalidate on biometric change
|
|
||||||
- Methods: `generateWallet`, `importWallet`, `getMnemonic`, `getBaseAddress`, `getStakeAddress`, `deleteWallet`
|
|
||||||
|
|
||||||
- ✅ **CardanoWalletManager** (interface + implementation)
|
|
||||||
- Key derivation using CIP-1852 via cardano-client-lib's Account class
|
|
||||||
- Path `m/1852'/1815'/0'/0/0` for external receiving address
|
|
||||||
- Path `m/1852'/1815'/0'/2/0` for staking key
|
|
||||||
- Shelley base address generation (payment + staking key hash)
|
|
||||||
- Uses CardanoNetworkConfig for network selection
|
|
||||||
- Exposes: `getAddress(sessionId)`, `getStakeAddress(sessionId)`, `getSpendingKey(sessionId)`
|
|
||||||
|
|
||||||
- ✅ **SeedPhraseManager** (interface + implementation)
|
|
||||||
- 24-word mnemonic generation (256-bit entropy)
|
|
||||||
- Support for 12/15/18/21/24 word counts
|
|
||||||
- BIP-39 validation (checksum + wordlist)
|
|
||||||
- Word suggestions for autocomplete
|
|
||||||
- Normalization (whitespace, case)
|
|
||||||
- ⚠️ UI must apply `FLAG_SECURE` when displaying seed phrases (documented)
|
|
||||||
|
|
||||||
- ✅ **FakeCardanoKeyStorage** for testing
|
|
||||||
- ✅ Unit tests for SeedPhraseManager, CardanoNetworkConfig, CardanoWalletManager
|
|
||||||
|
|
||||||
### Decisions Made (per instructions)
|
|
||||||
- Wallet scope: **PER SESSION** (each Matrix account has its own wallet)
|
|
||||||
- Biometric change: **INVALIDATE** key + require wallet re-import/creation
|
|
||||||
- Network: **TESTNET** (preprod) - single config constant for easy mainnet swap
|
|
||||||
|
|
||||||
### Not Verified (No Android SDK in build environment)
|
|
||||||
- ⚠️ Compilation with `./gradlew :features:wallet:impl:assemble`
|
|
||||||
- ⚠️ Unit tests with `./gradlew :features:wallet:impl:test`
|
|
||||||
- ⚠️ ktlint compliance
|
|
||||||
- ⚠️ Actual Android Keystore behavior (requires device/emulator)
|
|
||||||
- ⚠️ Biometric prompt integration (requires Activity context)
|
|
||||||
|
|
||||||
### Security Notes
|
|
||||||
1. **Mnemonic never stored in plaintext** - Always encrypted with Keystore key
|
|
||||||
2. **Key material cleared after use** - `ByteArray.fill(0)` called where possible
|
|
||||||
3. **Per-session isolation** - Different Matrix accounts cannot access each other's wallets
|
|
||||||
4. **Biometric invalidation** - If user adds/removes fingerprints, wallet key becomes invalid
|
|
||||||
5. **No screenshots** - UI must apply FLAG_SECURE when showing seed phrase
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 3: Koios Client ✅ COMPLETE
|
|
||||||
|
|
||||||
### Completed
|
|
||||||
- ✅ **CardanoClient.kt** interface in `api/` module:
|
|
||||||
- `getBalance(address: String): Result<Long>` — balance in lovelace
|
|
||||||
- `getUtxos(address: String): Result<List<Utxo>>` — unspent outputs
|
|
||||||
- `submitTx(signedTxCbor: String): Result<String>` — returns tx hash
|
|
||||||
- `getTxStatus(txHash: String): Result<TxStatus>` — PENDING/CONFIRMED/FAILED
|
|
||||||
|
|
||||||
- ✅ **Data models** in `api/`:
|
|
||||||
- `Utxo.kt` — txHash, outputIndex, amount, address
|
|
||||||
- `TxStatus.kt` — enum PENDING/CONFIRMED/FAILED
|
|
||||||
- `CardanoException.kt` — typed exceptions (NetworkException, RateLimitException, InvalidAddressException, TransactionNotFoundException, SubmissionFailedException, InsufficientFundsException, ApiException)
|
|
||||||
|
|
||||||
- ✅ **KoiosCardanoClient.kt** implementation:
|
|
||||||
- Uses `BackendFactory.getKoiosBackendService()` from cardano-client-lib
|
|
||||||
- Testnet URL: `https://preprod.koios.rest/api/v1` (via CardanoNetworkConfig)
|
|
||||||
- Mainnet URL: `https://api.koios.rest/api/v1` (via CardanoNetworkConfig)
|
|
||||||
- 3 retries with exponential backoff (1s → 2s → 4s, max 10s)
|
|
||||||
- Basic rate limiting (100ms min between requests for Koios 100 req/10s limit)
|
|
||||||
- DI: `@ContributesBinding(SessionScope::class)`
|
|
||||||
- Error parsing: 429 → RateLimitException, 5xx → NetworkException, etc.
|
|
||||||
|
|
||||||
- ✅ **FakeCardanoClient.kt** for testing:
|
|
||||||
- Configurable balances, UTxOs, transaction statuses
|
|
||||||
- Error simulation (network errors, rate limits, submit failures)
|
|
||||||
- Transaction lifecycle simulation (pending → confirmed → failed)
|
|
||||||
- Call counters for test verification
|
|
||||||
- Helper: `setupWallet(address, balance)` creates realistic UTxO set
|
|
||||||
|
|
||||||
- ✅ **KoiosCardanoClientTest.kt** — 15+ unit tests:
|
|
||||||
- getBalance success, unknown address, network error, rate limit
|
|
||||||
- getUtxos success, empty result
|
|
||||||
- submitTx success, failure
|
|
||||||
- getTxStatus pending, confirmed, failed
|
|
||||||
- reset/state management
|
|
||||||
|
|
||||||
- ✅ **CardanoWalletManager updated** to use CardanoClient:
|
|
||||||
- `refreshBalance()` now fetches real balance via Koios
|
|
||||||
- Updates WalletState with lovelace + formatted ADA string
|
|
||||||
|
|
||||||
### Design Notes
|
|
||||||
- **No API key required** — Koios public API is free
|
|
||||||
- **Network config centralized** — Change `CardanoNetworkConfig.NETWORK` to swap testnet/mainnet
|
|
||||||
- **Hex CBOR for submitTx** — Accepts hex-encoded signed transaction bytes
|
|
||||||
- **UTxO pagination** — Limited to first 100 UTxOs (sufficient for typical wallets)
|
|
||||||
|
|
||||||
### Potential Issues
|
|
||||||
- ⚠️ `getTxStatus` returns PENDING for unknown hashes (could be never-submitted or truly pending)
|
|
||||||
- ⚠️ Koios rate limit (100 req/10s) may need adjustment for heavy usage patterns
|
|
||||||
- ⚠️ No getProtocolParameters yet (needed for Task 4 fee calculation)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 4-6: See PHASE1-PLAN.md
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 7: Timeline Payment Card ✅ COMPLETE
|
|
||||||
|
|
||||||
### Completed
|
|
||||||
- ✅ **PaymentCardStatus.kt** — Enum for PENDING/CONFIRMED/FAILED states
|
|
||||||
- ✅ **TimelineItemPaymentContent.kt** — Data class implementing TimelineItemEventContent
|
|
||||||
- amountLovelace, addresses, txHash, status, network, isSentByMe
|
|
||||||
- Computed properties: amountAda, isTestnet, truncatedTxHash, explorerUrl
|
|
||||||
- Companion formatAda() helper
|
|
||||||
- ✅ **TimelineItemPaymentView.kt** — Compose UI for payment card
|
|
||||||
- Cardano icon (₳ symbol)
|
|
||||||
- Amount in ADA (formatted from lovelace)
|
|
||||||
- Status chip with spinner (pending), checkmark (confirmed), X (failed)
|
|
||||||
- Testnet badge when applicable
|
|
||||||
- Truncated tx hash (tappable → CardanoScan)
|
|
||||||
- View on explorer link for confirmed transactions
|
|
||||||
- @PreviewsDayNight with multiple preview states
|
|
||||||
- ✅ **TimelineItemPaymentContentTest.kt** — Unit tests for content model
|
|
||||||
- ✅ **Integration with TimelineItemEventContentView.kt**
|
|
||||||
|
|
||||||
### Design Notes
|
|
||||||
- Payment cards use different colors for sent (primary) vs received (surface)
|
|
||||||
- Explorer URLs: preprod.cardanoscan.io for testnet, cardanoscan.io for mainnet
|
|
||||||
- Tx hash truncated to first 8 + last 8 chars for display
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Task 8: Raw Event Handling ✅ COMPLETE (UPGRADED)
|
|
||||||
|
|
||||||
### ✅ RESOLVED: SDK Raw Event API
|
|
||||||
**Previous blocker:** Matrix Rust SDK did not expose raw event sending or raw JSON access.
|
|
||||||
|
|
||||||
**Resolution:** The SDK (version 26.03.24) now provides:
|
|
||||||
- `Timeline.sendRaw(eventType: String, content: String)` — Sends custom event types
|
|
||||||
- `MsgLikeKind.Other` with `eventType` field — Receives custom events
|
|
||||||
- `TimelineItemDebugInfo.originalJson` — Access to raw event JSON via debug info provider
|
|
||||||
|
|
||||||
**Implementation updated to use proper raw events instead of text markers.**
|
|
||||||
|
|
||||||
### Completed
|
|
||||||
- ✅ **PaymentEventSender.kt** — Interface for sending payment events
|
|
||||||
- ✅ **DefaultPaymentEventSender.kt** — Implementation using raw events
|
|
||||||
- Uses `timeline.sendRaw(eventType, content)` to send custom events
|
|
||||||
- Event type: `co.sulkta.payment.request` (reverse-domain format)
|
|
||||||
- Status updates: `co.sulkta.payment.status`
|
|
||||||
- No text marker hack — proper Matrix custom events
|
|
||||||
- ✅ **TimelineItemContentPaymentFactory.kt** — Parser for payment events
|
|
||||||
- `isPaymentEventType(eventType)` — Checks for payment event type
|
|
||||||
- `isStatusUpdateEventType(eventType)` — Checks for status update type
|
|
||||||
- `createFromRaw(json, isSentByMe)` — Parses raw JSON from custom events
|
|
||||||
- Supports both camelCase and snake_case field names
|
|
||||||
- Graceful error handling — returns null on malformed JSON
|
|
||||||
- ✅ **TimelineEventContentMapper.kt** — Maps `MsgLikeKind.Other` to `CustomEventContent`
|
|
||||||
- ✅ **TimelineItemContentFactory.kt** — Handles `CustomEventContent` for payments
|
|
||||||
- Gets raw JSON via `timelineItemDebugInfoProvider().originalJson`
|
|
||||||
- Delegates to paymentFactory for payment event types
|
|
||||||
- ✅ **CustomEventContent.kt** — New EventContent type for custom events
|
|
||||||
- ✅ **Timeline.sendRaw()** — Added to Timeline interface and RustTimeline implementation
|
|
||||||
- ✅ **FakePaymentEventSender.kt** — Test fake
|
|
||||||
- ✅ **TimelineItemContentPaymentFactoryTest.kt** — Updated unit tests
|
|
||||||
|
|
||||||
### m.replace Status Updates
|
|
||||||
**Decision:** Status updates are sent as separate events of type `co.sulkta.payment.status`.
|
|
||||||
|
|
||||||
**Future improvement:** When SDK exposes event relations, refactor to use m.replace for cleaner status update thread.
|
|
||||||
|
|
||||||
### Benefits of Raw Event Approach
|
|
||||||
- ✅ Proper Matrix protocol compliance (custom event types, not hacked text)
|
|
||||||
- ✅ Non-wallet clients see "Unknown event" instead of JSON-in-text
|
|
||||||
- ✅ Clean separation of payment events from regular messages
|
|
||||||
- ✅ Events won't be indexed by message search
|
|
||||||
- ✅ No message length limits concern
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Known Issues
|
|
||||||
|
|
||||||
### Issue 1: Biometric Prompt Activity Context
|
|
||||||
The `CardanoKeyStorageImpl` uses `setUserAuthenticationRequired(true)` which will cause `UserNotAuthenticatedException` when accessing the key. The biometric prompt UI must be triggered from an Activity/Fragment context before calling `getMnemonic()`, `getSpendingKey()`, etc.
|
|
||||||
|
|
||||||
**Solution:** Task 6 (Payment Flow UI) must call BiometricPrompt before invoking storage operations.
|
|
||||||
|
|
||||||
### Issue 2: KeyPermanentlyInvalidatedException
|
|
||||||
If user changes biometric enrollment, the Keystore key is invalidated. Current behavior: throws exception, user must delete and recreate wallet.
|
|
||||||
|
|
||||||
**Enhancement (future):** Show user-friendly message explaining why wallet became invalid and offer to re-import.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: 2026-03-27 - Task 2 complete*
|
|
||||||
210
CHANGES.md
210
CHANGES.md
|
|
@ -1,3 +1,213 @@
|
||||||
|
Changes in Element X v26.05.2
|
||||||
|
=============================
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at v26.05.2 -->
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
### ✨ Features
|
||||||
|
* Remove SignInWithClassic FeatureFlag to enable the feature. by @bmarty in https://github.com/element-hq/element-x-android/pull/6698
|
||||||
|
* Create a new room when inviting people in a DM by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6756
|
||||||
|
* Remove LiveLocationSharing feature flag by @ganfra in https://github.com/element-hq/element-x-android/pull/6811
|
||||||
|
### 🙌 Improvements
|
||||||
|
* Disable biometric unlock when we disable pin code unlock by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6781
|
||||||
|
### 🐛 Bugfixes
|
||||||
|
* Fix room list duplicate-detection telemetry crashing before it can report by @jennaharris7 in https://github.com/element-hq/element-x-android/pull/6791
|
||||||
|
* Only load full media on media viewer when it's the visible item by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6794
|
||||||
|
* Attempt to fix room list item duplicates at midnight by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6793
|
||||||
|
### 🗣 Translations
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6798
|
||||||
|
### 🧱 Build
|
||||||
|
* Fix Maestro again after changes to the invite flow by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6796
|
||||||
|
* Renovate: Keep Guava on the Android variant and ignore jre-only upgrades by @bmarty in https://github.com/element-hq/element-x-android/pull/6776
|
||||||
|
### Dependency upgrades
|
||||||
|
* Update dependency androidx.compose:compose-bom to v2026.05.00 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6784
|
||||||
|
* Update dependency io.sentry:sentry-android to v8.41.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6787
|
||||||
|
* Update kotlin by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6790
|
||||||
|
* Update camera to v1.6.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6783
|
||||||
|
* Update dependency androidx.webkit:webkit to v1.16.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6786
|
||||||
|
* Update dependency com.google.firebase:firebase-bom to v34.13.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6789
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.18 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6805
|
||||||
|
### Others
|
||||||
|
* Add MIDI playback by @cizra in https://github.com/element-hq/element-x-android/pull/6770
|
||||||
|
* Show error message when using "Sign in with QR code" with a QR from a device that is also not signed in by @hughns in https://github.com/element-hq/element-x-android/pull/6802
|
||||||
|
|
||||||
|
## New Contributors
|
||||||
|
* @jennaharris7 made their first contribution in https://github.com/element-hq/element-x-android/pull/6791
|
||||||
|
* @cizra made their first contribution in https://github.com/element-hq/element-x-android/pull/6770
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.05.1...v26.05.2
|
||||||
|
|
||||||
|
Changes in Element X v26.05.1
|
||||||
|
=============================
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at v26.05.1 -->
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
### ✨ Features
|
||||||
|
* Make Element Call screen work edge-to-edge by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6634
|
||||||
|
### 🙌 Improvements
|
||||||
|
* Stop removing the `logs` dir when clearing cache by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6765
|
||||||
|
* Adapt to new DM definition changes in the SDK by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6748
|
||||||
|
* feat: Update call started timeline item + declined support by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/6649
|
||||||
|
### 🐛 Bugfixes
|
||||||
|
* Improve pin code UX by @bmarty in https://github.com/element-hq/element-x-android/pull/6744
|
||||||
|
* Use just the other user's avatar for DM details by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6738
|
||||||
|
* Improve `FetchPushForegroundService`'s reliability by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6757
|
||||||
|
* Prevent user from starting Live Location Sharing in thread by @bmarty in https://github.com/element-hq/element-x-android/pull/6767
|
||||||
|
* Fix media playback from the timeline broken when exiting a thread by @bmarty in https://github.com/element-hq/element-x-android/pull/6771
|
||||||
|
* Pin code: remove the key if there is no pin code by @bmarty in https://github.com/element-hq/element-x-android/pull/6780
|
||||||
|
### 🗣 Translations
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6761
|
||||||
|
### 🚧 In development 🚧
|
||||||
|
* Feature : share live location by @ganfra in https://github.com/element-hq/element-x-android/pull/6741
|
||||||
|
### Dependency upgrades
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.7 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6746
|
||||||
|
* Update actions/add-to-project action to v2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6758
|
||||||
|
* Update dependency io.github.sergio-sastre.ComposablePreviewScanner:android to v0.9.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6759
|
||||||
|
* Update dependency io.element.android:element-call-embedded to v0.19.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6766
|
||||||
|
* Update metro to v1 (major) by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6720
|
||||||
|
* Update tspascoal/get-user-teams-membership action to v4.0.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6750
|
||||||
|
* Update plugin sonarqube to v7.3.0.8198 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6743
|
||||||
|
* Update plugin dependencycheck to v12.2.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6760
|
||||||
|
* Update dependency com.google.guava:guava to v33.6.0-android by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6646
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.13 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6779
|
||||||
|
### Others
|
||||||
|
* Render media captions formatting in the media viewer by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6729
|
||||||
|
* Reduce FeatureFlag `Knock` effect on room creation and room edition forms by @bmarty in https://github.com/element-hq/element-x-android/pull/6768
|
||||||
|
* Use the right analytics span as a parent in `checkNetworkConnection` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6751
|
||||||
|
* Add missing strings `theme.black` by @bmarty in https://github.com/element-hq/element-x-android/pull/6772
|
||||||
|
* Map back button in web view to esc (revive fixed version of: https://github.com/element-hq/element-x-android/pull/6724) by @toger5 in https://github.com/element-hq/element-x-android/pull/6725
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.05.0...v26.05.1
|
||||||
|
|
||||||
|
Changes in Element X v26.05.0
|
||||||
|
=============================
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at v26.05.0 -->
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
### ✨ Features
|
||||||
|
* Add flag for automatic back pagination feature by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6637
|
||||||
|
* Promote "history sharing on invite" out of developer options by @richvdh in https://github.com/element-hq/element-x-android/pull/6647
|
||||||
|
* Remove RoomDirectorySearch feature flag — always enable the feature by @Copilot in https://github.com/element-hq/element-x-android/pull/6736
|
||||||
|
### 🙌 Improvements
|
||||||
|
* Change native back button behavior in EC view (close settings in EC with os native back) by @toger5 in https://github.com/element-hq/element-x-android/pull/6642
|
||||||
|
* Revert PR #6642 by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6724
|
||||||
|
* Use 'Report a problem' string instead of 'Report bug' by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6735
|
||||||
|
### 🐛 Bugfixes
|
||||||
|
* Remove distributed tracing of the 'timeline loading' flow by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6644
|
||||||
|
* Set max lines for 'in reply to' view conditionally by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6612
|
||||||
|
* Mention pill cut off by @bmarty in https://github.com/element-hq/element-x-android/pull/6651
|
||||||
|
* Ensure that bottom sheet can scroll by @bmarty in https://github.com/element-hq/element-x-android/pull/6661
|
||||||
|
* Remove legacy `mx-reply` from `toPlainText` formatted event contents by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6683
|
||||||
|
* Fix ANRs when receiving push notifications by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6696
|
||||||
|
* Mitigate a deadlock when loading room timelines by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6674
|
||||||
|
* Fix calls on Huawei devices: skip addWebMessageListener on Chromium < 119 by @manfrommedan in https://github.com/element-hq/element-x-android/pull/6640
|
||||||
|
* Allow cancelling room loading in Home screen by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6723
|
||||||
|
* Let our Json parser accept comments and trailing comma. by @bmarty in https://github.com/element-hq/element-x-android/pull/6700
|
||||||
|
* Fix low width image message by @krbns in https://github.com/element-hq/element-x-android/pull/6692
|
||||||
|
* Make icons in the Chat screen top bar 16dp by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6733
|
||||||
|
* Fix back button sometimes not working after exiting a thread by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6732
|
||||||
|
* Make send event state UI easier to click by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6739
|
||||||
|
### 🗣 Translations
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6658
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6716
|
||||||
|
### 🧱 Build
|
||||||
|
* Fix record screenshots action permissions by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6679
|
||||||
|
* Fix dependency error by @bmarty in https://github.com/element-hq/element-x-android/pull/6697
|
||||||
|
### 🚧 In development 🚧
|
||||||
|
* [Link new device] Add missing screen to render digits that the user has to type on the other device by @bmarty in https://github.com/element-hq/element-x-android/pull/6680
|
||||||
|
### Dependency upgrades
|
||||||
|
* Update dependency io.nlopez.compose.rules:detekt to v0.5.7 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6594
|
||||||
|
* Update zizmorcore/zizmor-action action to v0.5.3 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6630
|
||||||
|
* Update dependency io.sentry:sentry-android to v8.38.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6597
|
||||||
|
* fix(deps): update camera to v1.6.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6514
|
||||||
|
* Update dependency io.sentry:sentry-android to v8.39.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6648
|
||||||
|
* Update dependency io.element.android:element-call-embedded to v0.19.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6662
|
||||||
|
* Update dependencyAnalysis to v3.9.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6657
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.04.27 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6666
|
||||||
|
* Update dependency io.sentry:sentry-android to v8.40.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6691
|
||||||
|
* Update dependency org.jsoup:jsoup to v1.22.2 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6660
|
||||||
|
* Update kotlin by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6687
|
||||||
|
* Update dependency androidx.compose:compose-bom to v2026.04.01 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6693
|
||||||
|
* Update dependency io.nlopez.compose.rules:detekt to v0.5.8 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6711
|
||||||
|
* Update dependency com.posthog:posthog-android to v3.43.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6704
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.4 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6718
|
||||||
|
* Update roborazzi to v1.60.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6722
|
||||||
|
* Update dependency net.zetetic:sqlcipher-android to v4.15.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6727
|
||||||
|
* Update dependency org.maplibre.gl:android-sdk to v13.1.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6731
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.05.6 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6734
|
||||||
|
* Update dependencyAnalysis to v3.10.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6742
|
||||||
|
* Update tspascoal/get-user-teams-membership action to v4 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6747
|
||||||
|
### Others
|
||||||
|
* devx: fix build sdk script options for macos by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/6636
|
||||||
|
* PR:Fix mention pill cut off by @krbns in https://github.com/element-hq/element-x-android/pull/6622
|
||||||
|
* Update media viewer UI by @bmarty in https://github.com/element-hq/element-x-android/pull/6643
|
||||||
|
* Strip formatting from media captions in room summary by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6670
|
||||||
|
* Update error mappings for Link new device flow by @hughns in https://github.com/element-hq/element-x-android/pull/6677
|
||||||
|
* Rename `OIDC` components and variables to `OAuth` by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6686
|
||||||
|
* [Link new device] Add missing error case "already signed in" by @bmarty in https://github.com/element-hq/element-x-android/pull/6688
|
||||||
|
* Improve detection of completion for Link new device flow by @hughns in https://github.com/element-hq/element-x-android/pull/6681
|
||||||
|
* Remove external call support by @bmarty in https://github.com/element-hq/element-x-android/pull/6668
|
||||||
|
* [a11y] Fix a set of issues by @bmarty in https://github.com/element-hq/element-x-android/pull/6650
|
||||||
|
* Add clipping to RoomSummaryRow by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6654
|
||||||
|
* Fix media viewer flickering and crashing by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6715
|
||||||
|
* Rename verification methods by @bmarty in https://github.com/element-hq/element-x-android/pull/6726
|
||||||
|
* Add a way to tweak MAS url. by @bmarty in https://github.com/element-hq/element-x-android/pull/6682
|
||||||
|
* Fix 2 x Crash the app in Developer Options - Update AppDeveloperSettingsView.kt by @escix in https://github.com/element-hq/element-x-android/pull/6708
|
||||||
|
* Introduce UI sample by @bmarty in https://github.com/element-hq/element-x-android/pull/6740
|
||||||
|
|
||||||
|
## New Contributors
|
||||||
|
* @krbns made their first contribution in https://github.com/element-hq/element-x-android/pull/6622
|
||||||
|
* @toger5 made their first contribution in https://github.com/element-hq/element-x-android/pull/6642
|
||||||
|
* @manfrommedan made their first contribution in https://github.com/element-hq/element-x-android/pull/6640
|
||||||
|
* @Copilot made their first contribution in https://github.com/element-hq/element-x-android/pull/6736
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.04.4...v26.05.0
|
||||||
|
|
||||||
|
Changes in Element X v26.04.4
|
||||||
|
=============================
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at v26.04.4 -->
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
### 🙌 Improvements
|
||||||
|
* Natural media viewer swiping order by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6431
|
||||||
|
* Replace `rustls-platform-verifier-android.aar` with single class by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6610
|
||||||
|
* Cleanup FetchPushForegroundService by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6577
|
||||||
|
* cleaning: Remove join button from call notify timelineItemView by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/6603
|
||||||
|
### 🐛 Bugfixes
|
||||||
|
* Fix crash when going back to threads list by @bxdxnn in https://github.com/element-hq/element-x-android/pull/6620
|
||||||
|
* audio: Let EC decide alone what communication device to use by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/6609
|
||||||
|
* Fix media viewer bottom sheets not being scrollable by @jmartinesp in https://github.com/element-hq/element-x-android/pull/6631
|
||||||
|
### 🗣 Translations
|
||||||
|
* Sync Strings by @ElementBot in https://github.com/element-hq/element-x-android/pull/6626
|
||||||
|
### 📄 Documentation
|
||||||
|
* Updates to new features and some refactoring. by @mxandreas in https://github.com/element-hq/element-x-android/pull/6591
|
||||||
|
### 🚧 In development 🚧
|
||||||
|
* WIP : live location rendering by @ganfra in https://github.com/element-hq/element-x-android/pull/6611
|
||||||
|
### Dependency upgrades
|
||||||
|
* Update dependency io.element.android:element-call-embedded to v0.19.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6593
|
||||||
|
* Update dependency androidx.annotation:annotation-jvm to v1.10.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6596
|
||||||
|
* Update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.11.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6605
|
||||||
|
* Update dependency com.google.firebase:firebase-bom to v34.12.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6604
|
||||||
|
* Update actions/upload-artifact action to v7.0.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6614
|
||||||
|
* Update plugin dependencycheck to v12.2.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6621
|
||||||
|
* Update actions/github-script action to v9 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6606
|
||||||
|
* Update peter-evans/create-pull-request action to v8.1.1 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6615
|
||||||
|
* Update dependencyAnalysis to v3.7.0 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6616
|
||||||
|
* Update dependency org.matrix.rustcomponents:sdk-android to v26.04.21 by @renovate[bot] in https://github.com/element-hq/element-x-android/pull/6635
|
||||||
|
### Others
|
||||||
|
* Settings UI update. by @bmarty in https://github.com/element-hq/element-x-android/pull/6602
|
||||||
|
* Support replying to messages with voice recordings by @kalix127 in https://github.com/element-hq/element-x-android/pull/6464
|
||||||
|
* Add Black theme option for battery saving on OLED displays by @timurgilfanov in https://github.com/element-hq/element-x-android/pull/6441
|
||||||
|
* Fix | When selecting earpiece twice in a row the proximity sensor get wrongly disabled by @BillCarsonFr in https://github.com/element-hq/element-x-android/pull/6627
|
||||||
|
* Update wording of deactivate account screen by @bmarty in https://github.com/element-hq/element-x-android/pull/6633
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/element-hq/element-x-android/compare/v26.04.3...v26.04.4
|
||||||
|
|
||||||
Changes in Element X v26.04.3
|
Changes in Element X v26.04.3
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
|
|
|
||||||
102
CONTRIBUTING.md
102
CONTRIBUTING.md
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
<!--- TOC -->
|
<!--- TOC -->
|
||||||
|
|
||||||
* [Developer onboarding](#developer-onboarding)
|
* [Contributing to Element](#contributing-to-element)
|
||||||
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
|
||||||
* [Android Studio settings](#android-studio-settings)
|
|
||||||
* [Compilation](#compilation)
|
|
||||||
* [Strings](#strings)
|
|
||||||
* [I want to add new strings to the project](#i-want-to-add-new-strings-to-the-project)
|
|
||||||
* [I want to help translating Element](#i-want-to-help-translating-element)
|
* [I want to help translating Element](#i-want-to-help-translating-element)
|
||||||
|
* [I want to fix a bug](#i-want-to-fix-a-bug)
|
||||||
|
* [I want to add a new feature or enhancement](#i-want-to-add-a-new-feature-or-enhancement)
|
||||||
|
* [Developer onboarding](#developer-onboarding)
|
||||||
|
* [Submitting the PRs](#submitting-the-prs)
|
||||||
|
* [Android Studio settings](#android-studio-settings)
|
||||||
|
* [Compilation](#compilation)
|
||||||
|
* [Strings](#strings)
|
||||||
* [Element X Android Gallery](#element-x-android-gallery)
|
* [Element X Android Gallery](#element-x-android-gallery)
|
||||||
* [I want to add a new feature to Element X Android](#i-want-to-add-a-new-feature-to-element-x-android)
|
|
||||||
* [I want to submit a PR to fix an issue](#i-want-to-submit-a-pr-to-fix-an-issue)
|
|
||||||
* [Kotlin](#kotlin)
|
* [Kotlin](#kotlin)
|
||||||
* [Changelog](#changelog)
|
* [Changelog](#changelog)
|
||||||
* [Code quality](#code-quality)
|
* [Code quality](#code-quality)
|
||||||
|
|
@ -29,69 +29,67 @@
|
||||||
|
|
||||||
<!--- END -->
|
<!--- END -->
|
||||||
|
|
||||||
## Developer onboarding
|
## Contributing to Element
|
||||||
|
|
||||||
For a detailed overview of the project, see [Developer Onboarding](./docs/_developer_onboarding.md).
|
|
||||||
|
|
||||||
## Contributing code to Matrix
|
|
||||||
|
|
||||||
If instead of contributing to the Element X Android project, you want to contribute to Synapse, the homeserver implementation, please read the [Synapse contribution guide](https://element-hq.github.io/synapse/latest/development/contributing_guide.html).
|
|
||||||
|
|
||||||
Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
|
Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
|
||||||
|
|
||||||
The rest of the document contains specific rules for Matrix Android projects.
|
The rest of the document contains specific rules for Matrix Android projects.
|
||||||
|
|
||||||
## Android Studio settings
|
|
||||||
|
|
||||||
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
|
|
||||||
Please ensure that you're using the project formatting rules (which are in the project at .idea/codeStyles/), and format the file before committing them.
|
|
||||||
|
|
||||||
## Compilation
|
|
||||||
|
|
||||||
This project should compile without any special action. Just clone it and open it with Android Studio, or compile from command line using `gradlew`.
|
|
||||||
|
|
||||||
## Strings
|
|
||||||
|
|
||||||
The strings of the project are managed externally using [https://localazy.com](https://localazy.com) and shared with Element X iOS.
|
|
||||||
|
|
||||||
### I want to add new strings to the project
|
|
||||||
|
|
||||||
Only the core team can modify or add English strings to Localazy. As an external contributor, if you want to add new strings, feel free to add an Android resource file to the project (for instance a file named `temporary.xml`), with a note in the description of the PR for the reviewer to integrate the String into `Localazy`. If accepted, the reviewer will add the String(s) for you, and then you can download them on your branch (following these [instructions](./tools/localazy/README.md#download-translations)) and remove the temporary file.
|
|
||||||
|
|
||||||
Please follow the naming rules for the key. More details in [the dedicated section in this README.md](./tools/localazy/README.md#key-naming-rules)
|
|
||||||
|
|
||||||
### I want to help translating Element
|
### I want to help translating Element
|
||||||
|
|
||||||
To help translating, please go to [https://localazy.com/p/element](https://localazy.com/p/element).
|
To help translating, please go to [https://localazy.com/p/element](https://localazy.com/p/element).
|
||||||
|
|
||||||
- If you want to fix an issue with an English string, please open an issue on the github project of Element X (Android or iOS). Only the core team can modify or add English strings.
|
|
||||||
- If you want to fix an issue in other languages, or add a missing translation, or even add a new language, please go to [https://localazy.com/p/element](https://localazy.com/p/element).
|
- If you want to fix an issue in other languages, or add a missing translation, or even add a new language, please go to [https://localazy.com/p/element](https://localazy.com/p/element).
|
||||||
|
- If you want to fix an issue with an English string, please open an issue on the github project of Element X (Android or iOS). Only the core team can modify or add English strings. As an external contributor, if you want to add new strings, feel free to add an Android resource file to the project (for instance a file named `temporary.xml`), with a note in the description of the PR for the reviewer to integrate the String into `Localazy`. If accepted, the reviewer will add the String(s) for you, and then you can download them on your branch (following these [instructions](./tools/localazy/README.md#download-translations)) and remove the temporary file. Please follow the naming rules for the key. More details in [the dedicated section in this README.md](./tools/localazy/README.md#key-naming-rules) More information can be found [in this README.md](./tools/localazy/README.md).
|
||||||
More information can be found [in this README.md](./tools/localazy/README.md).
|
|
||||||
|
|
||||||
Once a language is sufficiently translated, it will be added to the app. The core team will decide when a language is sufficiently translated.
|
Once a language is sufficiently translated, it will be added to the app. The core team will decide when a language is sufficiently translated.
|
||||||
|
|
||||||
|
### I want to fix a bug
|
||||||
|
|
||||||
|
Please check if a corresponding issue exists, if not please create one. In both cases, let us know in the comment that you've started working on it.
|
||||||
|
|
||||||
|
### I want to add a new feature or enhancement
|
||||||
|
|
||||||
|
To make a great product with a great user experience, all the small efforts need to go in the same direction and be aligned and consistent with each other.
|
||||||
|
|
||||||
|
Before making your contribution, please consider the following:
|
||||||
|
|
||||||
|
* One product can’t do everything well. Element is focusing on private end-to-end encrypted messaging and voice - this can either be for consumers (e.g. friends and family) or for professional teams and organizations. Public forums and other types of chats without E2EE remain supported but are not the primary use case in case UX compromises need to be made.
|
||||||
|
* There are 3 platforms - Android, [iOS](https://github.com/element-hq/element-x-ios) and [Web/Desktop](https://github.com/element-hq/element-web). These platforms need to have feature parity and design consistency. For some features, supporting all platforms is a must have, in some cases exceptions can be made to have it on one platform only.
|
||||||
|
* To make sure your idea fits both from a design/solution and use case perspective, please open a new issue (or find an existing issue) in [element-meta](https://github.com/element-hq/element-meta/issues) repository describing the use case and how you plan to tackle it. Do not just describe what feature is missing, explain why the users need it with a couple of real life examples from the field.
|
||||||
|
* In case of an existing issue, please comment that you're planning to contribute. If you create a new issue, please specify that in the issue. In such a case we will try to review the issue ASAP and provide you with initial feedback so you can be confident if and at which conditions your contributions will be accepted.
|
||||||
|
|
||||||
|
Once we know that you want to contribute and have confirmed that the new feature is overall aligned with the product direction, the designers of the core team will help you with the designs and any other type of guidance when it comes to the user experience. We will try to unblock you as quickly as we can, but it may not be instant. Having a clear understanding of the use case and the impact of the feature will help us with the prioritization and faster responses.
|
||||||
|
|
||||||
|
Only once all of the above is met should you open a PR with your proposed changes.
|
||||||
|
|
||||||
|
## Developer onboarding
|
||||||
|
|
||||||
|
For a detailed overview of the project, see [Developer Onboarding](./docs/_developer_onboarding.md).
|
||||||
|
|
||||||
|
### Submitting the PRs
|
||||||
|
|
||||||
|
Please have a look in the [dedicated documentation](./docs/pull_request.md) about pull request.
|
||||||
|
|
||||||
|
### Android Studio settings
|
||||||
|
|
||||||
|
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
|
||||||
|
Please ensure that you're using the project formatting rules (which are in the project at .idea/codeStyles/), and format the file before committing them.
|
||||||
|
|
||||||
|
### Compilation
|
||||||
|
|
||||||
|
This project should compile without any special action. Just clone it and open it with Android Studio, or compile from command line using `gradlew`.
|
||||||
|
|
||||||
|
### Strings
|
||||||
|
|
||||||
|
The strings of the project are managed externally using [https://localazy.com](https://localazy.com) and shared with Element X iOS.
|
||||||
|
|
||||||
### Element X Android Gallery
|
### Element X Android Gallery
|
||||||
|
|
||||||
Once added to Localazy, translations can be checked screen per screen using our tool Element X Android Gallery, available at https://element-hq.github.io/element-x-android/.
|
Once added to Localazy, translations can be checked screen per screen using our tool Element X Android Gallery, available at https://element-hq.github.io/element-x-android/.
|
||||||
|
|
||||||
Localazy syncs occur every Monday and the screenshots on this page are generated every Tuesday, so you'll have to wait to see your change appearing on Element X Android Gallery.
|
Localazy syncs occur every Monday and the screenshots on this page are generated every Tuesday, so you'll have to wait to see your change appearing on Element X Android Gallery.
|
||||||
|
|
||||||
## I want to add a new feature to Element X Android
|
|
||||||
|
|
||||||
Thank you for contributing to the project! Please have a look in the [dedicated documentation](./docs/pull_request.md) about pull request.
|
|
||||||
|
|
||||||
Also, please keep in mind that any feature added to Element X Android needs to be added to [the iOS client](https://github.com/element-hq/element-x-ios) too, unless it's related to an Android OS only behaviour.
|
|
||||||
|
|
||||||
**IMPORTANT:** if you are adding new screens or modifying existing ones, this needs acceptance from the product and design teams before being merged. For this, it's better to start with a [feature request issue](https://github.com/element-hq/element-x-android/issues/new?template=enhancement.yml) describing the change you want to make and the motivation behind it instead of directly creating a pull request. This will allow the product and design teams to give feedback on the change before you start working on it, and avoid you doing work that might end up being rejected.
|
|
||||||
|
|
||||||
## I want to submit a PR to fix an issue
|
|
||||||
|
|
||||||
Please have a look in the [dedicated documentation](./docs/pull_request.md) about pull request.
|
|
||||||
|
|
||||||
Please check if a corresponding issue exists. If yes, please let us know in a comment that you're working on it.
|
|
||||||
If an issue does not exist yet, it may be relevant to open a new issue and let us know that you're implementing it.
|
|
||||||
|
|
||||||
### Kotlin
|
### Kotlin
|
||||||
|
|
||||||
This project is full Kotlin. Please do not write Java classes.
|
This project is full Kotlin. Please do not write Java classes.
|
||||||
|
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
# Phase 1 Status — COMPLETE ✅
|
|
||||||
|
|
||||||
## Verification Date
|
|
||||||
2026-03-28
|
|
||||||
|
|
||||||
## What Was Verified
|
|
||||||
- APK: `app-gplay-x86_64-debug.apk` built from `phase1-dev` branch
|
|
||||||
- Installed on Android emulator `budtmo/docker-android:emulator_14.0` (emulator-5554)
|
|
||||||
- Signed in as `@testbot-elementx:sulkta.com` via OIDC (MAS at mas.sulkta.com)
|
|
||||||
- Opened DM room with `@cobb:sulkta.com`
|
|
||||||
- Typed `/pay` in message composer
|
|
||||||
|
|
||||||
## Result
|
|
||||||
✅ Slash command autocomplete appeared showing:
|
|
||||||
- Command: `/pay`
|
|
||||||
- Description: "Send ADA to someone"
|
|
||||||
|
|
||||||
## Phase 1 Bar (Option A) — All Conditions Met
|
|
||||||
- [x] App launches without crash
|
|
||||||
- [x] `/pay` appears in slash command autocomplete
|
|
||||||
- [x] Payment screens navigable (wired in DI graph)
|
|
||||||
- [x] No live testnet transaction required
|
|
||||||
|
|
||||||
## Build Info
|
|
||||||
- Gradle task: `:app:assembleGplayDebug`
|
|
||||||
- Branch: `phase1-dev`
|
|
||||||
- Final commit: `ad89eddfea`
|
|
||||||
- Build image: `mingc/android-build-box:latest` (Java 21)
|
|
||||||
|
|
||||||
## Key Fixes Applied
|
|
||||||
1. Metro DI scope mismatch: CardanoWalletManager removed CardanoClient dep (AppScope vs SessionScope)
|
|
||||||
2. WalletState constructor: all required fields populated
|
|
||||||
3. Packaging conflict: moshi-kotlin-codegen/lombok META-INF pickFirst
|
|
||||||
4. Build flavor: assembleGplayDebug (not fdroid, not plain assembleDebug)
|
|
||||||
78
SYNC.md
78
SYNC.md
|
|
@ -1,78 +0,0 @@
|
||||||
# Repo topology + upstream sync procedure
|
|
||||||
|
|
||||||
This repo is a fork of [`element-hq/element-x-android`](https://github.com/element-hq/element-x-android)
|
|
||||||
with a native Cardano wallet module added. The history is structured so that
|
|
||||||
staying current with upstream — and one day proposing our additions back —
|
|
||||||
stays possible.
|
|
||||||
|
|
||||||
## Branches
|
|
||||||
|
|
||||||
| Branch | Role |
|
|
||||||
|--------|------|
|
|
||||||
| `main` | Tracks the upstream commit we are currently based on. Fast-forwarded to `upstream/develop` when we deliberately pull in changes. Nothing coop-specific lives here. |
|
|
||||||
| `wallet` | `main` + all our wallet work. This is what we build APKs from. Linear history on top of `main`; rebased whenever `main` moves. |
|
|
||||||
| `archive/project-docs` | Frozen snapshot of the planning docs and screenshots that lived on the original orphan `main` branch. Not part of the active graph. |
|
|
||||||
|
|
||||||
When we ever want a clean "everything we'd propose upstream" branch, we cherry-pick
|
|
||||||
the wallet commits off `wallet` onto a fresh branch rooted at `main`. Because every
|
|
||||||
current commit on `wallet` is wallet-module work, that split is simple.
|
|
||||||
|
|
||||||
## Remotes
|
|
||||||
|
|
||||||
`origin` → this Gitea repo (LAN, via the Rackham SSH tunnel when working remotely).
|
|
||||||
|
|
||||||
Add upstream on any local clone:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote add upstream https://github.com/element-hq/element-x-android.git
|
|
||||||
git fetch upstream
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sync with upstream
|
|
||||||
|
|
||||||
When you want to pick up the latest from `element-hq/element-x-android`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Get the latest from upstream
|
|
||||||
git fetch upstream
|
|
||||||
|
|
||||||
# 2. Fast-forward main to upstream/develop
|
|
||||||
git checkout main
|
|
||||||
git merge --ff-only upstream/develop
|
|
||||||
git push origin main
|
|
||||||
|
|
||||||
# 3. Rebase wallet onto the new main
|
|
||||||
git checkout wallet
|
|
||||||
git rebase main
|
|
||||||
# → resolve conflicts, one commit at a time
|
|
||||||
# → conflict surface is small but real: our integration touches
|
|
||||||
# libraries/matrix/{api,impl}, libraries/textcomposer/impl,
|
|
||||||
# libraries/eventformatter/impl, libraries/mediaviewer/impl
|
|
||||||
|
|
||||||
# 4. Build + test the APK before force-pushing
|
|
||||||
./gradlew :app:assembleFdroidDebug # or mainnet variant
|
|
||||||
|
|
||||||
# 5. Push the rebased wallet branch (force-with-lease, not plain force)
|
|
||||||
git push --force-with-lease origin wallet
|
|
||||||
```
|
|
||||||
|
|
||||||
If the rebase gets ugly, abort and try merging instead:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rebase --abort
|
|
||||||
git merge upstream/develop
|
|
||||||
# resolves in one shot, one merge commit, less clean history
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why not a Gitea mirror?
|
|
||||||
|
|
||||||
Gitea only lets you configure a pull-mirror at repo-creation time, and mirroring
|
|
||||||
a whole repo also means we can't commit to it. We want to keep our own commits,
|
|
||||||
so upstream stays as a git remote you fetch from manually.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Upstream is **AGPL-3.0**. Every binary we hand out must be accompanied by the
|
|
||||||
corresponding source under the same license. Keeping this Gitea repo accessible
|
|
||||||
to recipients of the APK satisfies that. Don't ship binaries without also making
|
|
||||||
the source reachable.
|
|
||||||
|
|
@ -103,13 +103,13 @@ android {
|
||||||
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]")
|
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]")
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
val oidcRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
|
val oAuthRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
|
||||||
getByName("debug") {
|
getByName("debug") {
|
||||||
resValue("string", "app_name", "$baseAppName dbg")
|
resValue("string", "app_name", "$baseAppName dbg")
|
||||||
resValue(
|
resValue(
|
||||||
"string",
|
"string",
|
||||||
"login_redirect_scheme",
|
"login_redirect_scheme",
|
||||||
"$oidcRedirectSchemeBase.debug",
|
"$oAuthRedirectSchemeBase.debug",
|
||||||
)
|
)
|
||||||
applicationIdSuffix = ".debug"
|
applicationIdSuffix = ".debug"
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
|
@ -120,7 +120,7 @@ android {
|
||||||
resValue(
|
resValue(
|
||||||
"string",
|
"string",
|
||||||
"login_redirect_scheme",
|
"login_redirect_scheme",
|
||||||
oidcRedirectSchemeBase,
|
oAuthRedirectSchemeBase,
|
||||||
)
|
)
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ android {
|
||||||
resValue(
|
resValue(
|
||||||
"string",
|
"string",
|
||||||
"login_redirect_scheme",
|
"login_redirect_scheme",
|
||||||
"$oidcRedirectSchemeBase.nightly",
|
"$oAuthRedirectSchemeBase.nightly",
|
||||||
)
|
)
|
||||||
matchingFallbacks += listOf("release")
|
matchingFallbacks += listOf("release")
|
||||||
signingConfig = signingConfigs.getByName("nightly")
|
signingConfig = signingConfigs.getByName("nightly")
|
||||||
|
|
@ -208,7 +208,6 @@ android {
|
||||||
packaging {
|
packaging {
|
||||||
resources.pickFirsts += setOf(
|
resources.pickFirsts += setOf(
|
||||||
"META-INF/versions/9/OSGI-INF/MANIFEST.MF",
|
"META-INF/versions/9/OSGI-INF/MANIFEST.MF",
|
||||||
"META-INF/gradle/incremental.annotation.processors",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
jniLibs {
|
jniLibs {
|
||||||
|
|
@ -316,11 +315,6 @@ licensee {
|
||||||
allowUrl("https://asm.ow2.io/license.html")
|
allowUrl("https://asm.ow2.io/license.html")
|
||||||
allowUrl("https://www.gnu.org/licenses/agpl-3.0.txt")
|
allowUrl("https://www.gnu.org/licenses/agpl-3.0.txt")
|
||||||
allowUrl("https://github.com/mhssn95/compose-color-picker/blob/main/LICENSE")
|
allowUrl("https://github.com/mhssn95/compose-color-picker/blob/main/LICENSE")
|
||||||
allowUrl("https://opensource.org/licenses/mit-license.php")
|
|
||||||
allowUrl("https://github.com/javaee/javax.annotation/blob/master/LICENSE")
|
|
||||||
allowUrl("https://www.bouncycastle.org/licence.html")
|
|
||||||
allowUrl("https://projectlombok.org/LICENSE")
|
|
||||||
allow("CC0-1.0")
|
|
||||||
ignoreDependencies("com.github.matrix-org", "matrix-analytics-events")
|
ignoreDependencies("com.github.matrix-org", "matrix-analytics-events")
|
||||||
// Ignore dependency that are not third-party licenses to us.
|
// Ignore dependency that are not third-party licenses to us.
|
||||||
ignoreDependencies(groupId = "io.element.android")
|
ignoreDependencies(groupId = "io.element.android")
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@
|
||||||
android:scheme="elementx" />
|
android:scheme="elementx" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<!--
|
<!--
|
||||||
Oidc redirection
|
OAuth redirection
|
||||||
-->
|
-->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ class MainActivity : NodeActivity() {
|
||||||
}.collectAsState(SemanticColorsLightDark.default)
|
}.collectAsState(SemanticColorsLightDark.default)
|
||||||
ElementThemeApp(
|
ElementThemeApp(
|
||||||
appPreferencesStore = appBindings.preferencesStore(),
|
appPreferencesStore = appBindings.preferencesStore(),
|
||||||
|
featureFlagService = appBindings.featureFlagService(),
|
||||||
compoundLight = colors.light,
|
compoundLight = colors.light,
|
||||||
compoundDark = colors.dark,
|
compoundDark = colors.dark,
|
||||||
buildMeta = appBindings.buildMeta()
|
buildMeta = appBindings.buildMeta()
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ package io.element.android.x.oidc
|
||||||
|
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import io.element.android.x.R
|
import io.element.android.x.R
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class DefaultOidcRedirectUrlProvider(
|
class DefaultOAuthRedirectUrlProvider(
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
) : OidcRedirectUrlProvider {
|
) : OAuthRedirectUrlProvider {
|
||||||
override fun provide() = buildString {
|
override fun provide() = buildString {
|
||||||
append(stringProvider.getString(R.string.login_redirect_scheme))
|
append(stringProvider.getString(R.string.login_redirect_scheme))
|
||||||
append(":/")
|
append(":/")
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<locale android:name="be"/>
|
<locale android:name="be"/>
|
||||||
<locale android:name="bg"/>
|
<locale android:name="bg"/>
|
||||||
|
<locale android:name="ca"/>
|
||||||
<locale android:name="cs"/>
|
<locale android:name="cs"/>
|
||||||
<locale android:name="cy"/>
|
<locale android:name="cy"/>
|
||||||
<locale android:name="da"/>
|
<locale android:name="da"/>
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
import io.element.android.x.R
|
import io.element.android.x.R
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class DefaultOidcRedirectUrlProviderTest {
|
class DefaultOAuthRedirectUrlProviderTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test provide`() {
|
fun `test provide`() {
|
||||||
val stringProvider = FakeStringProvider(
|
val stringProvider = FakeStringProvider(
|
||||||
defaultResult = "str"
|
defaultResult = "str"
|
||||||
)
|
)
|
||||||
val sut = DefaultOidcRedirectUrlProvider(
|
val sut = DefaultOAuthRedirectUrlProvider(
|
||||||
stringProvider = stringProvider,
|
stringProvider = stringProvider,
|
||||||
)
|
)
|
||||||
val result = sut.provide()
|
val result = sut.provide()
|
||||||
|
|
@ -48,6 +48,8 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(libs.coroutines.core)
|
||||||
implementation(libs.androidx.annotationjvm)
|
implementation(libs.androidx.annotationjvm)
|
||||||
|
implementation(libs.androidx.corektx)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Element Creations Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object ProtectionConfig {
|
||||||
|
/**
|
||||||
|
* The maximum length of a room name, to limit attack vectors in room invite.
|
||||||
|
*/
|
||||||
|
const val MAX_ROOM_NAME_LENGTH = 128
|
||||||
|
}
|
||||||
|
|
@ -33,13 +33,14 @@ dependencies {
|
||||||
implementation(projects.libraries.deeplink.api)
|
implementation(projects.libraries.deeplink.api)
|
||||||
implementation(projects.libraries.featureflag.api)
|
implementation(projects.libraries.featureflag.api)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
implementation(projects.libraries.oidc.api)
|
implementation(projects.libraries.oauth.api)
|
||||||
implementation(projects.libraries.preferences.api)
|
implementation(projects.libraries.preferences.api)
|
||||||
implementation(projects.libraries.push.api)
|
implementation(projects.libraries.push.api)
|
||||||
implementation(projects.libraries.pushproviders.api)
|
implementation(projects.libraries.pushproviders.api)
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.matrixui)
|
implementation(projects.libraries.matrixui)
|
||||||
implementation(projects.libraries.matrixmedia.api)
|
implementation(projects.libraries.matrixmedia.api)
|
||||||
|
implementation(projects.libraries.sessionStorage.api)
|
||||||
implementation(projects.libraries.uiCommon)
|
implementation(projects.libraries.uiCommon)
|
||||||
implementation(projects.libraries.uiStrings)
|
implementation(projects.libraries.uiStrings)
|
||||||
implementation(projects.features.login.api)
|
implementation(projects.features.login.api)
|
||||||
|
|
@ -59,7 +60,7 @@ dependencies {
|
||||||
testImplementation(projects.features.login.test)
|
testImplementation(projects.features.login.test)
|
||||||
testImplementation(projects.features.share.test)
|
testImplementation(projects.features.share.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.oidc.test)
|
testImplementation(projects.libraries.oauth.test)
|
||||||
testImplementation(projects.libraries.preferences.test)
|
testImplementation(projects.libraries.preferences.test)
|
||||||
testImplementation(projects.libraries.push.test)
|
testImplementation(projects.libraries.push.test)
|
||||||
testImplementation(projects.libraries.pushproviders.test)
|
testImplementation(projects.libraries.pushproviders.test)
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import io.element.android.features.ftue.api.state.FtueService
|
||||||
import io.element.android.features.ftue.api.state.FtueState
|
import io.element.android.features.ftue.api.state.FtueState
|
||||||
import io.element.android.features.home.api.HomeEntryPoint
|
import io.element.android.features.home.api.HomeEntryPoint
|
||||||
import io.element.android.features.linknewdevice.api.LinkNewDeviceEntryPoint
|
import io.element.android.features.linknewdevice.api.LinkNewDeviceEntryPoint
|
||||||
|
import io.element.android.features.location.api.live.ActiveLiveLocationShareManager
|
||||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
|
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
|
||||||
|
|
@ -77,6 +78,7 @@ import io.element.android.libraries.designsystem.theme.ElementThemeApp
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||||
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
@ -144,11 +146,13 @@ class LoggedInFlowNode(
|
||||||
private val syncService: SyncService,
|
private val syncService: SyncService,
|
||||||
private val enterpriseService: EnterpriseService,
|
private val enterpriseService: EnterpriseService,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
|
private val featureFlagService: FeatureFlagService,
|
||||||
private val buildMeta: BuildMeta,
|
private val buildMeta: BuildMeta,
|
||||||
snackbarDispatcher: SnackbarDispatcher,
|
snackbarDispatcher: SnackbarDispatcher,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val analyticsRoomListStateWatcher: AnalyticsRoomListStateWatcher,
|
private val analyticsRoomListStateWatcher: AnalyticsRoomListStateWatcher,
|
||||||
private val createRoomEntryPoint: CreateRoomEntryPoint,
|
private val createRoomEntryPoint: CreateRoomEntryPoint,
|
||||||
|
private val activeLiveLocationShareManager: ActiveLiveLocationShareManager,
|
||||||
) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
|
) : BaseFlowNode<LoggedInFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.Placeholder,
|
initialElement = NavTarget.Placeholder,
|
||||||
|
|
@ -209,6 +213,7 @@ class LoggedInFlowNode(
|
||||||
super.onBuilt()
|
super.onBuilt()
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
sessionEnterpriseService.init()
|
sessionEnterpriseService.init()
|
||||||
|
activeLiveLocationShareManager.setup()
|
||||||
}
|
}
|
||||||
lifecycle.subscribe(
|
lifecycle.subscribe(
|
||||||
onCreate = {
|
onCreate = {
|
||||||
|
|
@ -217,7 +222,6 @@ class LoggedInFlowNode(
|
||||||
loggedInFlowProcessor.observeEvents(sessionCoroutineScope)
|
loggedInFlowProcessor.observeEvents(sessionCoroutineScope)
|
||||||
matrixClient.sessionVerificationService.setListener(verificationListener)
|
matrixClient.sessionVerificationService.setListener(verificationListener)
|
||||||
mediaPreviewConfigMigration()
|
mediaPreviewConfigMigration()
|
||||||
|
|
||||||
sessionCoroutineScope.launch {
|
sessionCoroutineScope.launch {
|
||||||
// Wait for the network to be connected before pre-fetching the max file upload size
|
// Wait for the network to be connected before pre-fetching the max file upload size
|
||||||
networkMonitor.connectivity.first { networkStatus -> networkStatus == NetworkStatus.Connected }
|
networkMonitor.connectivity.first { networkStatus -> networkStatus == NetworkStatus.Connected }
|
||||||
|
|
@ -378,9 +382,13 @@ class LoggedInFlowNode(
|
||||||
}
|
}
|
||||||
is NavTarget.Room -> {
|
is NavTarget.Room -> {
|
||||||
val joinedRoomCallback = object : JoinedRoomLoadedFlowNode.Callback {
|
val joinedRoomCallback = object : JoinedRoomLoadedFlowNode.Callback {
|
||||||
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>) {
|
override fun onDone() {
|
||||||
|
backstack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>, clearBackStack: Boolean) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
attachRoom(roomIdOrAlias = roomId.toRoomIdOrAlias(), serverNames = serverNames, clearBackstack = false)
|
attachRoom(roomIdOrAlias = roomId.toRoomIdOrAlias(), serverNames = serverNames, clearBackstack = clearBackStack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -671,6 +679,7 @@ class LoggedInFlowNode(
|
||||||
}.collectAsState(SemanticColorsLightDark.default)
|
}.collectAsState(SemanticColorsLightDark.default)
|
||||||
ElementThemeApp(
|
ElementThemeApp(
|
||||||
appPreferencesStore = appPreferencesStore,
|
appPreferencesStore = appPreferencesStore,
|
||||||
|
featureFlagService = featureFlagService,
|
||||||
compoundLight = colors.light,
|
compoundLight = colors.light,
|
||||||
compoundDark = colors.dark,
|
compoundDark = colors.dark,
|
||||||
buildMeta = buildMeta,
|
buildMeta = buildMeta,
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.core.asEventId
|
import io.element.android.libraries.matrix.api.core.asEventId
|
||||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcActionFlow
|
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||||
import io.element.android.libraries.sessionstorage.api.LoggedInState
|
import io.element.android.libraries.sessionstorage.api.LoggedInState
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import io.element.android.libraries.ui.common.nodes.emptyNode
|
import io.element.android.libraries.ui.common.nodes.emptyNode
|
||||||
|
|
@ -95,7 +95,7 @@ class RootFlowNode(
|
||||||
private val signedOutEntryPoint: SignedOutEntryPoint,
|
private val signedOutEntryPoint: SignedOutEntryPoint,
|
||||||
private val accountSelectEntryPoint: AccountSelectEntryPoint,
|
private val accountSelectEntryPoint: AccountSelectEntryPoint,
|
||||||
private val intentResolver: IntentResolver,
|
private val intentResolver: IntentResolver,
|
||||||
private val oidcActionFlow: OidcActionFlow,
|
private val oAuthActionFlow: OAuthActionFlow,
|
||||||
private val featureFlagService: FeatureFlagService,
|
private val featureFlagService: FeatureFlagService,
|
||||||
private val announcementService: AnnouncementService,
|
private val announcementService: AnnouncementService,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
|
|
@ -392,7 +392,7 @@ class RootFlowNode(
|
||||||
navigateTo(resolvedIntent.deeplinkData)
|
navigateTo(resolvedIntent.deeplinkData)
|
||||||
}
|
}
|
||||||
is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params)
|
is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params)
|
||||||
is ResolvedIntent.Oidc -> onOidcAction(resolvedIntent.oidcAction)
|
is ResolvedIntent.OAuth -> onOAuthAction(resolvedIntent.oAuthAction)
|
||||||
is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData)
|
is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData)
|
||||||
is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.shareIntentData)
|
is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.shareIntentData)
|
||||||
}
|
}
|
||||||
|
|
@ -529,8 +529,8 @@ class RootFlowNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onOidcAction(oidcAction: OidcAction) {
|
private fun onOAuthAction(oAuthAction: OAuthAction) {
|
||||||
oidcActionFlow.post(oidcAction)
|
oAuthActionFlow.post(oAuthAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun attachSession(sessionId: SessionId): LoggedInFlowNode {
|
private suspend fun attachSession(sessionId: SessionId): LoggedInFlowNode {
|
||||||
|
|
|
||||||
|
|
@ -89,16 +89,14 @@ class SyncOrchestrator(
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
internal fun observeStates() = coroutineScope.launch {
|
internal fun observeStates() = coroutineScope.launch {
|
||||||
Timber.tag(tag).d("start observing the app and network state")
|
Timber.tag(tag).d("start observing the app and network state")
|
||||||
|
val isAppActiveFlows = listOf(
|
||||||
val isAppActiveFlow = combine(
|
|
||||||
appForegroundStateService.isInForeground,
|
appForegroundStateService.isInForeground,
|
||||||
appForegroundStateService.isInCall,
|
appForegroundStateService.isInCall,
|
||||||
appForegroundStateService.isSyncingNotificationEvent,
|
appForegroundStateService.isSyncingNotificationEvent,
|
||||||
appForegroundStateService.hasRingingCall,
|
appForegroundStateService.hasRingingCall,
|
||||||
) { isInForeground, isInCall, isSyncingNotificationEvent, hasRingingCall ->
|
appForegroundStateService.isSharingLiveLocation
|
||||||
isInForeground || isInCall || isSyncingNotificationEvent || hasRingingCall
|
)
|
||||||
}
|
val isAppActiveFlow = combine(isAppActiveFlows) { actives -> actives.any { it } }
|
||||||
|
|
||||||
combine(
|
combine(
|
||||||
// small debounce to avoid spamming startSync when the state is changing quickly in case of error.
|
// small debounce to avoid spamming startSync when the state is changing quickly in case of error.
|
||||||
syncService.syncState.debounce(100.milliseconds),
|
syncService.syncState.debounce(100.milliseconds),
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ import io.element.android.libraries.deeplink.api.DeeplinkData
|
||||||
import io.element.android.libraries.deeplink.api.DeeplinkParser
|
import io.element.android.libraries.deeplink.api.DeeplinkParser
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.api.OidcIntentResolver
|
import io.element.android.libraries.oauth.api.OAuthIntentResolver
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
sealed interface ResolvedIntent {
|
sealed interface ResolvedIntent {
|
||||||
data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent
|
data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent
|
||||||
data class Oidc(val oidcAction: OidcAction) : ResolvedIntent
|
data class OAuth(val oAuthAction: OAuthAction) : ResolvedIntent
|
||||||
data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent
|
data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent
|
||||||
data class Login(val params: LoginParams) : ResolvedIntent
|
data class Login(val params: LoginParams) : ResolvedIntent
|
||||||
data class IncomingShare(val shareIntentData: ShareIntentData) : ResolvedIntent
|
data class IncomingShare(val shareIntentData: ShareIntentData) : ResolvedIntent
|
||||||
|
|
@ -34,7 +34,7 @@ sealed interface ResolvedIntent {
|
||||||
class IntentResolver(
|
class IntentResolver(
|
||||||
private val deeplinkParser: DeeplinkParser,
|
private val deeplinkParser: DeeplinkParser,
|
||||||
private val loginIntentResolver: LoginIntentResolver,
|
private val loginIntentResolver: LoginIntentResolver,
|
||||||
private val oidcIntentResolver: OidcIntentResolver,
|
private val oAuthIntentResolver: OAuthIntentResolver,
|
||||||
private val permalinkParser: PermalinkParser,
|
private val permalinkParser: PermalinkParser,
|
||||||
private val shareIntentHandler: ShareIntentHandler,
|
private val shareIntentHandler: ShareIntentHandler,
|
||||||
) {
|
) {
|
||||||
|
|
@ -45,9 +45,9 @@ class IntentResolver(
|
||||||
val deepLinkData = deeplinkParser.getFromIntent(intent)
|
val deepLinkData = deeplinkParser.getFromIntent(intent)
|
||||||
if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData)
|
if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData)
|
||||||
|
|
||||||
// Coming during login using Oidc?
|
// Coming during login using OAuth?
|
||||||
val oidcAction = oidcIntentResolver.resolve(intent)
|
val oAuthAction = oAuthIntentResolver.resolve(intent)
|
||||||
if (oidcAction != null) return ResolvedIntent.Oidc(oidcAction)
|
if (oAuthAction != null) return ResolvedIntent.OAuth(oAuthAction)
|
||||||
|
|
||||||
val actionViewData = intent
|
val actionViewData = intent
|
||||||
.takeIf { it.action == Intent.ACTION_VIEW }
|
.takeIf { it.action == Intent.ACTION_VIEW }
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import io.element.android.libraries.core.meta.BuildMeta
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
|
|
@ -177,7 +176,6 @@ class LoggedInPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.preloadAccountManagementUrl() = launch {
|
private fun CoroutineScope.preloadAccountManagementUrl() = launch {
|
||||||
matrixClient.getAccountManagementUrl(AccountManagementAction.Profile)
|
matrixClient.getAccountManagementUrl(null)
|
||||||
matrixClient.getAccountManagementUrl(AccountManagementAction.DevicesList)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,8 @@ class JoinedRoomLoadedFlowNode(
|
||||||
plugins = plugins,
|
plugins = plugins,
|
||||||
), DependencyInjectionGraphOwner {
|
), DependencyInjectionGraphOwner {
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun navigateToRoom(roomId: RoomId, serverNames: List<String>)
|
fun onDone()
|
||||||
|
fun navigateToRoom(roomId: RoomId, serverNames: List<String>, clearBackStack: Boolean = false)
|
||||||
fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean)
|
||||||
fun navigateToGlobalNotificationSettings()
|
fun navigateToGlobalNotificationSettings()
|
||||||
fun navigateToDeveloperSettings()
|
fun navigateToDeveloperSettings()
|
||||||
|
|
@ -142,6 +143,10 @@ class JoinedRoomLoadedFlowNode(
|
||||||
|
|
||||||
private fun createRoomDetailsNode(buildContext: BuildContext, initialTarget: RoomDetailsEntryPoint.InitialTarget): Node {
|
private fun createRoomDetailsNode(buildContext: BuildContext, initialTarget: RoomDetailsEntryPoint.InitialTarget): Node {
|
||||||
val callback = object : RoomDetailsEntryPoint.Callback {
|
val callback = object : RoomDetailsEntryPoint.Callback {
|
||||||
|
override fun onDone() {
|
||||||
|
callback.onDone()
|
||||||
|
}
|
||||||
|
|
||||||
override fun navigateToGlobalNotificationSettings() {
|
override fun navigateToGlobalNotificationSettings() {
|
||||||
callback.navigateToGlobalNotificationSettings()
|
callback.navigateToGlobalNotificationSettings()
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +155,7 @@ class JoinedRoomLoadedFlowNode(
|
||||||
callback.navigateToDeveloperSettings()
|
callback.navigateToDeveloperSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>) {
|
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>, clearBackStack: Boolean) {
|
||||||
callback.navigateToRoom(roomId, serverNames)
|
callback.navigateToRoom(roomId, serverNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
6
appnav/src/main/res/values-ca/translations.xml
Normal file
6
appnav/src/main/res/values-ca/translations.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="banner_migrate_to_native_sliding_sync_action">"Tanca sessió i actualitza"</string>
|
||||||
|
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s ja no admet el protocol antic. Tanca sessió i torna a entrar per continuar utilitzant l\'aplicació."</string>
|
||||||
|
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"El servidor utilitzat ja no admet el protocol antic. Tanca sessió i torna-la a iniciar per continuar utilitzant l\'aplicació."</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="banner_migrate_to_native_sliding_sync_action">"登出并升级"</string>
|
<string name="banner_migrate_to_native_sliding_sync_action">"注销并升级"</string>
|
||||||
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s 不再支持旧协议。请注销并重新登录以继续使用该应用程序。"</string>
|
<string name="banner_migrate_to_native_sliding_sync_app_force_logout_title">"%1$s 不再支持旧协议。请注销并重新登录以继续使用该应用程序。"</string>
|
||||||
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"您的服务器不再支持旧协议。请登出并重新登录以继续使用此应用。"</string>
|
<string name="banner_migrate_to_native_sliding_sync_force_logout_title">"你的主服务器不再支持旧协议。请注销并重新登录以继续使用此 app。"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_THREAD_ID
|
import io.element.android.libraries.matrix.test.A_THREAD_ID
|
||||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||||
import io.element.android.libraries.oidc.api.OidcAction
|
import io.element.android.libraries.oauth.api.OAuthAction
|
||||||
import io.element.android.libraries.oidc.test.FakeOidcIntentResolver
|
import io.element.android.libraries.oauth.test.FakeOAuthIntentResolver
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
@ -170,9 +170,9 @@ class IntentResolverTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test resolve oidc`() {
|
fun `test resolve OAuth`() {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
oidcIntentResolverResult = { OidcAction.GoBack() },
|
oAuthIntentResolverResult = { OAuthAction.GoBack() },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
|
|
@ -180,8 +180,8 @@ class IntentResolverTest {
|
||||||
}
|
}
|
||||||
val result = sut.resolve(intent)
|
val result = sut.resolve(intent)
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).isEqualTo(
|
||||||
ResolvedIntent.Oidc(
|
ResolvedIntent.OAuth(
|
||||||
oidcAction = OidcAction.GoBack()
|
oAuthAction = OAuthAction.GoBack()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ class IntentResolverTest {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
loginIntentResolverResult = { null },
|
loginIntentResolverResult = { null },
|
||||||
permalinkParserResult = { permalinkData },
|
permalinkParserResult = { permalinkData },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
|
|
@ -213,7 +213,7 @@ class IntentResolverTest {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
||||||
loginIntentResolverResult = { null },
|
loginIntentResolverResult = { null },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
|
|
@ -230,7 +230,7 @@ class IntentResolverTest {
|
||||||
)
|
)
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
permalinkParserResult = { permalinkData },
|
permalinkParserResult = { permalinkData },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_BATTERY_LOW
|
action = Intent.ACTION_BATTERY_LOW
|
||||||
|
|
@ -244,7 +244,7 @@ class IntentResolverTest {
|
||||||
fun `test incoming share simple`() {
|
fun `test incoming share simple`() {
|
||||||
val shareIntentData = ShareIntentData.PlainText("Hello")
|
val shareIntentData = ShareIntentData.PlainText("Hello")
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
onIncomingShareIntent = { shareIntentData },
|
onIncomingShareIntent = { shareIntentData },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
|
|
@ -260,7 +260,7 @@ class IntentResolverTest {
|
||||||
val fileUri = "content://com.example.app/file1.jpg".toUri()
|
val fileUri = "content://com.example.app/file1.jpg".toUri()
|
||||||
val shareIntentData = ShareIntentData.Uris(text = "Hello", uris = listOf(UriToShare(fileUri, "image/jpg")))
|
val shareIntentData = ShareIntentData.Uris(text = "Hello", uris = listOf(UriToShare(fileUri, "image/jpg")))
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
onIncomingShareIntent = { shareIntentData },
|
onIncomingShareIntent = { shareIntentData },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
|
|
@ -277,7 +277,7 @@ class IntentResolverTest {
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) },
|
||||||
loginIntentResolverResult = { null },
|
loginIntentResolverResult = { null },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
|
|
@ -292,7 +292,7 @@ class IntentResolverTest {
|
||||||
val aLoginParams = LoginParams("accountProvider", null)
|
val aLoginParams = LoginParams("accountProvider", null)
|
||||||
val sut = createIntentResolver(
|
val sut = createIntentResolver(
|
||||||
loginIntentResolverResult = { aLoginParams },
|
loginIntentResolverResult = { aLoginParams },
|
||||||
oidcIntentResolverResult = { null },
|
oAuthIntentResolverResult = { null },
|
||||||
)
|
)
|
||||||
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply {
|
||||||
action = Intent.ACTION_VIEW
|
action = Intent.ACTION_VIEW
|
||||||
|
|
@ -306,7 +306,7 @@ class IntentResolverTest {
|
||||||
deeplinkParserResult: DeeplinkData? = null,
|
deeplinkParserResult: DeeplinkData? = null,
|
||||||
permalinkParserResult: (String) -> PermalinkData = { lambdaError() },
|
permalinkParserResult: (String) -> PermalinkData = { lambdaError() },
|
||||||
loginIntentResolverResult: (String) -> LoginParams? = { lambdaError() },
|
loginIntentResolverResult: (String) -> LoginParams? = { lambdaError() },
|
||||||
oidcIntentResolverResult: (Intent) -> OidcAction? = { lambdaError() },
|
oAuthIntentResolverResult: (Intent) -> OAuthAction? = { lambdaError() },
|
||||||
onIncomingShareIntent: (Intent) -> ShareIntentData? = { null },
|
onIncomingShareIntent: (Intent) -> ShareIntentData? = { null },
|
||||||
): IntentResolver {
|
): IntentResolver {
|
||||||
return IntentResolver(
|
return IntentResolver(
|
||||||
|
|
@ -314,8 +314,8 @@ class IntentResolverTest {
|
||||||
loginIntentResolver = FakeLoginIntentResolver(
|
loginIntentResolver = FakeLoginIntentResolver(
|
||||||
parseResult = loginIntentResolverResult,
|
parseResult = loginIntentResolverResult,
|
||||||
),
|
),
|
||||||
oidcIntentResolver = FakeOidcIntentResolver(
|
oAuthIntentResolver = FakeOAuthIntentResolver(
|
||||||
resolveResult = oidcIntentResolverResult,
|
resolveResult = oAuthIntentResolverResult,
|
||||||
),
|
),
|
||||||
permalinkParser = FakePermalinkParser(
|
permalinkParser = FakePermalinkParser(
|
||||||
result = permalinkParserResult
|
result = permalinkParserResult
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
import io.element.android.libraries.matrix.api.oauth.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
|
|
@ -71,7 +71,7 @@ class LoggedInPresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - ensure that account urls are preloaded`() = runTest {
|
fun `present - ensure that account url is preloaded`() = runTest {
|
||||||
val accountManagementUrlResult = lambdaRecorder<AccountManagementAction?, Result<String?>> { Result.success("aUrl") }
|
val accountManagementUrlResult = lambdaRecorder<AccountManagementAction?, Result<String?>> { Result.success("aUrl") }
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
accountManagementUrlResult = accountManagementUrlResult,
|
accountManagementUrlResult = accountManagementUrlResult,
|
||||||
|
|
@ -81,11 +81,8 @@ class LoggedInPresenterTest {
|
||||||
).test {
|
).test {
|
||||||
awaitItem()
|
awaitItem()
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
accountManagementUrlResult.assertions().isCalledExactly(2)
|
accountManagementUrlResult.assertions().isCalledOnce()
|
||||||
.withSequence(
|
.with(value(null))
|
||||||
listOf(value(AccountManagementAction.Profile)),
|
|
||||||
listOf(value(AccountManagementAction.DevicesList)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
|
||||||
class FakeJoinedRoomLoadedFlowNodeCallback : JoinedRoomLoadedFlowNode.Callback {
|
class FakeJoinedRoomLoadedFlowNodeCallback : JoinedRoomLoadedFlowNode.Callback {
|
||||||
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>) = lambdaError()
|
override fun onDone() = lambdaError()
|
||||||
|
override fun navigateToRoom(roomId: RoomId, serverNames: List<String>, clearBackStack: Boolean) = lambdaError()
|
||||||
override fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
|
override fun handlePermalinkClick(data: PermalinkData, pushToBackstack: Boolean) = lambdaError()
|
||||||
override fun navigateToGlobalNotificationSettings() = lambdaError()
|
override fun navigateToGlobalNotificationSettings() = lambdaError()
|
||||||
override fun navigateToDeveloperSettings() = lambdaError()
|
override fun navigateToDeveloperSettings() = lambdaError()
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,15 @@ allprojects {
|
||||||
config.from(files("$rootDir/tools/detekt/detekt.yml"))
|
config.from(files("$rootDir/tools/detekt/detekt.yml"))
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
detektPlugins("io.nlopez.compose.rules:detekt:0.5.6")
|
detektPlugins("io.nlopez.compose.rules:detekt:0.5.8")
|
||||||
detektPlugins(project(":tests:detekt-rules"))
|
detektPlugins(project(":tests:detekt-rules"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
|
tasks.withType<io.gitlab.arturbosch.detekt.Detekt>().configureEach {
|
||||||
exclude("io/element/android/tests/konsist/failures/**")
|
exclude("io/element/android/tests/konsist/failures/**")
|
||||||
|
|
||||||
|
// This file comes from another project and we want to keep it as close to the original as possible
|
||||||
|
exclude("org/rustls/platformverifier/**")
|
||||||
}
|
}
|
||||||
|
|
||||||
// KtLint
|
// KtLint
|
||||||
|
|
@ -79,6 +82,9 @@ allprojects {
|
||||||
|
|
||||||
// This file comes from another project and we want to keep it as close to the original as possible
|
// This file comes from another project and we want to keep it as close to the original as possible
|
||||||
exclude("**/SafeChildrenTransitionScope.kt")
|
exclude("**/SafeChildrenTransitionScope.kt")
|
||||||
|
|
||||||
|
// This file comes from another project and we want to keep it as close to the original as possible
|
||||||
|
exclude("org/rustls/platformverifier/**")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dependency check
|
// Dependency check
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,11 @@ Prerequisites:
|
||||||
export ANDROID_HOME=$HOME/android/sdk
|
export ANDROID_HOME=$HOME/android/sdk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* On macos ensure gnu-getopt is installed
|
||||||
|
```
|
||||||
|
brew install gnu-getopt
|
||||||
|
```
|
||||||
|
|
||||||
You can then build the Rust SDK by running the script
|
You can then build the Rust SDK by running the script
|
||||||
[`tools/sdk/build-rust-sdk`](../tools/sdk/build-rust-sdk). Type
|
[`tools/sdk/build-rust-sdk`](../tools/sdk/build-rust-sdk). Type
|
||||||
`./tools/sdk/build-rust-sdk --help` for help.
|
`./tools/sdk/build-rust-sdk --help` for help.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
This file contains some rough notes about Oidc implementation, with some examples of actual data.
|
This file contains some rough notes about OAuth implementation, with some examples of actual data.
|
||||||
|
|
||||||
[ios implementation](https://github.com/element-hq/element-x-ios/compare/develop...doug/oidc-temp)
|
[ios implementation](https://github.com/element-hq/element-x-ios/compare/develop...doug/oidc-temp)
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ tosUri = "https://element.io/user-terms-of-service",
|
||||||
policyUri = "https://element.io/privacy"
|
policyUri = "https://element.io/privacy"
|
||||||
|
|
||||||
|
|
||||||
Example of OidcData (from presentUrl callback):
|
Example of OAuthData (from presentUrl callback):
|
||||||
url: https://auth-oidc.lab.element.dev/authorize?response_type=code&client_id=01GYCAGG3PA70CJ97ZVP0WFJY3&redirect_uri=io.element%3A%2Fcallback&scope=openid+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AYAgcPW4mcG&state=ex6mNJVFZ5jn9wL8&nonce=NZ93DOyIGQd9exPQ&code_challenge_method=S256&code_challenge=FFRcPALNSPCh-ZgpyTRFu_h8NZJVncfvihbfT9CyX8U&prompt=consent
|
url: https://auth-oidc.lab.element.dev/authorize?response_type=code&client_id=01GYCAGG3PA70CJ97ZVP0WFJY3&redirect_uri=io.element%3A%2Fcallback&scope=openid+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AYAgcPW4mcG&state=ex6mNJVFZ5jn9wL8&nonce=NZ93DOyIGQd9exPQ&code_challenge_method=S256&code_challenge=FFRcPALNSPCh-ZgpyTRFu_h8NZJVncfvihbfT9CyX8U&prompt=consent
|
||||||
|
|
||||||
Formatted url:
|
Formatted url:
|
||||||
|
|
@ -43,8 +43,8 @@ https://auth-oidc.lab.element.dev/authorize?
|
||||||
state: ex6mNJVFZ5jn9wL8
|
state: ex6mNJVFZ5jn9wL8
|
||||||
|
|
||||||
|
|
||||||
Oidc client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs
|
OAuth client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs
|
||||||
Oidc sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs
|
OAuth sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs
|
||||||
|
|
||||||
|
|
||||||
Test server:
|
Test server:
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit cdde60c158ecd0987a3ba6fd79a4617551aff463
|
Subproject commit 6781da90aae61cf77dcdbc543e18d76411d578b4
|
||||||
2
fastlane/metadata/android/en-US/changelogs/202604040.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202604040.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: several bug fixes.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
2
fastlane/metadata/android/en-US/changelogs/202605000.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202605000.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: bug fixes and improvements.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
2
fastlane/metadata/android/en-US/changelogs/202605010.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202605010.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: improvements in Element Call, room knocking and room directory are now available, improvements on DMs.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
2
fastlane/metadata/android/en-US/changelogs/202605020.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/202605020.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Main changes in this version: bug fixes and improvements.
|
||||||
|
Full changelog: https://github.com/element-hq/element-x-android/releases
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="screen_analytics_settings_help_us_improve">"Comparteix dades d\'ús anònimes per ajudar-nos a identificar problemes."</string>
|
||||||
|
<string name="screen_analytics_settings_read_terms">"Pots llegir tots els nostres termes %1$s."</string>
|
||||||
|
<string name="screen_analytics_settings_read_terms_content_link">"aquí"</string>
|
||||||
|
<string name="screen_analytics_settings_share_data">"Comparteix dades analítiques"</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_analytics_settings_help_us_improve">"問題発見のため、匿名の使用データの共有にご協力ください。"</string>
|
<string name="screen_analytics_settings_help_us_improve">"改善のため、匿名の使用データの共有にご協力ください。"</string>
|
||||||
<string name="screen_analytics_settings_read_terms">"利用規約の全文を%1$sから確認することができます。"</string>
|
<string name="screen_analytics_settings_read_terms">"規約の全文は%1$sから確認することができます。"</string>
|
||||||
<string name="screen_analytics_settings_read_terms_content_link">"こちら"</string>
|
<string name="screen_analytics_settings_read_terms_content_link">"こちら"</string>
|
||||||
<string name="screen_analytics_settings_share_data">"使用データを共有"</string>
|
<string name="screen_analytics_settings_share_data">"使用データを共有"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_analytics_settings_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
|
<string name="screen_analytics_settings_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
|
||||||
<string name="screen_analytics_settings_read_terms">"您可以阅读我们的所有条款 %1$s。"</string>
|
<string name="screen_analytics_settings_read_terms">"你可以点击 %1$s 阅读我们的所有条款。"</string>
|
||||||
<string name="screen_analytics_settings_read_terms_content_link">"此处"</string>
|
<string name="screen_analytics_settings_read_terms_content_link">"此处"</string>
|
||||||
<string name="screen_analytics_settings_share_data">"共享分析数据"</string>
|
<string name="screen_analytics_settings_share_data">"共享分析数据"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<string name="screen_analytics_prompt_data_usage">"No registrarem ni elaborarem perfils de cap dada personal"</string>
|
||||||
|
<string name="screen_analytics_prompt_help_us_improve">"Comparteix dades d\'ús anònimes per ajudar-nos a identificar problemes."</string>
|
||||||
|
<string name="screen_analytics_prompt_read_terms">"Pots llegir tots els nostres termes %1$s."</string>
|
||||||
|
<string name="screen_analytics_prompt_read_terms_content_link">"aquí"</string>
|
||||||
|
<string name="screen_analytics_prompt_settings">"Ho pots desactivar en qualsevol moment"</string>
|
||||||
|
<string name="screen_analytics_prompt_third_party_sharing">"No compartirem les teves dades amb tercers"</string>
|
||||||
|
<string name="screen_analytics_prompt_title">"Ajuda\'ns a millorar %1$s"</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_analytics_prompt_data_usage">"いかなる個人情報も記録, 分析されることはありません"</string>
|
<string name="screen_analytics_prompt_data_usage">"いかなる個人情報も記録, 分析されることはありません"</string>
|
||||||
<string name="screen_analytics_prompt_help_us_improve">"問題発見のため、匿名の使用データの共有にご協力ください。"</string>
|
<string name="screen_analytics_prompt_help_us_improve">"改善のため、匿名の使用データの共有にご協力ください。"</string>
|
||||||
<string name="screen_analytics_prompt_read_terms">"利用規約の全文を%1$sから確認することができます。"</string>
|
<string name="screen_analytics_prompt_read_terms">"規約の全文は%1$sから確認することができます。"</string>
|
||||||
<string name="screen_analytics_prompt_read_terms_content_link">"こちら"</string>
|
<string name="screen_analytics_prompt_read_terms_content_link">"こちら"</string>
|
||||||
<string name="screen_analytics_prompt_settings">"いつでも設定は変更できます"</string>
|
<string name="screen_analytics_prompt_settings">"いつでも設定は変更できます"</string>
|
||||||
<string name="screen_analytics_prompt_third_party_sharing">"情報が第三者に共有されることはありません"</string>
|
<string name="screen_analytics_prompt_third_party_sharing">"情報が第三者に共有されることはありません"</string>
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="screen_analytics_prompt_data_usage">"我们不会记录或分析任何个人数据"</string>
|
<string name="screen_analytics_prompt_data_usage">"我们不会记录或分析任何个人数据"</string>
|
||||||
<string name="screen_analytics_prompt_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
|
<string name="screen_analytics_prompt_help_us_improve">"共享匿名使用数据以帮助我们排查问题。"</string>
|
||||||
<string name="screen_analytics_prompt_read_terms">"您可以阅读我们的所有条款 %1$s。"</string>
|
<string name="screen_analytics_prompt_read_terms">"你可以点击 %1$s 阅读我们的所有条款。"</string>
|
||||||
<string name="screen_analytics_prompt_read_terms_content_link">"此处"</string>
|
<string name="screen_analytics_prompt_read_terms_content_link">"此处"</string>
|
||||||
<string name="screen_analytics_prompt_settings">"可以随时关闭此功能"</string>
|
<string name="screen_analytics_prompt_settings">"可以随时关闭此功能"</string>
|
||||||
<string name="screen_analytics_prompt_third_party_sharing">"我们不会与第三方共享您的数据"</string>
|
<string name="screen_analytics_prompt_third_party_sharing">"我们不会与第三方共享你的数据"</string>
|
||||||
<string name="screen_analytics_prompt_title">"帮助改进 %1$s"</string>
|
<string name="screen_analytics_prompt_title">"帮助改进 %1$s"</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item4">"Присъединете се към обществени пространства"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Zobrazit prostory, které jste vytvořili nebo ke kterým jste se připojili"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Přijmout nebo odmítnout pozvánky do prostorů"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Objevte všechny místnosti, do kterých můžete vstoupit ve svých prostorech"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Připojit se k veřejným prostorům"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Opustit všechny prostory, ke kterým jste se připojili"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtrování, vytváření a správa prostorů bude brzy k dispozici."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Vítejte v beta verzi prostorů! S touto první verzí můžete:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Představujeme prostory"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Se klynger, du har oprettet eller tilmeldt dig"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Acceptere eller afvise invitationer til klynger"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Finde alle rum, du kan deltage i, i dine klynger"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Deltage i offentlige klynger"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Forlade de klynger, du har tilsluttet dig"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtrering, oprettelse og administration af klynger kommer snart."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Velkommen til betaversionen af Klynger! Med denne første version kan du:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Introduktion til Klynger"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Von dir erstellte oder beigetretene Spaces anzeigen"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Einladungen zu Spaces annehmen oder ablehnen"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Chats innerhalb deiner Spaces entdecken, um ihnen beizutreten"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Öffentlichen Spaces beitreten"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Spaces verlassen, bei denen du Mitglied bist"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Das Filtern, Erstellen und Verwalten von Spaces ist bald verfügbar."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Willkommen bei der Beta-Version von Spaces! Mit dieser ersten Version kannst du:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Einführung in Spaces"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Δείτε τους χώρους που έχετε δημιουργήσει ή στους οποίους έχετε εγγραφεί"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Να αποδεχθείτε ή να απορρίψετε προσκλήσεις σε χώρους"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Να ανακαλύψτε όλες τις αίθουσες που μπορείτε να συμμετάσχετε στους χώρους σας"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Να συμμετάσχετε σε δημόσιους χώρους"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Να αποχωρήστε από χώρους στους οποίους έχετε συμμετάσχει"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Το φιλτράρισμα, η δημιουργία και η διαχείριση χώρων θα είναι σύντομα διαθέσιμα."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Καλώς ορίσατε στην δοκιμαστική έκδοση των Χώρων! Με αυτήν την πρώτη έκδοση μπορείτε:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Παρουσιάζοντας τους Χώρους"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Vaadata kogukondi, mille oled loonud või millega oled liitunud"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Nõustuda kutsetega liitumiseks kogukonnaga või sellest keelduda"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Uurida neis kogukondades leiduvaid jututube ning nendega liituda"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Liituda avalike kogukondadega"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Lahkuda kogukonnast, millega oled liitunud"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Kogukondade filtreerimine, loomine ja haldamine lisandub peagi"</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Tere tulemast kasutama kogukondade beetaversiooni! Selles esimeses versioonis saad sa:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Võtame kasutusele kogukonnad"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"دیدن فضاهایی که ساخته یا پیوستهاید"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"پذیرش یا رد دعوتها به فضاها"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"کشف تمامی اتاقهایی که میتوانید در فضاهایتان بپیوندید"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"پیوستن به فضاهای عمومی"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"ترک هر فضایی که پیوستهاید"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"پالایش، ایجاد و مدیریت کردن فضاها به زودی."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"به نگارش آزمایشی فضاها خوش آمدید! در این نگارش میتوانید:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"معرّفی فضاها"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Nähdä luomasi tai liittymäsi tilat"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Hyväksyä tai hylätä kutsuja tiloihin"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Löytää kaikki huoneet, joihin voit liittyä tiloissasi"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Liittyä julkisiin tiloihin"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Poistua mistä tahansa tilasta, johon olet liittynyt"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Tilojen suodatus, luominen ja hallinta on tulossa pian."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Tervetuloa tilojen beetaversioon! Tämän ensimmäisen version avulla voit:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Esittelyssä tilat"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Voir les espaces que vous avez créés ou rejoints"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Accepter ou refuser les invitations aux espaces"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Découvrir les salons que vous pouvez joindre depuis vos espaces"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Rejoindre les espaces publics"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Quitter les espaces dont vous êtes membre."</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Le filtrage, la création et la gestion des espaces seront bientôt disponibles."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Bienvenue dans la version bêta des espaces! Avec cette première version, vous pourrez :"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Ajout des espaces"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Pregledajte prostore koje ste stvorili ili kojima ste se pridružili"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Prihvatite ili odbijte pozivnice za prostore"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Otkrijte sve sobe kojima se možete pridružiti u svojim prostorima"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Pridružite se javnim prostorima"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Napustite sve prostore kojima ste se pridružili"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Uskoro stiže filtriranje i stvaranje prostora te upravljanje njima."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Dobrodošli u beta inačicu prostora! S ovom prvom inačicom možete:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Predstavljamo prostore"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Az Ön által létrehozott vagy csatlakozott térek megtekintése"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"A meghívások elfogadására vagy elutasítására a terekhez"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Szobák felfedezése a terekben, amelyekhez csatlakozhat"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Csatlakozás nyilvános terekhez"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Terek elhagyása"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Terek szűrése, készítése és kezelése hamarosan érkezik."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Üdvözöljük a tér béta verziójában! Ezzel az első verzióval a következőket teheti:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Bemutatkoznak a terek"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Visualizza gli spazi che hai creato o a cui partecipi"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Accetta o rifiuta gli inviti agli spazi"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Scopri tutte le stanze a cui puoi partecipare nei tuoi spazi"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Unisciti agli spazi pubblici"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Lascia tutti gli spazi a cui ti sei unito"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"A breve saranno disponibili le funzionalità di filtraggio, creazione e gestione degli spazi."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Benvenuti alla versione beta degli Spazi! Con questa prima versione potrete:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Ti presentiamo gli Spazi"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"作成または参加したスペースを表示できます"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"スペースへの招待を受諾または拒否できます"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"スペース内の参加可能なルームを検索できます"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"公開スペースに参加できます"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"参加したスペースを退出できます"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"スペースの作成や管理, フィルター検索は近日実装予定です。"</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"ベータ版のスペースにようこそ。この最新のバージョンでは:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"スペースの紹介"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"직접 만들거나 참여 중인 스페이스 보기"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"스페이스 초대 수락 또는 거절"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"참여 가능한 스페이스 내 모든 방 탐색"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"공개 스페이스 참여"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"참여 중인 스페이스 나가기"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"스페이스 필터링, 생성 및 관리 기능이 곧 추가될 예정입니다."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"스페이스 베타 버전에 오신 것을 환영합니다! 이번 첫 번째 버전에서는 다음과 같은 기능을 이용하실 수 있습니다.:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"스페이스 소개"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Se områder du har opprettet eller blitt med i"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Godta eller avslå invitasjoner til områder"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Oppdag alle rom du kan bli med i i dine områder"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Bli med i offentlige områder"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Forlat områder du har blitt med i"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Oppretting, filtrering og administrasjon av områder kommer snart."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Velkommen til betaversjonen av Områder! Med denne første versjonen kan du:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Vi introduserer Områder"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Wyświetlić przestrzenie, które stworzyłeś lub do których dołączyłeś"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Akceptować lub odrzucać zaproszenia"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Odkrywać wszystkie pokoje, do których możesz dołączyć w swoich przestrzeniach"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Dołączać do przestrzeni publicznych"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Opuszczać jakąkolwiek przestrzeń, do której dołączyłeś"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtrowanie, tworzenie i zarządzanie przestrzeniami pojawi się wkrótce."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Witamy w wersji beta przestrzeni! W tej wersji możesz:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Przedstawiamy przestrzenie"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Visualizar espaços que criou ou entrou"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Aceitar ou recusar convites aos espaços"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Descobrir quaisquer salas que você pode entrar nos espaços"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Entrar espaços públicos"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Sair de quaisquer espaços que entrou"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtrar, criar, e gerenciar espaços virão em breve."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Boas-vindas à versão beta dos Espaços! Com essa primeira versão, você pode:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Apresentando Espaços"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Ver espaços que criaste ou nos quais entraste"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Aceitar ou recusar convites para espaços"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Descobrir todas as salas dos seus espaços nas quais podes entrar"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Entrar em espaços públicos"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Deixar todos os espaços em que entraste"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Em breve, será possível filtrar, criar e gerir espaços."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Eis a versão beta dos Espaços! Nesta primeira versão, podes:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Apresentamos os Espaços"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Vizualizați spațiile pe care le-ați creat sau la care v-ați alăturat"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Acceptați sau refuzați invitațiile la spații"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Descoperiți toate camerele la care vă puteți alătura în spațiile dumneavoastră."</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Alăturați-vă spațiilor publice"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Părăsiți spațiile la care v-ați alăturat."</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtrarea, crearea și gestionarea spațiilor vor fi disponibile în curând."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Bun venit la versiunea beta a Spațiilor! Cu această primă versiune puteți:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Vă prezentăm Spații"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Просматривать пространства, которые вы создали или к которым присоединились"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Принимать или отклонять приглашения в пространства"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Находить все комнаты, к которым можно присоединиться в ваших пространствах"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Присоединяться к публичным пространствам"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Покидать все пространства, к которым вы присоединились"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Фильтровать, создавать пространства и управлять ими можно будет позже."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Добро пожаловать в бета-версию пространств! Сейчас вы сможете:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Представляем пространства"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Zobraziť priestory, ktoré ste vytvorili alebo ku ktorým ste sa pripojili"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Prijímať alebo odmietať pozvánky do priestorov"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Objaviť všetky miestnosti, do ktorých sa môžete pripojiť vo svojich priestoroch"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Pripojiť sa k verejnému priestoru"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Opustiť akékoľvek priestory, ku ktorým ste sa pridali"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtrovanie, vytváranie a správa priestorov bude čoskoro k dispozícii."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Vitajte v beta verzii priestorov! S touto prvou verziou môžete:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Predstavujeme priestory"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Oluşturduğunuz veya katıldığınız alanları görüntüleyin"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Alan davetlerini kabul edin veya reddedin"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Alanlarınızdaki katılabileceğiniz odaları keşfedin"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Herkese açık alanlara katılın"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Katıldığınız alanlardan ayrılın"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Alanları filtreleme, oluşturma ve yönetme yakında geliyor."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Alanlar’ın beta sürümüne hoş geldiniz! Bu ilk sürümle şunları yapabilirsiniz:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Alanlar ile tanışın"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item3">"Знаходьте у своїх просторах кімнати, до яких можна приєднатися"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Фільтрування, створення та керування просторами стане доступним найближчим часом."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Ласкаво просимо до бета-версії Просторів! У цій першій версії ви можете:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Представляємо Простори"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"Siz yaratgan yoki qo‘shilgan maydonlarni ko‘rish"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Maydonlarga takliflarni qabul qilish yoki rad etish"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Maydonlaringizga qo‘shilishingiz mumkin bo‘lgan xonalarni kashf eting"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Jamoat maydonlariga qo‘shilish"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Kirgan maydonlaringizni tark eting"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Maydonlarni filtrlash, yaratish va boshqarish tez orada amalga oshiriladi."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Maydonlar beta versiyasiga xush kelibsiz! Bu birinchi versiya bilan siz:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Maydonlar bilan tanishish"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"檢視您建立或加入的空間"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"接受或拒絕空間邀請"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"探索空間內您可以加入的任何聊天室"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"加入公開空間"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"離開任何您已加入的空間"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"篩選、建立與管理空間功能即將推出。"</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"歡迎使用空間的測試版!此初始版本可讓您:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"介紹空間"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"查看您创建或加入的空间"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"接受或拒绝空间邀请"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"发现您可以加入空间的所有房间"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"加入公共空间"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"离开你加入的所有空间"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"筛选、创建及管理空间功能即将上线。"</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"欢迎使用空间测试版!使用首个版本,您可以:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"空间简介"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
|
||||||
<string name="screen_space_announcement_item1">"View spaces you\'ve created or joined"</string>
|
|
||||||
<string name="screen_space_announcement_item2">"Accept or decline invites to spaces"</string>
|
|
||||||
<string name="screen_space_announcement_item3">"Discover any rooms you can join in your spaces"</string>
|
|
||||||
<string name="screen_space_announcement_item4">"Join public spaces"</string>
|
|
||||||
<string name="screen_space_announcement_item5">"Leave any spaces you’ve joined"</string>
|
|
||||||
<string name="screen_space_announcement_notice">"Filtering, creating and managing spaces is coming soon."</string>
|
|
||||||
<string name="screen_space_announcement_subtitle">"Welcome to the beta version of Spaces! With this first version you can:"</string>
|
|
||||||
<string name="screen_space_announcement_title">"Introducing Spaces"</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -6,11 +6,14 @@
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:OptIn(ExperimentalTestApi::class)
|
||||||
|
|
||||||
package io.element.android.features.announcement.impl.fullscreen
|
package io.element.android.features.announcement.impl.fullscreen
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
import androidx.compose.ui.test.ExperimentalTestApi
|
||||||
|
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import io.element.android.features.announcement.api.Announcement
|
import io.element.android.features.announcement.api.Announcement
|
||||||
import io.element.android.features.announcement.impl.AnnouncementEvent
|
import io.element.android.features.announcement.impl.AnnouncementEvent
|
||||||
|
|
@ -20,43 +23,39 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
import io.element.android.tests.testutils.clickOn
|
import io.element.android.tests.testutils.clickOn
|
||||||
import io.element.android.tests.testutils.pressBackKey
|
import io.element.android.tests.testutils.pressBackKey
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TestRule
|
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class FullscreenAnnouncementViewTest {
|
class FullscreenAnnouncementViewTest {
|
||||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on back sends a AnnouncementEvent`() {
|
fun `clicking on back sends a AnnouncementEvent`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<AnnouncementEvent>()
|
val eventsRecorder = EventsRecorder<AnnouncementEvent>()
|
||||||
rule.setFullscreenAnnouncementView(
|
setFullscreenAnnouncementView(
|
||||||
anAnnouncementState(
|
anAnnouncementState(
|
||||||
announcement = Announcement.Fullscreen.Space,
|
announcement = Announcement.Fullscreen.Space,
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
rule.pressBackKey()
|
pressBackKey()
|
||||||
eventsRecorder.assertSingle(AnnouncementEvent.Continue(Announcement.Fullscreen.Space))
|
eventsRecorder.assertSingle(AnnouncementEvent.Continue(Announcement.Fullscreen.Space))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clicking on Continue sends a AnnouncementEvent`() {
|
fun `clicking on Continue sends a AnnouncementEvent`() = runAndroidComposeUiTest {
|
||||||
val eventsRecorder = EventsRecorder<AnnouncementEvent>()
|
val eventsRecorder = EventsRecorder<AnnouncementEvent>()
|
||||||
rule.setFullscreenAnnouncementView(
|
setFullscreenAnnouncementView(
|
||||||
anAnnouncementState(
|
anAnnouncementState(
|
||||||
announcement = Announcement.Fullscreen.Space,
|
announcement = Announcement.Fullscreen.Space,
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
rule.clickOn(CommonStrings.action_continue)
|
clickOn(CommonStrings.action_continue)
|
||||||
eventsRecorder.assertSingle(AnnouncementEvent.Continue(Announcement.Fullscreen.Space))
|
eventsRecorder.assertSingle(AnnouncementEvent.Continue(Announcement.Fullscreen.Space))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setFullscreenAnnouncementView(
|
private fun AndroidComposeUiTest<ComponentActivity>.setFullscreenAnnouncementView(
|
||||||
state: AnnouncementState,
|
state: AnnouncementState,
|
||||||
) {
|
) {
|
||||||
setContent {
|
setContent {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue