Skip to content
Closed

sys #958

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2936d77
更新
lsfqxd2006 Aug 26, 2026
4d3d4e3
Update core.yml
lsfqxd2006 Aug 26, 2026
65f400f
黑色
lsfqxd2006 Aug 26, 2026
df0125f
Update ic_winged_victory.xml
lsfqxd2006 Aug 26, 2026
9ad35c3
Update ic_winged_victory.xml
lsfqxd2006 Aug 26, 2026
04f0639
Update ic_winged_victory.xml
lsfqxd2006 Aug 26, 2026
aa44aac
图标
lsfqxd2006 Aug 26, 2026
ecbac5e
Add files via upload
lsfqxd2006 Aug 27, 2026
de91230
Add files via upload
lsfqxd2006 Aug 27, 2026
9878e8e
Add files via upload
lsfqxd2006 Aug 27, 2026
c4fdf82
Add files via upload
lsfqxd2006 Aug 27, 2026
0e764ac
Merge pull request #1 from lsfqxd2006/mytest
lsfqxd2006 Aug 27, 2026
f1c87c7
Add files via upload
lsfqxd2006 Aug 27, 2026
54fa056
Center and enhance ApiBadge and ModuleRow UI
lsfqxd2006 Aug 27, 2026
71b76dc
Update ApiBadge.kt
lsfqxd2006 Aug 27, 2026
53765e4
Update ApiBadge.kt
lsfqxd2006 Aug 27, 2026
7763e77
Refine ApiBadge and ModuleRow UI layout and styling
lsfqxd2006 Aug 27, 2026
39e06e7
Improve UI badge text handling and icon clipping
lsfqxd2006 Aug 27, 2026
ddfa803
Update ApiBadge.kt
lsfqxd2006 Aug 27, 2026
8f84866
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
95646c1
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
bc20be1
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
07ad250
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
1ef817e
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
61169d8
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
812f0eb
Update HomeViewModel.kt
lsfqxd2006 Aug 27, 2026
9aea08b
Add files via upload
lsfqxd2006 Aug 28, 2026
adc1154
Merge branch 'JingMatrix:master' into master
lsfqxd2006 Sep 1, 2026
2b62808
Merge branch 'master' into master
lsfqxd2006 Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 11 additions & 118 deletions .github/workflows/core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
# branch came from a fork, and the checked-out HEAD is an ephemeral merge commit that exists
# nowhere and cannot be looked up by anyone who reads it off a device. Both head.* values are
# null outside a pull request, where the defaults are already right.
VECTOR_BASE_REMOTE: upstream
VECTOR_BUILD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
VECTOR_BUILD_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
Expand All @@ -40,6 +41,12 @@ jobs:
with:
submodules: recursive
fetch-depth: 0

- name: Fetch upstream JingMatrix Vector (only master + tags)
run: |
git remote add upstream https://github.com/JingMatrix/Vector.git
git fetch upstream master
git fetch upstream --tags --no-recurse-submodules

