chore: publish native ui polish release v2.5.3
This commit is contained in:
@@ -90,7 +90,7 @@ Android APK:
|
||||
- 已生成 Android debug APK:`android/app/build/outputs/apk/debug/app-debug.apk`
|
||||
- 已生成 Android signed release APK:`android/app/build/outputs/apk/release/app-release.apk`
|
||||
- `npm run apk:release` 还会额外产出带版本号的文件:`android/app/build/outputs/apk/release/boss-android-v{versionName}-release.apk`
|
||||
- 当前最新 release 构建版本:`2.5.2`(`versionCode=15`)
|
||||
- 当前最新 release 构建版本:`2.5.3`(`versionCode=16`)
|
||||
- 当前 APK 已切到原生 Android 客户端:`MainActivity + BossApiClient + 原生 XML 布局`
|
||||
- 当前原生活动页已经覆盖:会话首页、项目详情、项目目标、版本记录、会话信息、群资料、发起群聊、消息转发、线程详情、设备详情、添加设备、账号与安全、设置、AI 账号、技能、运维中心、关于
|
||||
- 当前原生一级体验已回退到微信式交互:`会话 / 设备 / 我的` 固定底部 tab,会话首页是简单聊天列表,`主 Agent / 审计对话` 以普通置顶会话样式排在最前;项目详情页是聊天优先,只保留 `项目目标 / 版本记录` 两个轻入口
|
||||
@@ -112,6 +112,7 @@ Android APK:
|
||||
- `2.5.0` 已补齐聊天附件主链:原生聊天框左侧 `+` 会打开底部抽屉,支持图片 / 视频 / 文件发送;默认走服务器文件存储,`我的 > 附件与存储` 可切到阿里 OSS 私有桶;附件消息已支持下载 / 打开、手动分析、自动分析状态,以及带 task token 的主 Agent 附件分析链接
|
||||
- `2.5.1` 继续收口微信式原生 UI:聊天页普通态顶部已隐藏刷新按钮,只保留右上角“信息”;发起群聊页顶部说明和选择区已压成更轻的会话式密度,候选线程继续复用微信式会话卡片
|
||||
- `2.5.2` 继续补齐深层原生页:`项目目标 / 版本迭代记录 / 会话信息 / 群资料` 已进一步向设计图收口;附件消息卡片的分析状态和动作文案也压成了更轻的微信式层级
|
||||
- `2.5.3` 继续压缩原生聊天与建群页面:`发起群聊` 页已收成轻量头部 + hint pill + 一层操作区;聊天页里自己发出的消息顶部元信息已收成只显示时间,不再重复 `你 · 时间`
|
||||
|
||||
## 本地启动
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ android {
|
||||
applicationId "com.hyzq.boss"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 15
|
||||
versionName "2.5.2"
|
||||
versionCode 16
|
||||
versionName "2.5.3"
|
||||
buildConfigField "String", "BOSS_API_BASE_URL", "\"https://boss.hyzq.net\""
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -912,10 +912,7 @@ public final class BossUi {
|
||||
wrapper.setLayoutParams(wrapperParams);
|
||||
|
||||
TextView metaView = new TextView(context);
|
||||
String metaText = senderLabel;
|
||||
if (!TextUtils.isEmpty(meta)) {
|
||||
metaText = metaText + " · " + meta;
|
||||
}
|
||||
String metaText = buildMessageMetaText(senderLabel, meta, outgoing);
|
||||
metaView.setText(metaText);
|
||||
metaView.setTextSize(11);
|
||||
metaView.setTextColor(context.getColor(R.color.boss_text_soft));
|
||||
@@ -1049,10 +1046,7 @@ public final class BossUi {
|
||||
wrapper.setLayoutParams(wrapperParams);
|
||||
|
||||
TextView metaView = new TextView(context);
|
||||
String metaText = senderLabel;
|
||||
if (!TextUtils.isEmpty(meta)) {
|
||||
metaText = metaText + " · " + meta;
|
||||
}
|
||||
String metaText = buildMessageMetaText(senderLabel, meta, outgoing);
|
||||
metaView.setText(metaText);
|
||||
metaView.setTextSize(11);
|
||||
metaView.setTextColor(context.getColor(R.color.boss_text_soft));
|
||||
@@ -1061,6 +1055,23 @@ public final class BossUi {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private static String buildMessageMetaText(
|
||||
String senderLabel,
|
||||
@Nullable String meta,
|
||||
boolean outgoing
|
||||
) {
|
||||
if (outgoing && !TextUtils.isEmpty(meta)) {
|
||||
return meta;
|
||||
}
|
||||
if (TextUtils.isEmpty(meta)) {
|
||||
return senderLabel;
|
||||
}
|
||||
if (TextUtils.isEmpty(senderLabel)) {
|
||||
return meta;
|
||||
}
|
||||
return senderLabel + " · " + meta;
|
||||
}
|
||||
|
||||
private static TextView buildAttachmentPrimaryText(Context context, String text) {
|
||||
TextView primary = new TextView(context);
|
||||
primary.setText(TextUtils.isEmpty(text) ? "未命名附件" : text);
|
||||
|
||||
@@ -2,8 +2,11 @@ package com.hyzq.boss;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -85,15 +88,13 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
? sourceProjectName
|
||||
: threadMeta.optString("threadDisplayName", sourceProjectName == null ? "当前会话" : sourceProjectName);
|
||||
}
|
||||
for (SummaryCardSpec cardSpec : buildHeaderCardSpecs(
|
||||
appendContent(buildHeaderView(
|
||||
hasSourceProject(),
|
||||
sourceProjectId,
|
||||
sourceProjectName,
|
||||
threadMeta,
|
||||
participants
|
||||
)) {
|
||||
appendContent(BossUi.buildCard(this, cardSpec.title, cardSpec.body, cardSpec.meta));
|
||||
}
|
||||
));
|
||||
|
||||
if (rebuildCandidates) {
|
||||
List<JSONObject> selectableConversations = collectSelectableConversationItems(conversationsPayload, sourceProjectId);
|
||||
@@ -121,16 +122,10 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
lastCandidateProjectIds.addAll(nextCandidateProjectIds);
|
||||
}
|
||||
|
||||
SummaryCardSpec selectionCard = buildSelectionCardSpec(
|
||||
candidates.size(),
|
||||
selectedProjectIds.size(),
|
||||
hasSourceProject()
|
||||
);
|
||||
appendContent(BossUi.buildCard(
|
||||
appendContent(buildSectionLabel("选择其他线程"));
|
||||
appendContent(BossUi.buildHintPill(
|
||||
this,
|
||||
selectionCard.title,
|
||||
selectionCard.body,
|
||||
selectionCard.meta
|
||||
buildSelectionHintText(candidates.size(), selectedProjectIds.size(), hasSourceProject())
|
||||
));
|
||||
|
||||
candidateListLayout = new LinearLayout(this);
|
||||
@@ -145,16 +140,53 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
|
||||
createButton = BossUi.buildPrimaryButton(this, "创建群聊");
|
||||
createButton.setOnClickListener(v -> createGroupChat());
|
||||
appendContent(createButton);
|
||||
|
||||
Button cancelButton = BossUi.buildSecondaryButton(this, "取消");
|
||||
cancelButton.setOnClickListener(v -> finish());
|
||||
appendContent(cancelButton);
|
||||
appendContent(BossUi.buildInlineActionRow(this, cancelButton, createButton));
|
||||
|
||||
setRefreshing(false);
|
||||
updateCreateButtonState();
|
||||
}
|
||||
|
||||
private View buildHeaderView(
|
||||
boolean hasSourceProject,
|
||||
@Nullable String sourceProjectId,
|
||||
@Nullable String sourceProjectName,
|
||||
@Nullable JSONObject threadMeta,
|
||||
@Nullable JSONArray participants
|
||||
) {
|
||||
if (hasSourceProject) {
|
||||
return BossUi.buildSimpleProfileHeader(
|
||||
this,
|
||||
TextUtils.isEmpty(sourceProjectName) ? "当前会话" : sourceProjectName,
|
||||
"从当前会话发起群聊",
|
||||
buildSourceHeaderDetail(sourceProjectId, threadMeta, participants)
|
||||
);
|
||||
}
|
||||
return BossUi.buildSimpleProfileHeader(
|
||||
this,
|
||||
"发起新群聊",
|
||||
"从会话列表直接建群",
|
||||
"至少选择 2 个线程后创建新群"
|
||||
);
|
||||
}
|
||||
|
||||
private TextView buildSectionLabel(String text) {
|
||||
TextView label = new TextView(this);
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
params.leftMargin = BossUi.dp(this, 16);
|
||||
params.rightMargin = BossUi.dp(this, 16);
|
||||
params.bottomMargin = BossUi.dp(this, 6);
|
||||
label.setLayoutParams(params);
|
||||
label.setText(text);
|
||||
label.setTextSize(13);
|
||||
label.setTextColor(getColor(R.color.boss_text_muted));
|
||||
return label;
|
||||
}
|
||||
|
||||
static List<JSONObject> collectSelectableConversationItems(@Nullable JSONObject conversationsPayload, String sourceProjectId) {
|
||||
List<JSONObject> result = new ArrayList<>();
|
||||
JSONArray conversations = conversationsPayload == null ? null : conversationsPayload.optJSONArray("conversations");
|
||||
@@ -192,65 +224,39 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
);
|
||||
}
|
||||
|
||||
static List<SummaryCardSpec> buildHeaderCardSpecs(
|
||||
boolean hasSourceProject,
|
||||
static String buildSourceHeaderDetail(
|
||||
@Nullable String sourceProjectId,
|
||||
@Nullable String sourceProjectName,
|
||||
@Nullable JSONObject threadMeta,
|
||||
@Nullable JSONArray participants
|
||||
) {
|
||||
List<SummaryCardSpec> cards = new ArrayList<>(1);
|
||||
if (hasSourceProject) {
|
||||
String resolvedSourceProjectName = sourceProjectName == null || sourceProjectName.isEmpty()
|
||||
? "当前会话"
|
||||
: sourceProjectName;
|
||||
cards.add(new SummaryCardSpec(
|
||||
resolvedSourceProjectName,
|
||||
buildSourceBody(sourceProjectId, threadMeta, participants),
|
||||
"新群会单独创建,原会话保留"
|
||||
));
|
||||
return cards;
|
||||
}
|
||||
cards.add(new SummaryCardSpec(
|
||||
"从会话中发起群聊",
|
||||
"至少选择 2 个线程,新群会单独创建。",
|
||||
"原有单线程会话会保留"
|
||||
));
|
||||
return cards;
|
||||
return buildSourceBody(sourceProjectId, threadMeta, participants);
|
||||
}
|
||||
|
||||
static SummaryCardSpec buildSelectionCardSpec(
|
||||
static String buildSelectionHintText(
|
||||
int candidateCount,
|
||||
int selectedCount,
|
||||
boolean hasSourceProject
|
||||
) {
|
||||
if (candidateCount <= 0) {
|
||||
return new SummaryCardSpec(
|
||||
"选择其他线程",
|
||||
"当前没有可加入的其他线程",
|
||||
"候选 0 个 · 已选 0 个"
|
||||
);
|
||||
return "当前没有可加入的其他线程";
|
||||
}
|
||||
if (selectedCount <= 0) {
|
||||
return new SummaryCardSpec(
|
||||
"选择其他线程",
|
||||
hasSourceProject ? "至少选择 1 个其他线程" : "至少选择 2 个线程",
|
||||
"候选 " + candidateCount + " 个 · 已选 0 个"
|
||||
);
|
||||
return hasSourceProject ? "至少选择 1 个其他线程" : "至少选择 2 个线程";
|
||||
}
|
||||
return new SummaryCardSpec(
|
||||
"选择其他线程",
|
||||
"继续点选可调整成员",
|
||||
"候选 " + candidateCount + " 个 · 已选 " + selectedCount + " 个"
|
||||
);
|
||||
return "已选 " + selectedCount + " 个线程";
|
||||
}
|
||||
|
||||
private LinearLayout buildCandidateRow(CandidateConversation candidate) {
|
||||
return BossUi.buildConversationRow(
|
||||
LinearLayout row = BossUi.buildConversationRow(
|
||||
this,
|
||||
toCandidateConversationRow(candidate.sourceItem, selectedProjectIds.contains(candidate.projectId)),
|
||||
v -> toggleSelection(candidate.projectId)
|
||||
);
|
||||
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) row.getLayoutParams();
|
||||
params.bottomMargin = BossUi.dp(this, 8);
|
||||
row.setLayoutParams(params);
|
||||
row.setPadding(BossUi.dp(this, 12), BossUi.dp(this, 12), BossUi.dp(this, 12), BossUi.dp(this, 12));
|
||||
return row;
|
||||
}
|
||||
|
||||
private void toggleSelection(String projectId) {
|
||||
@@ -399,7 +405,7 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
String folderName = threadMeta == null ? "" : threadMeta.optString("folderName", "");
|
||||
String resolvedFolderName = folderName.isEmpty() ? "未命名文件夹" : folderName;
|
||||
String resolvedThreadId = threadId == null || threadId.isEmpty() ? "未命名线程" : threadId;
|
||||
return "来源线程 " + resolvedThreadId
|
||||
return resolvedThreadId
|
||||
+ " · "
|
||||
+ resolvedFolderName
|
||||
+ " · "
|
||||
@@ -407,18 +413,6 @@ public class GroupCreateActivity extends BossScreenActivity {
|
||||
+ " 个参与线程";
|
||||
}
|
||||
|
||||
static final class SummaryCardSpec {
|
||||
final String title;
|
||||
final String body;
|
||||
final String meta;
|
||||
|
||||
SummaryCardSpec(String title, String body, String meta) {
|
||||
this.title = title;
|
||||
this.body = body;
|
||||
this.meta = meta;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CandidateConversation {
|
||||
private final String projectId;
|
||||
private final JSONObject sourceItem;
|
||||
|
||||
@@ -14,7 +14,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class GroupCreateActivityTest {
|
||||
@Test
|
||||
public void buildHeaderCardSpecs_collapsesSourceFlowIntoSingleCompactCard() {
|
||||
public void buildSourceHeaderDetail_usesCompactWechatSummary() {
|
||||
JSONObject threadMeta = new StubJSONObject()
|
||||
.withString("threadDisplayName", "北区试产线回归")
|
||||
.withString("threadId", "thread-7")
|
||||
@@ -25,27 +25,20 @@ public class GroupCreateActivityTest {
|
||||
new StubJSONObject()
|
||||
);
|
||||
|
||||
List<GroupCreateActivity.SummaryCardSpec> cards = GroupCreateActivity.buildHeaderCardSpecs(
|
||||
true,
|
||||
String detail = GroupCreateActivity.buildSourceHeaderDetail(
|
||||
"source-1",
|
||||
"北区试产线回归",
|
||||
threadMeta,
|
||||
participants
|
||||
);
|
||||
|
||||
assertEquals(1, cards.size());
|
||||
assertEquals("北区试产线回归", cards.get(0).title);
|
||||
assertEquals("来源线程 thread-7 · Mac Studio · 3 个参与线程", cards.get(0).body);
|
||||
assertEquals("新群会单独创建,原会话保留", cards.get(0).meta);
|
||||
assertEquals("thread-7 · Mac Studio · 3 个参与线程", detail);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildSelectionCardSpec_usesCompactWechatStyleHint() {
|
||||
GroupCreateActivity.SummaryCardSpec card = GroupCreateActivity.buildSelectionCardSpec(5, 0, true);
|
||||
|
||||
assertEquals("选择其他线程", card.title);
|
||||
assertEquals("至少选择 1 个其他线程", card.body);
|
||||
assertEquals("候选 5 个 · 已选 0 个", card.meta);
|
||||
public void buildSelectionHintText_usesCompactWechatStyleHint() {
|
||||
assertEquals("至少选择 1 个其他线程", GroupCreateActivity.buildSelectionHintText(5, 0, true));
|
||||
assertEquals("已选 2 个线程", GroupCreateActivity.buildSelectionHintText(5, 2, true));
|
||||
assertEquals("当前没有可加入的其他线程", GroupCreateActivity.buildSelectionHintText(0, 0, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -40,11 +40,10 @@ public class GroupCreateActivityUiTest {
|
||||
|
||||
LinearLayout content = activity.findViewById(R.id.screen_content);
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(0), "北区试产线回归"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(0), "来源线程 thread-7 · Mac Studio · 3 个参与线程"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(0), "新群会单独创建,原会话保留"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(0), "从当前会话发起群聊"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(0), "thread-7 · Mac Studio · 3 个参与线程"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(1), "选择其他线程"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(1), "继续点选可调整成员"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(1), "候选 2 个 · 已选 2 个"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(2), "已选 2 个线程"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,8 +76,32 @@ public class GroupCreateActivityUiTest {
|
||||
);
|
||||
|
||||
LinearLayout content = activity.findViewById(R.id.screen_content);
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(1), "至少选择 1 个其他线程"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(1), "候选 2 个 · 已选 0 个"));
|
||||
assertTrue(viewTreeContainsText(content.getChildAt(2), "至少选择 1 个其他线程"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderCreatePageUsesInlineActionRowInsteadOfStackedButtons() throws Exception {
|
||||
Intent intent = new Intent()
|
||||
.putExtra(GroupCreateActivity.EXTRA_SOURCE_PROJECT_ID, "source-1")
|
||||
.putExtra(GroupCreateActivity.EXTRA_SOURCE_PROJECT_NAME, "北区试产线回归");
|
||||
TestGroupCreateActivity activity = Robolectric
|
||||
.buildActivity(TestGroupCreateActivity.class, intent)
|
||||
.setup()
|
||||
.get();
|
||||
|
||||
ReflectionHelpers.callInstanceMethod(
|
||||
activity,
|
||||
"renderCreatePage",
|
||||
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildParticipantsPayload()),
|
||||
ReflectionHelpers.ClassParameter.from(JSONObject.class, buildConversationsPayload()),
|
||||
ReflectionHelpers.ClassParameter.from(boolean.class, true)
|
||||
);
|
||||
|
||||
LinearLayout content = activity.findViewById(R.id.screen_content);
|
||||
View lastChild = content.getChildAt(content.getChildCount() - 1);
|
||||
assertTrue(lastChild instanceof LinearLayout);
|
||||
assertTrue(viewTreeContainsText(lastChild, "取消"));
|
||||
assertTrue(viewTreeContainsText(lastChild, "创建群聊"));
|
||||
}
|
||||
|
||||
private static JSONObject buildParticipantsPayload() throws Exception {
|
||||
|
||||
@@ -190,6 +190,42 @@ public class ProjectDetailActivityUiTest {
|
||||
assertFalse(viewTreeContainsText(attachmentView, "已分析"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outgoingAttachmentMetaPrefersTimeOnly() throws Exception {
|
||||
Intent intent = new Intent()
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "project-1")
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "北区试产线回归");
|
||||
TestProjectDetailActivity activity = Robolectric
|
||||
.buildActivity(TestProjectDetailActivity.class, intent)
|
||||
.setup()
|
||||
.get();
|
||||
|
||||
JSONObject attachment = new JSONObject()
|
||||
.put("attachmentId", "att-meta")
|
||||
.put("fileName", "现场照片.jpg")
|
||||
.put("mimeType", "image/jpeg")
|
||||
.put("attachmentKind", "image")
|
||||
.put("analysisState", "queued_auto")
|
||||
.put("fileSizeBytes", 1024);
|
||||
JSONObject message = new JSONObject()
|
||||
.put("id", "msg-meta")
|
||||
.put("kind", "attachment")
|
||||
.put("body", "已发送附件")
|
||||
.put("attachments", new JSONArray().put(attachment));
|
||||
|
||||
View attachmentView = ReflectionHelpers.callInstanceMethod(
|
||||
activity,
|
||||
"buildAttachmentMessageView",
|
||||
ReflectionHelpers.ClassParameter.from(JSONObject.class, message),
|
||||
ReflectionHelpers.ClassParameter.from(String.class, "你"),
|
||||
ReflectionHelpers.ClassParameter.from(String.class, "09:26"),
|
||||
ReflectionHelpers.ClassParameter.from(boolean.class, true)
|
||||
);
|
||||
|
||||
assertTrue(viewTreeContainsText(attachmentView, "09:26"));
|
||||
assertFalse(viewTreeContainsText(attachmentView, "你 · 09:26"));
|
||||
}
|
||||
|
||||
private static View buildBoundMessageView(TestProjectDetailActivity activity, String messageId, String body) {
|
||||
TextView messageView = new TextView(activity);
|
||||
messageView.setText(body);
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
- 邮件:`Postfix + Dovecot`
|
||||
- Android:`AppCompatActivity + 原生 XML 布局 + HttpURLConnection`
|
||||
- 原生登录恢复:`SharedPreferences + restore token`
|
||||
- 当前最新原生 APK:`2.5.2`(`versionCode=15`)
|
||||
- 当前最新原生 APK:`2.5.3`(`versionCode=16`)
|
||||
|
||||
当前不要误判成已经用了:
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ cd /Users/kris/code/boss
|
||||
- 当前已生成 Android debug APK:`android/app/build/outputs/apk/debug/app-debug.apk`
|
||||
- 当前已生成 Android signed release APK:`android/app/build/outputs/apk/release/app-release.apk`
|
||||
- 当前 release 构建还会额外生成带版本号的 APK:`android/app/build/outputs/apk/release/boss-android-v{versionName}-release.apk`
|
||||
- 当前最新 release 构建版本:`2.5.2`(`versionCode=15`)
|
||||
- 当前最新 release 构建版本:`2.5.3`(`versionCode=16`)
|
||||
- 当前 release keystore 位于本机 `android/keystores/boss-release.keystore`,签名参数位于 `android/signing/release-signing.properties`
|
||||
- `2.0.1` 已在本机连接的华为真机上复核通过,修复了 `Theme.SplashScreen` 导致的 `AppCompatActivity` 启动闪退
|
||||
- `2.1.0` 已把 Web 一级页和主要二级页全部补成原生活动页:`MainActivity / ProjectDetailActivity / ProjectGoalsActivity / ProjectVersionsActivity / ProjectForwardActivity / ThreadDetailActivity / DeviceDetailActivity / DeviceEnrollmentActivity / SkillInventoryActivity / SecurityActivity / SettingsActivity / AiAccountsActivity / OpsCenterActivity / AboutActivity`
|
||||
@@ -132,6 +132,8 @@ cd /Users/kris/code/boss
|
||||
- `2.5.1` 已压缩“发起群聊”页首信息密度:来源会话场景只保留一张紧凑摘要卡,选择区改成更短的微信式提示,同时保留会话卡片式候选列表
|
||||
- `2.5.2` 已继续回退深层原生页:`会话信息 / 群资料` 改为轻量头部信息 + 菜单式入口 + 线程列表;`项目目标 / 版本迭代记录` 也已按设计图改成轻卡片结构,不再使用厚按钮和说明块
|
||||
- `2.5.2` 已压缩附件消息卡片的状态层级:`待分析` 收成 `可分析`,`让 AI 分析` 收成 `AI 分析`,有摘要时不再重复显示 `已分析`
|
||||
- `2.5.3` 已继续压缩“发起群聊”页:来源会话摘要改成轻量 profile header,选择区改成 `选择其他线程 + hint pill`,底部按钮收成同层操作区,候选会话卡片纵向间距进一步压缩
|
||||
- `2.5.3` 已把聊天页里自己发出的消息顶部元信息收成只显示时间,不再重复 `你 · 时间`,文本消息、附件卡片和聊天记录卡片都会共用这条规则
|
||||
- 当前附件分析任务已带受控 `task token` 下载链接和文本摘录:本地开发环境会跟随请求 origin 生成链接,生产环境默认走 `https://boss.hyzq.net`
|
||||
- `2.5.x` 当前已补上会话首页独立建群入口:可以不从单线程聊天内部出发,直接在会话首页右上角 `+` 建立新群聊;同时已把多个原生自定义 top bar 页面统一纳入状态栏安全区处理
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"artifactType": "aab",
|
||||
"fileName": "boss-android-v2.5.2-release.aab",
|
||||
"urlPath": "/downloads/boss-android-v2.5.2-release.aab",
|
||||
"sizeBytes": 2912579,
|
||||
"updatedAt": "2026-03-29T12:26:43Z",
|
||||
"sha256": "dca2dc0a080bba282505bacf7e8a37e5aca2e695a657b46df0e184c1ff077d6e",
|
||||
"versionName": "2.5.2",
|
||||
"versionCode": 15,
|
||||
"fileName": "boss-android-v2.5.3-release.aab",
|
||||
"urlPath": "/downloads/boss-android-v2.5.3-release.aab",
|
||||
"sizeBytes": 2912097,
|
||||
"updatedAt": "2026-03-29T12:41:56Z",
|
||||
"sha256": "12b520dba9a9fa3075c374910a595943d3f2a0b9f70a813bdfe8d1546e380d3c",
|
||||
"versionName": "2.5.3",
|
||||
"versionCode": 16,
|
||||
"buildFlavor": "release"
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"fileName": "boss-android-v2.5.2-release.apk",
|
||||
"fileName": "boss-android-v2.5.3-release.apk",
|
||||
"urlPath": "/api/v1/user/ota/package",
|
||||
"sizeBytes": 3089319,
|
||||
"updatedAt": "2026-03-29T12:26:31Z",
|
||||
"sha256": "a27be7abe260c42dcd357206adf292f48bdd33bb14e343c25ee38faeebefd97f",
|
||||
"versionName": "2.5.2",
|
||||
"versionCode": 15,
|
||||
"sizeBytes": 3088834,
|
||||
"updatedAt": "2026-03-29T12:41:51Z",
|
||||
"sha256": "dd44b6e1228966fbd6e83ab53936393024a76e17f7fe996e15442f4f105a435a",
|
||||
"versionName": "2.5.3",
|
||||
"versionCode": 16,
|
||||
"buildFlavor": "release"
|
||||
}
|
||||
|
||||
BIN
public/downloads/boss-android-v2.5.3-release.aab
Normal file
BIN
public/downloads/boss-android-v2.5.3-release.aab
Normal file
Binary file not shown.
BIN
public/downloads/boss-android-v2.5.3-release.apk
Normal file
BIN
public/downloads/boss-android-v2.5.3-release.apk
Normal file
Binary file not shown.
Reference in New Issue
Block a user