优化:积分页面积分同步处理

This commit is contained in:
ivan 2026-03-12 15:30:45 +08:00
parent 5cfb4c74af
commit 6ae2b55677
7 changed files with 71 additions and 68 deletions

View File

@ -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),
], ],

View 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 (_) {}
}

View File

@ -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(

View File

@ -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(

View File

@ -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 {

View File

@ -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(

View File

@ -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(