# Before anything is built, because it needs nothing but Python and a translator's mistake
# should not wait twenty minutes to surface. Crowdin owns the content of these files, so what
Expand All @@ -57,25 +64,19 @@ jobs:
# to it and cannot be given one, so a fork builds unsigned, as does any branch that is not
# master: neither publishes anything.
- name: Write key
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/master' ) || github.ref_type == 'tag' }}
# pull_request事件不注入密钥,其余(workflow_dispatch / push master / tag)都注入
if: ${{ github.event_name != 'pull_request' }}
env:
KEY_STORE: ${{ secrets.KEY_STORE }}
KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
ALIAS: ${{ secrets.ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
IS_UPSTREAM: ${{ github.repository_owner == 'JingMatrix' }}
run: |
set -euo pipefail
if [ -z "$KEY_STORE" ]; then
if [ "$IS_UPSTREAM" = "true" ]; then
echo "::error::KEY_STORE is empty on ${{ github.ref }}. Refusing to publish an unsigned build."
exit 1
fi
echo "No signing secret on this fork; building unsigned."
echo "::warning::No signing secret, building unsigned debug build."
exit 0
fi
# Through the environment rather than interpolated into the script: a password holding a
# quote would otherwise be pasted into a shell word and mangled, or worse, executed.
{
echo "androidStorePassword=$KEY_STORE_PASSWORD"
echo "androidKeyAlias=$ALIAS"
Expand Down Expand Up @@ -169,112 +170,4 @@ jobs:
path: |
zygisk/build/symbols
daemon/build/symbols
dex2oat/build/symbols

# --- stable release --------------------------------------------------------------------
#
# A pushed `v*` tag is a stable release, not a canary. It is published here from the same
# signed zips this build produced, so cutting a release is `git tag && git push` with nothing
# hand-uploaded afterwards — the hand-assembly is exactly how v2.0's assets came to disagree
# with zygisk/update.json (#811), and an automated attach cannot drift from what was built.
#
# Marked `--latest`, unlike the canaries below: this is what `releases/latest`, and therefore
# the manager's update check, resolves to. The body is the module's own zygisk/changelog.md
# under a GitHub H1 the release page shows. The changelog itself carries no title line — the
# manager renders it beneath its own heading, so a banner there would only read twice.
- name: Publish release
if: ${{ success() && github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }}
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
# `%s` arguments, never the format string, so a `%` anywhere in the changelog is literal.
notes=$(printf '# 🎉 Vector %s 🎉\n\n%s\n' "${TAG#v}" "$(cat zygisk/changelog.md)")

# Recreated rather than edited so a re-run replaces the assets instead of appending a
# second copy. No `--cleanup-tag`: the release is rebuilt, the pushed release tag is kept.
gh release delete "$TAG" --yes 2>/dev/null || true
gh release create "$TAG" \
--latest \
--title "Vector ${TAG}" \
--notes "$notes" \
zygisk/release/Vector-v*-Release.zip \
zygisk/release/Vector-v*-Debug.zip

# --- canary distribution ---------------------------------------------------------------
#
# The zips above are also attached to a prerelease, because an Actions artifact cannot be
# downloaded without a GitHub account — `GET /actions/artifacts/<id>/zip` answers 401 to an
# anonymous caller, while a release asset answers 206. Testing a canary is the lowest-friction
# way for an ordinary user to help, so it must not require handing an OAuth grant to anyone,
# and it must work for the many users who cannot reach GitHub's login page at all.
#
# Marked prerelease so `releases/latest` — which is what update checks read — keeps pointing
# at the last stable tag.
- name: Publish canary prerelease
if: >-
success() &&
(github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && github.ref == 'refs/heads/master'))
env:
GH_TOKEN: ${{ github.token }}
VERSION_CODE: ${{ steps.prepareArtifact.outputs.versionCode }}
VERSION_NAME: ${{ steps.prepareArtifact.outputs.versionName }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}
run: |
set -euo pipefail
tag="canary-${VERSION_CODE}"
subject=$(git log -1 --pretty=%s)
short=$(git rev-parse --short HEAD)

notes=$(cat <<EOF
**${subject}**

Built from [\`${short}\`](${COMMIT_URL}) by [run ${{ github.run_id }}](${RUN_URL}).

This is a canary: the current state of \`master\`, tested by CI and nothing else. It is
published here rather than left as a workflow artifact so that it can be downloaded
without a GitHub account.

| Build | Use it when |
| :-- | :-- |
| \`Vector-${VERSION_NAME}-${VERSION_CODE}-Debug.zip\` | You are chasing a bug. Far more logging, and the build maintainers ask for in reports. |
| \`Vector-${VERSION_NAME}-${VERSION_CODE}-Release.zip\` | You just want the newest code. |

Only the five most recent canaries are kept.
EOF
)

# Recreated rather than edited: re-running the workflow for the same commit should
# replace that build, not append a second copy of every asset to it.
gh release delete "$tag" --yes --cleanup-tag 2>/dev/null || true
gh release create "$tag" \
--prerelease \
--target "${{ github.sha }}" \
--title "Vector ${VERSION_NAME} canary ${VERSION_CODE}" \
--notes "$notes" \
zygisk/release/Vector-v*-Release.zip \
zygisk/release/Vector-v*-Debug.zip

# Five is what a tester needs: enough to bisect a regression across a few days, few enough
# that the releases page is still mostly releases. Sorted by version code, which is the commit
# count and therefore monotonic, rather than by date, which reruns and reverts can disorder.
- name: Keep only the five most recent canaries
if: >-
success() &&
(github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && github.ref == 'refs/heads/master'))
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# `grep` exits 1 when nothing matches, which under `pipefail` would fail the step on a
# repository that has no canaries yet. Collected first, then acted on.
tags=$(gh release list --limit 100 --json tagName --jq '.[].tagName' | grep '^canary-' || true)
[ -n "$tags" ] || exit 0
echo "$tags" | sort -t- -k2 -n -r | tail -n +6 | while read -r old; do
echo "Removing $old"
gh release delete "$old" --yes --cleanup-tag
done
dex2oat/build/symbols
38 changes: 0 additions & 38 deletions .github/workflows/crowdin.yml

This file was deleted.

17 changes: 11 additions & 6 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,26 @@ plugins {
}

/** A ValueSource that executes 'git rev-list --count' to get the total commit count. */
abstract class GitCommitCountValueSource : ValueSource<String, ValueSourceParameters.None> {
abstract class GitCommitCountValueSource : ValueSource<String, GitCommitCountValueSource.Parameters> {
interface Parameters : ValueSourceParameters {
val baseRemoteName: Property<String>
}
@get:Inject abstract val execOperations: ExecOperations

override fun obtain(): String {
val remoteName = parameters.baseRemoteName.get()
val output = ByteArrayOutputStream()
val result = execOperations.exec {
commandLine("git", "rev-list", "--count", "refs/remotes/origin/master")
commandLine("git", "rev-list", "--count", "refs/remotes/$remoteName/master")
standardOutput = output
isIgnoreExitValue = true
}
// Return the count if successful, otherwise a default of "1".
return if (result.exitValue == 0 && output.toString().isNotBlank()) {
output.toString().trim()
} else {
"1"
}
}
}

/** A ValueSource that executes 'git tag' to get the latest version tag. */
abstract class GitLatestTagValueSource : ValueSource<String, ValueSourceParameters.None> {
@get:Inject abstract val execOperations: ExecOperations
Expand Down Expand Up @@ -202,7 +203,11 @@ abstract class GitCommitHashValueSource : ValueSource<String, GitCommitHashValue
// the string here and the property name have to stay in step by hand now.
//
// This defers the execution of the git commands and allows Gradle to cache the results.
val versionCodeProvider = providers.of(GitCommitCountValueSource::class.java) {}
val versionCodeProvider = providers.of(GitCommitCountValueSource::class.java) {
parameters.baseRemoteName.set(
providers.environmentVariable("VECTOR_BASE_REMOTE").orElse("origin")
)
}
val versionHashProvider =
providers.of(GitCommitHashValueSource::class.java) {
// Set on every GitHub Actions runner and on nothing else, so the presence of either is
Expand Down
62 changes: 24 additions & 38 deletions daemon/src/main/res/drawable/ic_statue_monochrome.xml

Large diffs are not rendered by default.

38 changes: 21 additions & 17 deletions manager-ui/src/main/kotlin/org/matrix/vector/ui/ApiBadge.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,43 @@ package org.matrix.vector.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.text.style.TextOverflow

/**
* `API 101` / `Xposed 93`, with the scale name small and quiet and the number carrying the colour.
*
* The scale name is context that rarely changes and repeats down every row; the number is the fact
* being checked, so it is the only part given weight and colour. A caller with no value to show
* passes `"?"` for [value] and `incompatible = true`, which keeps the badge the same shape while the
* missing number reads as missing rather than as a different kind of thing.
*
* Model-agnostic on purpose: Vector maps a module's declared API into ([label], [value]); LSPatch
* passes its own text. Both get one badge instead of two that drift apart.
*/
@Composable
fun ApiBadge(label: String, value: String, incompatible: Boolean = false) {
val colors = MaterialTheme.colorScheme
Row(verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.spacedBy(3.dp)) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.Bottom,
) {
Text(
text = label,
style = MaterialTheme.typography.labelSmall.copy(fontSize = 8.sp),
style = MaterialTheme.typography.labelSmall, // ← 统一用 labelMedium
color = colors.onSurfaceVariant.copy(alpha = 0.7f),
maxLines = 1,
overflow = TextOverflow.Clip,
)
Text(
text = " ",
style = MaterialTheme.typography.labelSmall,
color = colors.onSurfaceVariant.copy(alpha = 0.7f),
maxLines = 1,
)
Text(
text = value,
style = MaterialTheme.typography.labelMedium,
fontWeight = FontWeight.SemiBold,
fontWeight = FontWeight.Black,
color = if (incompatible) colors.error else colors.primary,
maxLines = 1,
overflow = TextOverflow.Clip,
)
}
}
}
41 changes: 26 additions & 15 deletions manager-ui/src/main/kotlin/org/matrix/vector/ui/ModuleRow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,24 +131,30 @@ fun ModuleRow(
// leaving the list; a bare tap only reports state, since a one-tap toggle would fire whenever
// a thumb brushed the list.
Column(
modifier =
if (onIconClick != null)
Modifier.contextClickable(onClick = onIconClick, onLongClick = onIconLongClick)
else Modifier,
// Against the text, not centred over the badge: the badge below is wider than the icon,
// so centring left a gap between the icon and the edge the names all start from.
horizontalAlignment = Alignment.End,
modifier = Modifier.width(72.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
// Fixed at the icon's size whatever is drawn inside, so selecting a module cannot resize
// its row — a tick larger than the icon would grow this box and reflow the list.
Box(modifier = Modifier.size(ICON_SIZE), contentAlignment = Alignment.Center) {
// 图标 - 不裁剪,保持应用原生形状
Box(
modifier = Modifier
.size(ICON_SIZE)
.clip(RoundedCornerShape(8.dp))
.then(
if (onIconClick != null)
Modifier.contextClickable(
onClick = onIconClick,
onLongClick = onIconLongClick,
)
else Modifier
),
contentAlignment = Alignment.Center,
) {
icon()
if (selected) {
Box(
modifier =
Modifier.fillMaxSize()
.clip(CircleShape)
.background(colors.primary.copy(alpha = 0.85f)),
modifier = Modifier.fillMaxSize()
.clip(CircleShape)
.background(colors.primary.copy(alpha = 0.85f)),
contentAlignment = Alignment.Center,
) {
Icon(
Expand All @@ -161,7 +167,12 @@ fun ModuleRow(
}
}
Spacer(Modifier.height(6.dp))
apiBadge()
Box(
modifier = Modifier.width(72.dp),
contentAlignment = Alignment.Center,
) {
apiBadge()
}
}

Spacer(Modifier.width(16.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,5 @@ enum class ReleaseDirection {
* row anywhere marked as installed.
*/
fun FrameworkUpdateState.divergesFrom(release: FrameworkRelease?): Boolean {
if (release == null || release.versionCode != installedVersionCode) return false
val mine = buildStamp(installedCommit ?: return false)
if (mine.commit == null || release.commit == null) return false
return !mine.isCommit(release.commit)
return false
}
Loading