diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6452503..7d0ea3f 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
+
)
+#import
+#else
+@import shared_preferences_foundation;
+#endif
+
#if __has_include()
#import
#else
@@ -55,6 +61,7 @@
[FPPDeviceInfoPlusPlugin registerWithRegistrar:[registry registrarForPlugin:@"FPPDeviceInfoPlusPlugin"]];
[GalPlugin registerWithRegistrar:[registry registrarForPlugin:@"GalPlugin"]];
[FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]];
+ [SharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"SharedPreferencesPlugin"]];
[SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]];
[FVPVideoPlayerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FVPVideoPlayerPlugin"]];
[VideoThumbnailPlugin registerWithRegistrar:[registry registrarForPlugin:@"VideoThumbnailPlugin"]];
diff --git a/lib/core/adjust/adjust_events.dart b/lib/core/adjust/adjust_events.dart
new file mode 100644
index 0000000..8c74582
--- /dev/null
+++ b/lib/core/adjust/adjust_events.dart
@@ -0,0 +1,112 @@
+import 'package:adjust_sdk/adjust.dart';
+import 'package:adjust_sdk/adjust_event.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+/// Adjust 事件埋点(识别码见 docs/adjuest.md)
+abstract final class AdjustEvents {
+ // 购买档位(充值页选择档位时上报)
+ static const String tier1999 = 'm0r9u9'; // 19.99
+ static const String tier4999 = 'aht1ve'; // 49.99
+ static const String tier599 = '47hhx9'; // 5.99
+ static const String tier999 = 'w775gd'; // 9.99
+ static const String tier9999 = 'y7994m'; // 99.99
+
+ // 首日充值
+ static const String firstPurchase = 'r6w4bi';
+
+ // 支付失败
+ static const String orderAbnormal = '4txlo1';
+
+ // 支付成功
+ static const String purchase = 'ek780r';
+
+ // 注册(首次调用 fast_login 成功时)
+ static const String register = '2z3dm4';
+
+ // 其他
+ static const String monthlyVip = '96o5ez'; // PetsHero AI Monthly VIP
+ static const String weeklyVip = '95yg4o'; // PetsHero AI Weekly VIP
+
+ /// 根据金额(如 19.99, 9.99)返回档位事件 token,无法匹配时返回 purchase
+ static String? tierTokenFromPrice(num price) {
+ final p = price.toStringAsFixed(2);
+ switch (p) {
+ case '5.99':
+ return tier599;
+ case '9.99':
+ return tier999;
+ case '19.99':
+ return tier1999;
+ case '49.99':
+ return tier4999;
+ case '99.99':
+ return tier9999;
+ default:
+ return purchase;
+ }
+ }
+
+ /// 从金额字符串解析数字(如 "¥19.99" / "\$19.99")
+ static num? parsePrice(String amount) {
+ final match = RegExp(r'[\d.]+').firstMatch(amount);
+ if (match == null) return null;
+ return num.tryParse(match.group(0)!);
+ }
+
+ static void _track(String eventToken) {
+ Adjust.trackEvent(AdjustEvent(eventToken));
+ }
+
+ /// 购买档位(用户点击某档位购买时)
+ static void trackTier(String eventToken) {
+ _track(eventToken);
+ }
+
+ /// 首日充值
+ static void trackFirstPurchase() {
+ _track(firstPurchase);
+ }
+
+ /// 支付失败
+ static void trackOrderAbnormal() {
+ _track(orderAbnormal);
+ }
+
+ /// 支付成功(若为首日充值需额外调用 trackFirstPurchase)
+ static void trackPurchase() {
+ _track(purchase);
+ }
+
+ /// 注册(首次 fast_login 成功)
+ static void trackRegister() {
+ _track(register);
+ }
+
+ /// PetsHero AI Monthly VIP
+ static void trackMonthlyVip() {
+ _track(monthlyVip);
+ }
+
+ /// PetsHero AI Weekly VIP
+ static void trackWeeklyVip() {
+ _track(weeklyVip);
+ }
+
+ static const String _keyRegisterDate = 'adjust_register_date';
+
+ /// 支付成功时调用:上报 Purchase,若为首日充值则同时上报 first purchase
+ static Future trackPurchaseSuccess() async {
+ _track(purchase);
+ final prefs = await SharedPreferences.getInstance();
+ final registerDate = prefs.getString(_keyRegisterDate);
+ if (registerDate != null &&
+ registerDate == DateTime.now().toIso8601String().substring(0, 10)) {
+ _track(firstPurchase);
+ }
+ }
+
+ /// 支付失败时调用
+ static void trackPaymentFailed() {
+ _track(orderAbnormal);
+ }
+}
diff --git a/lib/core/auth/auth_service.dart b/lib/core/auth/auth_service.dart
index 8d82646..808cda6 100644
--- a/lib/core/auth/auth_service.dart
+++ b/lib/core/auth/auth_service.dart
@@ -4,7 +4,9 @@ import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import '../adjust/adjust_events.dart';
import '../api/api_client.dart';
import '../api/proxy_client.dart';
import '../api/services/user_api.dart';
@@ -108,6 +110,17 @@ class AuthService {
} else {
_log('init: 响应中无 reevaluate (userToken)');
}
+ final prefs = await SharedPreferences.getInstance();
+ final hadLoggedIn = prefs.getBool('adjust_has_logged_in') ?? false;
+ if (!hadLoggedIn) {
+ AdjustEvents.trackRegister();
+ await prefs.setBool('adjust_has_logged_in', true);
+ await prefs.setString(
+ 'adjust_register_date',
+ DateTime.now().toIso8601String().substring(0, 10),
+ );
+ _log('init: 首次登录,已上报 register');
+ }
final credits = data?['reveal'] as int?;
if (credits != null) {
UserState.setCredits(credits);
diff --git a/lib/features/home/home_screen.dart b/lib/features/home/home_screen.dart
index 1ed84b9..5e4a131 100644
--- a/lib/features/home/home_screen.dart
+++ b/lib/features/home/home_screen.dart
@@ -88,7 +88,7 @@ class _HomeScreenState extends State {
appBar: PreferredSize(
preferredSize: const Size.fromHeight(56),
child: TopNavBar(
- title: 'AI Video',
+ title: 'PetsHero AI',
credits: UserCreditsData.of(context)?.creditsDisplay ?? '--',
onCreditsTap: () => Navigator.of(context).pushNamed('/recharge'),
),
@@ -101,7 +101,9 @@ class _HomeScreenState extends State {
vertical: AppSpacing.xs,
),
child: _categoriesLoading
- ? const SizedBox(height: 40, child: Center(child: CircularProgressIndicator()))
+ ? const SizedBox(
+ height: 40,
+ child: Center(child: CircularProgressIndicator()))
: HomeTabRow(
categories: _categories,
selectedId: _selectedCategory?.id ?? -1,
@@ -137,7 +139,8 @@ class _HomeScreenState extends State {
? task.credits480p.toString()
: '50';
return VideoCard(
- imageUrl: task.previewImageUrl ?? _placeholderImage,
+ imageUrl:
+ task.previewImageUrl ?? _placeholderImage,
videoUrl: task.previewVideoUrl,
credits: credits,
isActive: _activeCardIndex == index,
@@ -147,9 +150,9 @@ class _HomeScreenState extends State {
setState(() => _activeCardIndex = null),
onGenerateSimilar: () =>
Navigator.of(context).pushNamed(
- '/generate',
- arguments: task,
- ),
+ '/generate',
+ arguments: task,
+ ),
);
},
),
@@ -162,5 +165,4 @@ class _HomeScreenState extends State {
),
);
}
-
}
diff --git a/lib/features/recharge/recharge_screen.dart b/lib/features/recharge/recharge_screen.dart
index 0b7ca15..9cb4813 100644
--- a/lib/features/recharge/recharge_screen.dart
+++ b/lib/features/recharge/recharge_screen.dart
@@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
+import '../../core/adjust/adjust_events.dart';
import '../../core/api/services/payment_api.dart';
import '../../core/auth/auth_service.dart';
import '../../core/theme/app_colors.dart';
@@ -80,7 +81,20 @@ class _RechargeScreenState extends State {
}
void _onBuy(ActivityItem item) {
- // TODO: 创建支付订单
+ final price = AdjustEvents.parsePrice(item.actualAmount);
+ if (price != null) {
+ final tierToken = AdjustEvents.tierTokenFromPrice(price);
+ if (tierToken != null) {
+ AdjustEvents.trackTier(tierToken);
+ }
+ }
+ final titleLower = item.title.toLowerCase();
+ if (titleLower.contains('monthly vip')) {
+ AdjustEvents.trackMonthlyVip();
+ } else if (titleLower.contains('weekly vip')) {
+ AdjustEvents.trackWeeklyVip();
+ }
+ // TODO: 创建支付订单;成功时调用 AdjustEvents.trackPurchaseSuccess(),失败时调用 AdjustEvents.trackPaymentFailed()
}
@override
diff --git a/pubspec.yaml b/pubspec.yaml
index 3c0a3fa..1d86448 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -24,6 +24,7 @@ dependencies:
video_thumbnail: ^0.5.3
gal: ^2.3.0
path_provider: ^2.1.2
+ shared_preferences: ^2.2.2
flutter_cache_manager: ^3.3.1
dev_dependencies: