fix(guide): use fitWidth to prevent image stretching + add debug logs
- Change BoxFit.cover to BoxFit.fitWidth for guide page images - Add screen info logging (resolution, pixel ratio, aspect ratio) - Add detailed avatar loading logs in frontend and backend - Log avatarUrl from DB and API response during recovery 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a3c0d3948d
commit
243105f97f
|
|
@ -43,6 +43,10 @@ export class RecoverByMnemonicHandler {
|
|||
|
||||
// 如果头像为空,重新生成一个
|
||||
let avatarUrl = account.avatarUrl;
|
||||
this.logger.log(`Account ${command.accountSequence} avatarUrl from DB: ${avatarUrl ? `长度=${avatarUrl.length}` : 'null'}`);
|
||||
if (avatarUrl) {
|
||||
this.logger.log(`Account ${command.accountSequence} avatarUrl前50字符: ${avatarUrl.substring(0, 50)}`);
|
||||
}
|
||||
if (!avatarUrl) {
|
||||
this.logger.log(`Account ${command.accountSequence} has no avatar, generating new one`);
|
||||
avatarUrl = generateRandomAvatarSvg();
|
||||
|
|
@ -62,7 +66,7 @@ export class RecoverByMnemonicHandler {
|
|||
await this.eventPublisher.publishAll(account.domainEvents);
|
||||
account.clearDomainEvents();
|
||||
|
||||
return {
|
||||
const result = {
|
||||
userId: account.userId.toString(),
|
||||
accountSequence: account.accountSequence.value,
|
||||
nickname: account.nickname,
|
||||
|
|
@ -71,5 +75,10 @@ export class RecoverByMnemonicHandler {
|
|||
accessToken: tokens.accessToken,
|
||||
refreshToken: tokens.refreshToken,
|
||||
};
|
||||
|
||||
this.logger.log(`RecoverByMnemonic result - accountSequence: ${result.accountSequence}, nickname: ${result.nickname}`);
|
||||
this.logger.log(`RecoverByMnemonic result - avatarUrl: ${result.avatarUrl ? `长度=${result.avatarUrl.length}` : 'null'}`);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,11 +199,16 @@ class RecoverAccountResponse {
|
|||
|
||||
factory RecoverAccountResponse.fromJson(Map<String, dynamic> json) {
|
||||
debugPrint('[AccountService] 解析 RecoverAccountResponse: ${json.keys.toList()}');
|
||||
final avatarUrl = json['avatarUrl'] as String?;
|
||||
debugPrint('[AccountService] RecoverAccountResponse.avatarUrl: ${avatarUrl != null ? "长度=${avatarUrl.length}" : "null"}');
|
||||
if (avatarUrl != null && avatarUrl.isNotEmpty) {
|
||||
debugPrint('[AccountService] RecoverAccountResponse.avatarUrl前50字符: ${avatarUrl.substring(0, avatarUrl.length > 50 ? 50 : avatarUrl.length)}');
|
||||
}
|
||||
return RecoverAccountResponse(
|
||||
userId: json['userId'] as String,
|
||||
userSerialNum: json['accountSequence'] as int,
|
||||
username: json['nickname'] as String,
|
||||
avatarSvg: json['avatarUrl'] as String?,
|
||||
avatarSvg: avatarUrl,
|
||||
referralCode: json['referralCode'] as String,
|
||||
accessToken: json['accessToken'] as String,
|
||||
refreshToken: json['refreshToken'] as String,
|
||||
|
|
@ -884,12 +889,15 @@ class AccountService {
|
|||
value: response.username,
|
||||
);
|
||||
|
||||
if (response.avatarSvg != null) {
|
||||
if (response.avatarSvg != null && response.avatarSvg!.isNotEmpty) {
|
||||
debugPrint('$_tag _saveRecoverAccountData() - 保存 avatarSvg (长度: ${response.avatarSvg!.length})');
|
||||
debugPrint('$_tag _saveRecoverAccountData() - avatarSvg前50字符: ${response.avatarSvg!.substring(0, response.avatarSvg!.length > 50 ? 50 : response.avatarSvg!.length)}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.avatarSvg,
|
||||
value: response.avatarSvg!,
|
||||
);
|
||||
} else {
|
||||
debugPrint('$_tag _saveRecoverAccountData() - ⚠️ avatarSvg 为空! response.avatarSvg=${response.avatarSvg}');
|
||||
}
|
||||
|
||||
// 保存 Token
|
||||
|
|
|
|||
|
|
@ -38,6 +38,31 @@ class _GuidePageState extends ConsumerState<GuidePage> {
|
|||
final PageController _pageController = PageController();
|
||||
int _currentPage = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 延迟到 build 后获取屏幕信息
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_logScreenInfo();
|
||||
});
|
||||
}
|
||||
|
||||
/// 打印屏幕信息用于调试
|
||||
void _logScreenInfo() {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
final screenSize = mediaQuery.size;
|
||||
final devicePixelRatio = mediaQuery.devicePixelRatio;
|
||||
final physicalSize = screenSize * devicePixelRatio;
|
||||
|
||||
debugPrint('[GuidePage] ========== 屏幕信息 ==========');
|
||||
debugPrint('[GuidePage] 逻辑分辨率: ${screenSize.width.toStringAsFixed(1)} x ${screenSize.height.toStringAsFixed(1)}');
|
||||
debugPrint('[GuidePage] 设备像素比: $devicePixelRatio');
|
||||
debugPrint('[GuidePage] 物理分辨率: ${physicalSize.width.toStringAsFixed(0)} x ${physicalSize.height.toStringAsFixed(0)}');
|
||||
debugPrint('[GuidePage] 屏幕宽高比: ${(screenSize.width / screenSize.height).toStringAsFixed(3)} (${screenSize.width.toStringAsFixed(0)}:${screenSize.height.toStringAsFixed(0)})');
|
||||
debugPrint('[GuidePage] 图片设计比例: 0.5625 (1080:1920 = 9:16)');
|
||||
debugPrint('[GuidePage] ================================');
|
||||
}
|
||||
|
||||
// 向导页1-5的数据 (第5页为欢迎加入页)
|
||||
// 支持 png、jpg、webp 等格式
|
||||
final List<GuidePageData> _guidePages = const [
|
||||
|
|
@ -121,37 +146,50 @@ class _GuidePageState extends ConsumerState<GuidePage> {
|
|||
}
|
||||
|
||||
/// 构建向导页 (页面1-4) - 全屏背景图片,无文字
|
||||
/// 使用 BoxFit.fitWidth 保持图片原始比例,不拉伸文字
|
||||
Widget _buildGuidePage(GuidePageData data, int index) {
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// 全屏背景图片
|
||||
if (data.imagePath != null)
|
||||
Image.asset(
|
||||
data.imagePath!,
|
||||
fit: BoxFit.cover,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
child: _buildPlaceholderImage(index),
|
||||
);
|
||||
},
|
||||
)
|
||||
else
|
||||
Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
child: _buildPlaceholderImage(index),
|
||||
debugPrint('[GuidePage] _buildGuidePage() - 页面 ${index + 1}, 图片: ${data.imagePath}');
|
||||
return Container(
|
||||
color: Colors.black, // 如果图片不够高,上下用黑色填充
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// 全屏背景图片 - 使用 fitWidth 保持宽高比
|
||||
if (data.imagePath != null)
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
debugPrint('[GuidePage] 页面 ${index + 1} 容器尺寸: ${constraints.maxWidth.toStringAsFixed(1)} x ${constraints.maxHeight.toStringAsFixed(1)}');
|
||||
debugPrint('[GuidePage] 页面 ${index + 1} 使用 BoxFit.fitWidth');
|
||||
return Center(
|
||||
child: Image.asset(
|
||||
data.imagePath!,
|
||||
fit: BoxFit.fitWidth,
|
||||
width: double.infinity,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
debugPrint('[GuidePage] 页面 ${index + 1} 图片加载失败: $error');
|
||||
return Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
child: _buildPlaceholderImage(index),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
else
|
||||
Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
child: _buildPlaceholderImage(index),
|
||||
),
|
||||
// 底部页面指示器
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 80.h,
|
||||
child: _buildPageIndicator(),
|
||||
),
|
||||
// 底部页面指示器
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 80.h,
|
||||
child: _buildPageIndicator(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -385,39 +423,42 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
|
|||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// 全屏背景图片
|
||||
if (widget.backgroundImage != null)
|
||||
Image.asset(
|
||||
widget.backgroundImage!,
|
||||
fit: BoxFit.cover,
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
);
|
||||
},
|
||||
)
|
||||
else
|
||||
child: Container(
|
||||
color: Colors.black, // 如果图片不够高,上下用黑色填充
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// 全屏背景图片 - 使用 fitWidth 保持宽高比
|
||||
if (widget.backgroundImage != null)
|
||||
Center(
|
||||
child: Image.asset(
|
||||
widget.backgroundImage!,
|
||||
fit: BoxFit.fitWidth,
|
||||
width: double.infinity,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
),
|
||||
// 半透明遮罩,让内容更清晰
|
||||
Container(
|
||||
color: const Color(0xFFFFF8E7),
|
||||
),
|
||||
// 半透明遮罩,让内容更清晰
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.black.withValues(alpha: 0.3),
|
||||
Colors.black.withValues(alpha: 0.6),
|
||||
],
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.black.withValues(alpha: 0.3),
|
||||
Colors.black.withValues(alpha: 0.6),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 内容区域
|
||||
SafeArea(
|
||||
child: LayoutBuilder(
|
||||
|
|
@ -526,6 +567,7 @@ class _WelcomePageContentState extends ConsumerState<_WelcomePageContent> {
|
|||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue