forked from baron/baron-sso
App 카드 로고 이미지 표시
This commit is contained in:
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:math' as math;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@@ -1384,6 +1385,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
||||
_ActivityItem(
|
||||
clientId: rp.id,
|
||||
appName: name,
|
||||
logo: rp.logo.trim(),
|
||||
lastAuthAt: lastAuthLabel,
|
||||
status: statusCode,
|
||||
scopes: rp.scopes,
|
||||
@@ -1522,37 +1524,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.appName,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _ink,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Text(
|
||||
item.status == 'active'
|
||||
? tr('ui.userfront.dashboard.activity.linked')
|
||||
: tr('ui.userfront.dashboard.status.revoked'),
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
_buildActivityCardHeader(item, statusColor),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
tr('ui.userfront.dashboard.last_auth_label'),
|
||||
@@ -1658,6 +1630,115 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
||||
return opaqueCard;
|
||||
}
|
||||
|
||||
Widget _buildActivityCardHeader(_ActivityItem item, Color statusColor) {
|
||||
final statusBadge = Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: statusColor,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Text(
|
||||
item.status == 'active'
|
||||
? tr('ui.userfront.dashboard.activity.linked')
|
||||
: tr('ui.userfront.dashboard.status.revoked'),
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
height: 40,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (item.logo.isNotEmpty) ...[
|
||||
_buildActivityLogo(item.logo),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
item.appName,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _ink,
|
||||
height: 1.25,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
statusBadge,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActivityLogo(String logoUrl) {
|
||||
return SizedBox(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: _buildActivityLogoImage(logoUrl),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActivityLogoImage(String logoUrl) {
|
||||
final isSvg = _isSvgLogoUrl(logoUrl);
|
||||
return isSvg
|
||||
? SvgPicture.network(
|
||||
logoUrl,
|
||||
fit: BoxFit.contain,
|
||||
placeholderBuilder: (context) => _buildActivityLogoLoading(),
|
||||
)
|
||||
: Image.network(
|
||||
logoUrl,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return _buildActivityLogoFallback();
|
||||
},
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) {
|
||||
return child;
|
||||
}
|
||||
return _buildActivityLogoLoading();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool _isSvgLogoUrl(String logoUrl) {
|
||||
final normalized = logoUrl.trim().toLowerCase();
|
||||
if (normalized.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
final uri = Uri.tryParse(normalized);
|
||||
final path = uri?.path.toLowerCase() ?? normalized;
|
||||
return path.endsWith('.svg');
|
||||
}
|
||||
|
||||
Widget _buildActivityLogoLoading() {
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActivityLogoFallback() {
|
||||
return Icon(Icons.apps_rounded, size: 20, color: Colors.grey[500]);
|
||||
}
|
||||
|
||||
Widget _buildAccessHistory(AuthTimelineState state, bool isWide) {
|
||||
final sessionsState = ref.watch(userSessionsProvider);
|
||||
if (state.isLoading && state.items.isEmpty) {
|
||||
@@ -2470,6 +2551,7 @@ enum _HistorySessionStatus { current, active, inactive }
|
||||
class _ActivityItem {
|
||||
final String clientId;
|
||||
final String appName;
|
||||
final String logo;
|
||||
final String lastAuthAt;
|
||||
final String status;
|
||||
final String? url;
|
||||
@@ -2482,6 +2564,7 @@ class _ActivityItem {
|
||||
_ActivityItem({
|
||||
required this.clientId,
|
||||
required this.appName,
|
||||
required this.logo,
|
||||
required this.lastAuthAt,
|
||||
required this.status,
|
||||
required this.scopes,
|
||||
|
||||
Reference in New Issue
Block a user