fix(app): X 상세 화면 프로필 사진/표시 이름 누락 수정
- ScheduleDetail에 profileDisplayName, profileAvatarUrl 필드 추가 - X 섹션: profile.displayName으로 표시 이름, profile.avatarUrl로 프로필 사진 표시 - 아바타 URL이 없을 때 이니셜 폴백 유지 - @username 표시 수정 (displayName이 아닌 실제 username 사용) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fc38678fbd
commit
998125333b
2 changed files with 55 additions and 24 deletions
|
|
@ -55,6 +55,9 @@ class ScheduleDetail {
|
||||||
final String? content;
|
final String? content;
|
||||||
final List<String> imageUrls;
|
final List<String> imageUrls;
|
||||||
final String? postUrl;
|
final String? postUrl;
|
||||||
|
// X 프로필
|
||||||
|
final String? profileDisplayName;
|
||||||
|
final String? profileAvatarUrl;
|
||||||
|
|
||||||
ScheduleDetail({
|
ScheduleDetail({
|
||||||
required this.id,
|
required this.id,
|
||||||
|
|
@ -75,6 +78,8 @@ class ScheduleDetail {
|
||||||
this.content,
|
this.content,
|
||||||
this.imageUrls = const [],
|
this.imageUrls = const [],
|
||||||
this.postUrl,
|
this.postUrl,
|
||||||
|
this.profileDisplayName,
|
||||||
|
this.profileAvatarUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory ScheduleDetail.fromJson(Map<String, dynamic> json) {
|
factory ScheduleDetail.fromJson(Map<String, dynamic> json) {
|
||||||
|
|
@ -103,6 +108,8 @@ class ScheduleDetail {
|
||||||
content: json['content'] as String?,
|
content: json['content'] as String?,
|
||||||
imageUrls: (json['imageUrls'] as List<dynamic>?)?.cast<String>() ?? [],
|
imageUrls: (json['imageUrls'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||||
postUrl: json['postUrl'] as String?,
|
postUrl: json['postUrl'] as String?,
|
||||||
|
profileDisplayName: (json['profile'] as Map<String, dynamic>?)?['displayName'] as String?,
|
||||||
|
profileAvatarUrl: (json['profile'] as Map<String, dynamic>?)?['avatarUrl'] as String?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,9 @@ class _ScheduleDetailViewState extends ConsumerState<ScheduleDetailView> {
|
||||||
|
|
||||||
/// X 섹션
|
/// X 섹션
|
||||||
Widget _buildXSection(ScheduleDetail schedule) {
|
Widget _buildXSection(ScheduleDetail schedule) {
|
||||||
final displayName = schedule.username ?? 'Unknown';
|
final username = schedule.username ?? 'Unknown';
|
||||||
|
final displayName = schedule.profileDisplayName ?? username;
|
||||||
|
final avatarUrl = schedule.profileAvatarUrl;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -440,28 +442,24 @@ class _ScheduleDetailViewState extends ConsumerState<ScheduleDetailView> {
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
// 프로필 이미지
|
// 프로필 이미지
|
||||||
Container(
|
avatarUrl != null
|
||||||
width: 40,
|
? ClipOval(
|
||||||
height: 40,
|
child: CachedNetworkImage(
|
||||||
decoration: BoxDecoration(
|
imageUrl: avatarUrl,
|
||||||
gradient: LinearGradient(
|
width: 40,
|
||||||
begin: Alignment.topLeft,
|
height: 40,
|
||||||
end: Alignment.bottomRight,
|
fit: BoxFit.cover,
|
||||||
colors: [Colors.grey[700]!, Colors.grey[900]!],
|
placeholder: (_, _) => Container(
|
||||||
),
|
width: 40, height: 40,
|
||||||
shape: BoxShape.circle,
|
decoration: BoxDecoration(
|
||||||
),
|
color: Colors.grey[300],
|
||||||
child: Center(
|
shape: BoxShape.circle,
|
||||||
child: Text(
|
),
|
||||||
displayName[0].toUpperCase(),
|
),
|
||||||
style: const TextStyle(
|
errorWidget: (_, _, _) => _buildAvatarFallback(displayName),
|
||||||
color: Colors.white,
|
),
|
||||||
fontWeight: FontWeight.bold,
|
)
|
||||||
fontSize: 16,
|
: _buildAvatarFallback(displayName),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -484,7 +482,7 @@ class _ScheduleDetailViewState extends ConsumerState<ScheduleDetailView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'@$displayName',
|
'@$username',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: Colors.grey[500],
|
color: Colors.grey[500],
|
||||||
|
|
@ -691,6 +689,32 @@ class _ScheduleDetailViewState extends ConsumerState<ScheduleDetailView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 아바타 폴백 (이니셜)
|
||||||
|
Widget _buildAvatarFallback(String name) {
|
||||||
|
return Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [Colors.grey[700]!, Colors.grey[900]!],
|
||||||
|
),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
name[0].toUpperCase(),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// 인증 배지
|
/// 인증 배지
|
||||||
Widget _buildVerifiedBadge() {
|
Widget _buildVerifiedBadge() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue