优化:积分页面积分同步处理
This commit is contained in:
parent
5cfb4c74af
commit
6ae2b55677
@ -90,7 +90,7 @@ class _MainScaffold extends StatelessWidget {
|
|||||||
body: IndexedStack(
|
body: IndexedStack(
|
||||||
index: currentTab.index,
|
index: currentTab.index,
|
||||||
children: [
|
children: [
|
||||||
const HomeScreen(),
|
HomeScreen(isActive: currentTab == NavTab.home),
|
||||||
GalleryScreen(isActive: currentTab == NavTab.gallery),
|
GalleryScreen(isActive: currentTab == NavTab.gallery),
|
||||||
ProfileScreen(isActive: currentTab == NavTab.profile),
|
ProfileScreen(isActive: currentTab == NavTab.profile),
|
||||||
],
|
],
|
||||||
|
|||||||
30
lib/core/user/account_refresh.dart
Normal file
30
lib/core/user/account_refresh.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import '../api/api_config.dart';
|
||||||
|
import '../api/services/user_api.dart';
|
||||||
|
import '../auth/auth_service.dart';
|
||||||
|
import 'user_state.dart';
|
||||||
|
|
||||||
|
/// 刷新用户账户信息并更新 UserState
|
||||||
|
///
|
||||||
|
/// [updateProfile] 为 true 时,同时更新 avatar 和 userName(用于 Profile 页)
|
||||||
|
Future<void> refreshAccount({bool updateProfile = false}) async {
|
||||||
|
final uid = UserState.userId.value;
|
||||||
|
if (uid == null || uid.isEmpty) return;
|
||||||
|
try {
|
||||||
|
await AuthService.loginComplete;
|
||||||
|
final res = await UserApi.getAccount(
|
||||||
|
sentinel: ApiConfig.appId,
|
||||||
|
asset: uid,
|
||||||
|
);
|
||||||
|
if (!res.isSuccess || res.data == null) return;
|
||||||
|
final data = res.data as Map<String, dynamic>?;
|
||||||
|
final credits = data?['reveal'] as int?;
|
||||||
|
if (credits != null) UserState.setCredits(credits);
|
||||||
|
if (updateProfile) {
|
||||||
|
final avatarUrl = data?['realm'] as String?;
|
||||||
|
UserState.setAvatar(
|
||||||
|
avatarUrl != null && avatarUrl.isNotEmpty ? avatarUrl : null);
|
||||||
|
final name = data?['terminal'] as String?;
|
||||||
|
UserState.setUserName(name != null && name.isNotEmpty ? name : null);
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
@ -8,7 +8,6 @@ import '../../core/api/services/image_api.dart';
|
|||||||
import '../../core/auth/auth_service.dart';
|
import '../../core/auth/auth_service.dart';
|
||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/theme/app_spacing.dart';
|
import '../../core/theme/app_spacing.dart';
|
||||||
import '../../core/user/user_state.dart';
|
|
||||||
import '../../shared/widgets/top_nav_bar.dart';
|
import '../../shared/widgets/top_nav_bar.dart';
|
||||||
|
|
||||||
import 'models/gallery_task_item.dart';
|
import 'models/gallery_task_item.dart';
|
||||||
@ -142,9 +141,7 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
|||||||
appBar: PreferredSize(
|
appBar: PreferredSize(
|
||||||
preferredSize: const Size.fromHeight(56),
|
preferredSize: const Size.fromHeight(56),
|
||||||
child: TopNavBar(
|
child: TopNavBar(
|
||||||
title: 'Gallery',
|
title: 'My Gallery',
|
||||||
credits: UserCreditsData.of(context)?.creditsDisplay ?? '--',
|
|
||||||
onCreditsTap: () => Navigator.of(context).pushNamed('/recharge'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: _loading
|
body: _loading
|
||||||
@ -176,7 +173,8 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
|||||||
onRefresh: () => _loadTasks(refresh: true),
|
onRefresh: () => _loadTasks(refresh: true),
|
||||||
child: _gridItems.isEmpty && !_loading
|
child: _gridItems.isEmpty && !_loading
|
||||||
? SingleChildScrollView(
|
? SingleChildScrollView(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics:
|
||||||
|
const AlwaysScrollableScrollPhysics(),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: constraints.maxHeight - 100,
|
height: constraints.maxHeight - 100,
|
||||||
child: Center(
|
child: Center(
|
||||||
@ -190,7 +188,8 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
: GridView.builder(
|
: GridView.builder(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics:
|
||||||
|
const AlwaysScrollableScrollPhysics(),
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
padding: EdgeInsets.fromLTRB(
|
padding: EdgeInsets.fromLTRB(
|
||||||
AppSpacing.screenPadding,
|
AppSpacing.screenPadding,
|
||||||
@ -206,8 +205,8 @@ class _GalleryScreenState extends State<GalleryScreen> {
|
|||||||
mainAxisSpacing: AppSpacing.xl,
|
mainAxisSpacing: AppSpacing.xl,
|
||||||
crossAxisSpacing: AppSpacing.xl,
|
crossAxisSpacing: AppSpacing.xl,
|
||||||
),
|
),
|
||||||
itemCount:
|
itemCount: _gridItems.length +
|
||||||
_gridItems.length + (_loadingMore ? 1 : 0),
|
(_loadingMore ? 1 : 0),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index >= _gridItems.length) {
|
if (index >= _gridItems.length) {
|
||||||
return const Center(
|
return const Center(
|
||||||
@ -276,17 +275,17 @@ class _GalleryCard extends StatelessWidget {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
child: mediaItem.imageUrl != null
|
child: mediaItem.imageUrl != null
|
||||||
? CachedNetworkImage(
|
? CachedNetworkImage(
|
||||||
imageUrl: mediaItem.imageUrl!,
|
imageUrl: mediaItem.imageUrl!,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
placeholder: (_, __) => Container(
|
placeholder: (_, __) => Container(
|
||||||
color: AppColors.surfaceAlt,
|
color: AppColors.surfaceAlt,
|
||||||
),
|
),
|
||||||
errorWidget: (_, __, ___) => Container(
|
errorWidget: (_, __, ___) => Container(
|
||||||
color: AppColors.surfaceAlt,
|
color: AppColors.surfaceAlt,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: _VideoThumbnailCover(videoUrl: mediaItem.videoUrl!),
|
: _VideoThumbnailCover(videoUrl: mediaItem.videoUrl!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,13 +13,12 @@ import '../../core/log/app_logger.dart';
|
|||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/theme/app_spacing.dart';
|
import '../../core/theme/app_spacing.dart';
|
||||||
import '../../core/theme/app_typography.dart';
|
import '../../core/theme/app_typography.dart';
|
||||||
|
import '../../core/user/account_refresh.dart';
|
||||||
import '../../core/user/user_state.dart';
|
import '../../core/user/user_state.dart';
|
||||||
import '../../features/home/models/task_item.dart';
|
import '../../features/home/models/task_item.dart';
|
||||||
import '../../shared/widgets/top_nav_bar.dart';
|
import '../../shared/widgets/top_nav_bar.dart';
|
||||||
|
|
||||||
import '../../core/api/api_config.dart';
|
|
||||||
import '../../core/api/services/image_api.dart';
|
import '../../core/api/services/image_api.dart';
|
||||||
import '../../core/api/services/user_api.dart';
|
|
||||||
|
|
||||||
/// Generate Video screen - matches Pencil mmLB5
|
/// Generate Video screen - matches Pencil mmLB5
|
||||||
class GenerateVideoScreen extends StatefulWidget {
|
class GenerateVideoScreen extends StatefulWidget {
|
||||||
@ -56,6 +55,7 @@ class _GenerateVideoScreenState extends State<GenerateVideoScreen> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
refreshAccount();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
GenerateVideoScreen._log.d('opened with task: ${widget.task}');
|
GenerateVideoScreen._log.d('opened with task: ${widget.task}');
|
||||||
});
|
});
|
||||||
@ -192,17 +192,7 @@ class _GenerateVideoScreenState extends State<GenerateVideoScreen> {
|
|||||||
final taskId = taskData?['tree'];
|
final taskId = taskData?['tree'];
|
||||||
|
|
||||||
// 创建任务成功后刷新用户账户信息(积分等)
|
// 创建任务成功后刷新用户账户信息(积分等)
|
||||||
final accountRes = await UserApi.getAccount(
|
await refreshAccount();
|
||||||
sentinel: ApiConfig.appId,
|
|
||||||
asset: userId,
|
|
||||||
);
|
|
||||||
if (accountRes.isSuccess && accountRes.data != null) {
|
|
||||||
final accountData = accountRes.data as Map<String, dynamic>?;
|
|
||||||
final credits = accountData?['reveal'] as int?;
|
|
||||||
if (credits != null) {
|
|
||||||
UserState.setCredits(credits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
Navigator.of(context).pushReplacementNamed(
|
Navigator.of(context).pushReplacementNamed(
|
||||||
@ -235,10 +225,8 @@ class _GenerateVideoScreenState extends State<GenerateVideoScreen> {
|
|||||||
preferredSize: const Size.fromHeight(56),
|
preferredSize: const Size.fromHeight(56),
|
||||||
child: TopNavBar(
|
child: TopNavBar(
|
||||||
title: 'Generate Video',
|
title: 'Generate Video',
|
||||||
credits: UserCreditsData.of(context)?.creditsDisplay ?? '--',
|
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onBack: () => Navigator.of(context).pop(),
|
onBack: () => Navigator.of(context).pop(),
|
||||||
onCreditsTap: () => Navigator.of(context).pushNamed('/recharge'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../core/api/services/image_api.dart';
|
import '../../core/api/services/image_api.dart';
|
||||||
import '../../core/user/user_state.dart';
|
|
||||||
import '../../core/auth/auth_service.dart';
|
import '../../core/auth/auth_service.dart';
|
||||||
|
import '../../core/user/account_refresh.dart';
|
||||||
|
import '../../core/user/user_state.dart';
|
||||||
import '../../core/theme/app_spacing.dart';
|
import '../../core/theme/app_spacing.dart';
|
||||||
import '../../shared/widgets/top_nav_bar.dart';
|
import '../../shared/widgets/top_nav_bar.dart';
|
||||||
import 'models/category_item.dart';
|
import 'models/category_item.dart';
|
||||||
@ -12,7 +13,9 @@ import 'widgets/video_card.dart';
|
|||||||
|
|
||||||
/// AI Video App home screen - tab 来自分类接口,Grid 来自任务列表接口
|
/// AI Video App home screen - tab 来自分类接口,Grid 来自任务列表接口
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
const HomeScreen({super.key});
|
const HomeScreen({super.key, this.isActive = true});
|
||||||
|
|
||||||
|
final bool isActive;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<HomeScreen> createState() => _HomeScreenState();
|
State<HomeScreen> createState() => _HomeScreenState();
|
||||||
@ -30,6 +33,15 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_loadCategories();
|
_loadCategories();
|
||||||
|
if (widget.isActive) refreshAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant HomeScreen oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (widget.isActive && !oldWidget.isActive) {
|
||||||
|
refreshAccount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadCategories() async {
|
Future<void> _loadCategories() async {
|
||||||
|
|||||||
@ -2,9 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_lucide/flutter_lucide.dart';
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
|
||||||
import '../../core/api/api_config.dart';
|
import '../../core/user/account_refresh.dart';
|
||||||
import '../../core/api/services/user_api.dart';
|
|
||||||
import '../../core/auth/auth_service.dart';
|
|
||||||
import '../recharge/payment_webview_screen.dart';
|
import '../recharge/payment_webview_screen.dart';
|
||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/user/user_state.dart';
|
import '../../core/user/user_state.dart';
|
||||||
@ -25,41 +23,17 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (widget.isActive) _fetchAccount();
|
if (widget.isActive) refreshAccount(updateProfile: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant ProfileScreen oldWidget) {
|
void didUpdateWidget(covariant ProfileScreen oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (widget.isActive && !oldWidget.isActive) {
|
if (widget.isActive && !oldWidget.isActive) {
|
||||||
_fetchAccount();
|
refreshAccount(updateProfile: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _fetchAccount() async {
|
|
||||||
final uid = UserState.userId.value;
|
|
||||||
if (uid == null || uid.isEmpty) return;
|
|
||||||
try {
|
|
||||||
await AuthService.loginComplete;
|
|
||||||
final res = await UserApi.getAccount(
|
|
||||||
sentinel: ApiConfig.appId,
|
|
||||||
asset: uid,
|
|
||||||
);
|
|
||||||
if (!mounted) return;
|
|
||||||
if (res.isSuccess && res.data != null) {
|
|
||||||
final data = res.data as Map<String, dynamic>?;
|
|
||||||
final credits = data?['reveal'] as int?;
|
|
||||||
if (credits != null) UserState.setCredits(credits);
|
|
||||||
final avatarUrl = data?['realm'] as String?;
|
|
||||||
UserState.setAvatar(
|
|
||||||
avatarUrl != null && avatarUrl.isNotEmpty ? avatarUrl : null);
|
|
||||||
final name = data?['terminal'] as String?;
|
|
||||||
UserState.setUserName(
|
|
||||||
name != null && name.isNotEmpty ? name : null);
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import '../../core/adjust/adjust_events.dart';
|
|||||||
import '../../core/api/api_config.dart';
|
import '../../core/api/api_config.dart';
|
||||||
import '../../core/api/services/payment_api.dart';
|
import '../../core/api/services/payment_api.dart';
|
||||||
import '../../core/auth/auth_service.dart';
|
import '../../core/auth/auth_service.dart';
|
||||||
|
import '../../core/user/account_refresh.dart';
|
||||||
import '../../core/log/app_logger.dart';
|
import '../../core/log/app_logger.dart';
|
||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/user/user_state.dart';
|
import '../../core/user/user_state.dart';
|
||||||
@ -39,6 +40,7 @@ class _RechargeScreenState extends State<RechargeScreen> with WidgetsBindingObse
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
refreshAccount();
|
||||||
_fetchActivities();
|
_fetchActivities();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,10 +370,8 @@ class _RechargeScreenState extends State<RechargeScreen> with WidgetsBindingObse
|
|||||||
preferredSize: const Size.fromHeight(56),
|
preferredSize: const Size.fromHeight(56),
|
||||||
child: TopNavBar(
|
child: TopNavBar(
|
||||||
title: 'Recharge',
|
title: 'Recharge',
|
||||||
credits: UserCreditsData.of(context)?.creditsDisplay ?? '--',
|
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onBack: () => Navigator.of(context).pop(),
|
onBack: () => Navigator.of(context).pop(),
|
||||||
onCreditsTap: null,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user