Files
Ichino/lib/config/responsive.dart
T
Cookiues 8dda399f76 feat: 旅行伙伴发放与编组、修复退登卡死、优化宽屏布局、加 CI
自动退出登录卡死:_performLogoutAndExit 只 pop() 一层,而解锁/收藏品页是 push
在 HomePage 之上的,退登后被弹回「风险」hub,同时 _loggingOut 仍为 true,
PopScope(canPop:false) + 返回键转圈形成死局。改为 popUntil(isFirst)。

旅行伙伴发不了:它是 ItemKind.Character = 9,与搭档 Partner = 10 是两种东西,
原先收藏品的类型列表 [1,2,3,10,11,12] 里根本没有 9。按客户端实现,角色不走
userItemList(ExportUserItems 不导出 itemKind 9),而是
upsertUserAll.userCharacterList 的 {characterId, level, awakening, useCount},
配 isNewCharacterList 一行一字符。新增发放与 5 槽 charaSlot 编组页,
含「把槽 0 复制到其他槽位」,并校验所选角色确为已拥有或本次待发放。

宽屏布局:各页只有 ConstrainedBox 限宽、没有居中容器,1440 窗口下内容贴左、
右侧大片空白。抽出 responsiveBody 统一居中;B50 预览改用按宽度适配
(InteractiveViewer constrained:false + FittedBox fitWidth),横屏下不再被
contain 缩成中间一小块,导出仍是原始 1762x1850。

CI:.github/workflows/build.yml 先跑 analyze+test 作为门槛,再产出
Windows exe、Android apk、iOS 未签名 ipa(macOS runner,无证书故不可安装)。
README 从 Flutter 模板改写为实际文档,含 path_provider/jni 与 JBR jlink
两个构建环境坑的说明。
2026-09-26 00:37:54 +08:00

79 lines
2.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
/// Breakpoints: phone < 600, tablet 600–900, desktop > 900
const double _breakpointTablet = 600;
const double _breakpointDesktop = 900;
/// Returns a responsive max width for content containers.
/// - Phone: 500
/// - Tablet: 700
/// - Desktop: 900
double responsiveMaxWidth(BuildContext context) {
final width = MediaQuery.of(context).size.width;
if (width >= _breakpointDesktop) return 900;
if (width >= _breakpointTablet) return 700;
return 500;
}
/// Whether the screen is tablet-sized or wider.
bool isTablet(BuildContext context) =>
MediaQuery.of(context).size.width >= _breakpointTablet;
/// Whether the screen is desktop-sized or wider.
bool isDesktop(BuildContext context) =>
MediaQuery.of(context).size.width >= _breakpointDesktop;
/// 把页面内容限制在响应式宽度内,并在宽窗口(桌面/横屏)下水平居中。
/// 之前各页只有 ConstrainedBox 限宽,没有居中容器,1440 宽的窗口里内容
/// 会贴左、右侧留出大片空白。
Widget responsiveBody(BuildContext context, {required Widget child}) {
return Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: responsiveMaxWidth(context)),
child: child,
),
);
}
/// Build columns for tablet/desktop — on phone, each item is full-width;
/// on tablet+ they are laid out in [columns] columns.
List<Widget> responsiveGrid({
required BuildContext context,
required List<Widget> children,
int columns = 2,
double spacing = 12,
}) {
final tablet = isTablet(context);
if (!tablet) return children;
final rows = <Widget>[];
final padded = <Widget>[];
for (int i = 0; i < children.length; i++) {
padded.add(children[i]);
if ((i + 1) % columns == 0 || i == children.length - 1) {
final cols = <Widget>[];
for (int j = 0; j < padded.length; j++) {
cols.add(Expanded(child: padded[j]));
}
// pad incomplete last row with empty expanded widgets
while (cols.length < columns) {
cols.add(const Expanded(child: SizedBox.shrink()));
}
rows.add(Padding(
padding: EdgeInsets.only(bottom: rows.isEmpty ? 0 : spacing),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for (int j = 0; j < cols.length; j++) ...[
if (j > 0) SizedBox(width: spacing),
cols[j],
],
],
),
));
padded.clear();
}
}
return rows;
}