diff --git a/android/app/build.gradle b/android/app/build.gradle
index f1f35d8..4f6b947 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -76,9 +76,14 @@ android {
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
+
+ debug {
+ signingConfig signingConfigs.release
+ }
}
}
+
flutter {
source '../..'
}
diff --git a/android/app/google-services.json b/android/app/google-services.json
index f0f7ae1..7d519c1 100644
--- a/android/app/google-services.json
+++ b/android/app/google-services.json
@@ -7,17 +7,113 @@
"client": [
{
"client_info": {
- "mobilesdk_app_id": "1:581103504002:android:896e4d41aad9180318829b",
+ "mobilesdk_app_id": "1:581103504002:android:d12a150d3d54570418829b",
+ "android_client_info": {
+ "package_name": "com.example.hoshan"
+ }
+ },
+ "oauth_client": [
+ {
+ "client_id": "581103504002-kb0klg3vds4qcnt5cc348d402l803jh8.apps.googleusercontent.com",
+ "client_type": 1,
+ "android_info": {
+ "package_name": "com.example.hoshan",
+ "certificate_hash": "4fea29f5e9872705f5d86af453b1d77fd4134260"
+ }
+ },
+ {
+ "client_id": "581103504002-dhn875p11up9ae7k6l5r1kdqs71ap3qf.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
+ "api_key": [
+ {
+ "current_key": "AIzaSyDi2WRiOSEws1alpLitxX0zsX14rT71aPk"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": [
+ {
+ "client_id": "581103504002-dhn875p11up9ae7k6l5r1kdqs71ap3qf.apps.googleusercontent.com",
+ "client_type": 3
+ },
+ {
+ "client_id": "581103504002-2e454pgr7fes6b94ptbt82rpfldehedq.apps.googleusercontent.com",
+ "client_type": 2,
+ "ios_info": {
+ "bundle_id": "com.example.hoshan"
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:581103504002:android:8983465e8b4f637d18829b",
"android_client_info": {
"package_name": "com.houshan.basa"
}
},
+ "oauth_client": [
+ {
+ "client_id": "581103504002-mugog6e0d224snhmoen4t01g91m4corc.apps.googleusercontent.com",
+ "client_type": 1,
+ "android_info": {
+ "package_name": "com.houshan.basa",
+ "certificate_hash": "5f7bdab9d1978fa6ba4bb89ba17cfddb41aa7bdb"
+ }
+ },
+ {
+ "client_id": "581103504002-qc5f48octc7274mr3n4hgam3fr5pejd3.apps.googleusercontent.com",
+ "client_type": 1,
+ "android_info": {
+ "package_name": "com.houshan.basa",
+ "certificate_hash": "df8e828db30cabed5c68362c0a67f760610046ee"
+ }
+ },
+ {
+ "client_id": "581103504002-dhn875p11up9ae7k6l5r1kdqs71ap3qf.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
+ "api_key": [
+ {
+ "current_key": "AIzaSyDi2WRiOSEws1alpLitxX0zsX14rT71aPk"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": [
+ {
+ "client_id": "581103504002-dhn875p11up9ae7k6l5r1kdqs71ap3qf.apps.googleusercontent.com",
+ "client_type": 3
+ },
+ {
+ "client_id": "581103504002-2e454pgr7fes6b94ptbt82rpfldehedq.apps.googleusercontent.com",
+ "client_type": 2,
+ "ios_info": {
+ "bundle_id": "com.example.hoshan"
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:581103504002:android:896e4d41aad9180318829b",
+ "android_client_info": {
+ "package_name": "com.houshan.hoshan"
+ }
+ },
"oauth_client": [
{
"client_id": "581103504002-jqptfhs4cpgqngckh8g6kisd25jhfp35.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
- "package_name": "com.houshan.basa",
+ "package_name": "com.houshan.hoshan",
"certificate_hash": "b64c77112af5000772d60fbe05138e873f6fc118"
}
},
@@ -25,7 +121,7 @@
"client_id": "581103504002-t6a9nuq2nnbdjj71s2inc70p4fikl921.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
- "package_name": "com.houshan.basa",
+ "package_name": "com.houshan.hoshan",
"certificate_hash": "5f7bdab9d1978fa6ba4bb89ba17cfddb41aa7bdb"
}
},
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 0aba8f6..5fe11fd 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -35,6 +35,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/assets/icon/outline/folder-add.svg b/assets/icon/outline/folder-add.svg
new file mode 100644
index 0000000..0ad8c40
--- /dev/null
+++ b/assets/icon/outline/folder-add.svg
@@ -0,0 +1,5 @@
+
diff --git a/lib/core/gen/assets.gen.dart b/lib/core/gen/assets.gen.dart
index f453401..ec3c9fc 100644
--- a/lib/core/gen/assets.gen.dart
+++ b/lib/core/gen/assets.gen.dart
@@ -362,6 +362,10 @@ class $AssetsIconBulkGen {
class $AssetsIconGifGen {
const $AssetsIconGifGen();
+ /// File path: assets/icon/gif/33.gif
+ AssetGenImage get a33 =>
+ const AssetGenImage('assets/icon/gif/33.gif', size: Size(640.0, 360.0));
+
/// File path: assets/icon/gif/alpha.gif
AssetGenImage get alpha => const AssetGenImage('assets/icon/gif/alpha.gif');
@@ -445,6 +449,7 @@ class $AssetsIconGifGen {
/// List of all assets
List get values => [
+ a33,
alpha,
bell,
beta,
@@ -534,6 +539,18 @@ class $AssetsIconNavbarsGen {
class $AssetsIconOutlineGen {
const $AssetsIconOutlineGen();
+ /// File path: assets/icon/outline/Houshan features.svg
+ SvgGenImage get houshanFeatures => const SvgGenImage(
+ 'assets/icon/outline/Houshan features.svg',
+ size: Size(32.0, 33.0),
+ );
+
+ /// File path: assets/icon/outline/add family.svg
+ SvgGenImage get addFamily => const SvgGenImage(
+ 'assets/icon/outline/add family.svg',
+ size: Size(32.0, 33.0),
+ );
+
/// File path: assets/icon/outline/add.svg
SvgGenImage get add =>
const SvgGenImage('assets/icon/outline/add.svg', size: Size(24.0, 24.0));
@@ -550,6 +567,12 @@ class $AssetsIconOutlineGen {
size: Size(24.0, 24.0),
);
+ /// File path: assets/icon/outline/arrow-left.svg
+ SvgGenImage get arrowLeft => const SvgGenImage(
+ 'assets/icon/outline/arrow-left.svg',
+ size: Size(24.0, 24.0),
+ );
+
/// File path: assets/icon/outline/arrow-right.svg
SvgGenImage get arrowRight => const SvgGenImage(
'assets/icon/outline/arrow-right.svg',
@@ -596,6 +619,12 @@ class $AssetsIconOutlineGen {
size: Size(19.0, 19.0),
);
+ /// File path: assets/icon/outline/carbon_pedestrian-family.svg
+ SvgGenImage get carbonPedestrianFamily => const SvgGenImage(
+ 'assets/icon/outline/carbon_pedestrian-family.svg',
+ size: Size(32.0, 32.0),
+ );
+
/// File path: assets/icon/outline/card-add.svg
SvgGenImage get cardAdd => const SvgGenImage(
'assets/icon/outline/card-add.svg',
@@ -630,6 +659,12 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 17.0),
);
+ /// File path: assets/icon/outline/close-circle.svg
+ SvgGenImage get closeCircle => const SvgGenImage(
+ 'assets/icon/outline/close-circle.svg',
+ size: Size(24.0, 24.0),
+ );
+
/// File path: assets/icon/outline/coin.svg
SvgGenImage get coin =>
const SvgGenImage('assets/icon/outline/coin.svg', size: Size(25.0, 25.0));
@@ -692,6 +727,10 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 16.0),
);
+ /// File path: assets/icon/outline/edit.svg
+ SvgGenImage get edit =>
+ const SvgGenImage('assets/icon/outline/edit.svg', size: Size(24.0, 24.0));
+
/// File path: assets/icon/outline/element-plus.svg
SvgGenImage get elementPlus => const SvgGenImage(
'assets/icon/outline/element-plus.svg',
@@ -722,6 +761,18 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 17.0),
);
+ /// File path: assets/icon/outline/family.svg
+ SvgGenImage get family => const SvgGenImage(
+ 'assets/icon/outline/family.svg',
+ size: Size(328.0, 115.0),
+ );
+
+ /// File path: assets/icon/outline/familyMembers.svg
+ SvgGenImage get familyMembers => const SvgGenImage(
+ 'assets/icon/outline/familyMembers.svg',
+ size: Size(30.0, 29.0),
+ );
+
/// File path: assets/icon/outline/filter.svg
SvgGenImage get filter => const SvgGenImage(
'assets/icon/outline/filter.svg',
@@ -734,6 +785,12 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 16.0),
);
+ /// File path: assets/icon/outline/folder-add.svg
+ SvgGenImage get folderAdd => const SvgGenImage(
+ 'assets/icon/outline/folder-add.svg',
+ size: Size(18.0, 18.0),
+ );
+
/// File path: assets/icon/outline/gallery-add.svg
SvgGenImage get galleryAdd => const SvgGenImage(
'assets/icon/outline/gallery-add.svg',
@@ -746,6 +803,12 @@ class $AssetsIconOutlineGen {
size: Size(18.0, 18.0),
);
+ /// File path: assets/icon/outline/gift 2.svg
+ SvgGenImage get gift2 => const SvgGenImage(
+ 'assets/icon/outline/gift 2.svg',
+ size: Size(86.0, 88.0),
+ );
+
/// File path: assets/icon/outline/gift.svg
SvgGenImage get gift =>
const SvgGenImage('assets/icon/outline/gift.svg', size: Size(24.0, 24.0));
@@ -786,6 +849,12 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 16.0),
);
+ /// File path: assets/icon/outline/ion_infinite.svg
+ SvgGenImage get ionInfinite => const SvgGenImage(
+ 'assets/icon/outline/ion_infinite.svg',
+ size: Size(32.0, 32.0),
+ );
+
/// File path: assets/icon/outline/lamp-charge.svg
SvgGenImage get lampCharge => const SvgGenImage(
'assets/icon/outline/lamp-charge.svg',
@@ -918,6 +987,10 @@ class $AssetsIconOutlineGen {
size: Size(24.0, 24.0),
);
+ /// File path: assets/icon/outline/send.svg
+ SvgGenImage get send =>
+ const SvgGenImage('assets/icon/outline/send.svg', size: Size(16.0, 16.0));
+
/// File path: assets/icon/outline/setting.svg
SvgGenImage get setting => const SvgGenImage(
'assets/icon/outline/setting.svg',
@@ -952,6 +1025,12 @@ class $AssetsIconOutlineGen {
SvgGenImage get stop =>
const SvgGenImage('assets/icon/outline/stop.svg', size: Size(24.0, 24.0));
+ /// File path: assets/icon/outline/streamline_coins-stack.svg
+ SvgGenImage get streamlineCoinsStack => const SvgGenImage(
+ 'assets/icon/outline/streamline_coins-stack.svg',
+ size: Size(32.0, 32.0),
+ );
+
/// File path: assets/icon/outline/sun.svg
SvgGenImage get sun =>
const SvgGenImage('assets/icon/outline/sun.svg', size: Size(18.0, 18.0));
@@ -992,6 +1071,12 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 16.0),
);
+ /// File path: assets/icon/outline/trashPopup.svg
+ SvgGenImage get trashPopup => const SvgGenImage(
+ 'assets/icon/outline/trashPopup.svg',
+ size: Size(48.0, 48.0),
+ );
+
/// File path: assets/icon/outline/verify.svg
SvgGenImage get verify => const SvgGenImage(
'assets/icon/outline/verify.svg',
@@ -1010,17 +1095,32 @@ class $AssetsIconOutlineGen {
size: Size(16.0, 16.0),
);
+ /// File path: assets/icon/outline/wallet.svg
+ SvgGenImage get wallet => const SvgGenImage(
+ 'assets/icon/outline/wallet.svg',
+ size: Size(32.0, 33.0),
+ );
+
/// File path: assets/icon/outline/warning-2.svg
SvgGenImage get warning2 => const SvgGenImage(
'assets/icon/outline/warning-2.svg',
size: Size(24.0, 25.0),
);
+ /// File path: assets/icon/outline/warning.svg
+ SvgGenImage get warning => const SvgGenImage(
+ 'assets/icon/outline/warning.svg',
+ size: Size(32.0, 33.0),
+ );
+
/// List of all assets
List get values => [
+ houshanFeatures,
+ addFamily,
add,
archiveTick,
arrowFlashRight,
+ arrowLeft,
arrowRight,
assistant,
bitcoinRefresh,
@@ -1029,12 +1129,14 @@ class $AssetsIconOutlineGen {
calendarEdit,
call,
camera,
+ carbonPedestrianFamily,
cardAdd,
cardPos,
characters,
chart,
chat,
clock,
+ closeCircle,
coin,
copy,
courthouse,
@@ -1046,15 +1148,20 @@ class $AssetsIconOutlineGen {
documentText,
download,
edit2,
+ edit,
elementPlus,
emojiHappy,
emptyWalletTick,
emptyWallet,
eraser,
+ family,
+ familyMembers,
filter,
flag2,
+ folderAdd,
galleryAdd,
ghost,
+ gift2,
gift,
globalSearch,
hat,
@@ -1063,6 +1170,7 @@ class $AssetsIconOutlineGen {
idea,
import,
infoCircle,
+ ionInfinite,
lampCharge,
library,
like,
@@ -1087,12 +1195,14 @@ class $AssetsIconOutlineGen {
profileUserDoual,
profile,
searchNormal,
+ send,
setting,
share,
shieldTick,
smsTracking,
stopCircle,
stop,
+ streamlineCoinsStack,
sun,
tickCircle,
tickSquare,
@@ -1100,10 +1210,13 @@ class $AssetsIconOutlineGen {
toolBox,
translate,
trash,
+ trashPopup,
verify,
videoPlay,
voiceCricle,
+ wallet,
warning2,
+ warning,
];
}
@@ -1130,6 +1243,12 @@ class $AssetsIconSocialGen {
class $AssetsImageBoardingsGen {
const $AssetsImageBoardingsGen();
+ /// File path: assets/image/boardings/AI Houshan.svg
+ SvgGenImage get aIHoushan => const SvgGenImage(
+ 'assets/image/boardings/AI Houshan.svg',
+ size: Size(328.0, 88.0),
+ );
+
/// File path: assets/image/boardings/drei.png
AssetGenImage get drei => const AssetGenImage(
'assets/image/boardings/drei.png',
@@ -1167,7 +1286,7 @@ class $AssetsImageBoardingsGen {
);
/// List of all assets
- List get values => [drei, eins, funf, sechs, vier, zwei];
+ List get values => [aIHoushan, drei, eins, funf, sechs, vier, zwei];
}
class $AssetsImageEmptyGen {
@@ -1191,6 +1310,12 @@ class $AssetsImageEmptyGen {
size: Size(347.0, 433.0),
);
+ /// File path: assets/image/empty/empty state 1 1.png
+ AssetGenImage get emptyState11 => const AssetGenImage(
+ 'assets/image/empty/empty state 1 1.png',
+ size: Size(328.0, 351.0),
+ );
+
/// File path: assets/image/empty/empty-text-underline.svg
SvgGenImage get emptyTextUnderline => const SvgGenImage(
'assets/image/empty/empty-text-underline.svg',
@@ -1226,6 +1351,7 @@ class $AssetsImageEmptyGen {
amount,
assistant,
connection,
+ emptyState11,
emptyTextUnderline,
inbox,
messages,
diff --git a/lib/core/routes/route_generator.dart b/lib/core/routes/route_generator.dart
index 9a3c827..73d5fba 100644
--- a/lib/core/routes/route_generator.dart
+++ b/lib/core/routes/route_generator.dart
@@ -180,20 +180,20 @@ class Routes {
navigatorKey: navigatorKey,
redirect: (context, state) async {
final uri = state.uri;
- if (uri.scheme == 'houshan' && uri.host == 'auth') {
- final token = uri.queryParameters['token'];
- if (token != null && token.isNotEmpty) {
+
+ final token = uri.queryParameters['token'];
+ final hasToken = token != null && token.isNotEmpty;
+
+ final isCustomScheme = uri.scheme == 'houshan' && uri.host == 'auth';
+
+ if (hasToken) {
+ if (isCustomScheme || kIsWeb || uri.path == '/') {
if (kDebugMode) {
- print('Deep link token received: ${token.substring(0, 20)}...');
+ print('✅ Login Token Detected: ${token.substring(0, 10)}...');
}
await AuthTokenStorage.setToken(token);
- await OnBoardingStorage
- .setAsSeen();
+ await OnBoardingStorage.setAsSeen();
showOnBoarding = false;
- if (kDebugMode) {
- print('Token saved. Redirecting to main...');
- }
-
return main;
}
}
@@ -211,7 +211,7 @@ class Routes {
return auth;
}
- if (state.matchedLocation == auth) {
+ if (state.uri.path == auth) {
if (context.read().state is UserInfoFail) return null;
if (AuthTokenStorage.getToken().isNotEmpty ||
(UserInfoCubit.userInfoModel.login != null &&
@@ -219,7 +219,7 @@ class Routes {
return main;
}
}
- if (state.matchedLocation == home && kIsWeb) {
+ if (state.uri.path == home && kIsWeb) {
if (UserInfoCubit.userInfoModel.login == null) {
return main;
} else {
@@ -250,7 +250,6 @@ class Routes {
try {
showOnBoarding = state.extra as bool;
} catch (e) {
- // Check if onboarding was already seen
showOnBoarding = !OnBoardingStorage.hasSeen();
if (kDebugMode) {
print('Error get Args: $e');
diff --git a/lib/core/services/firebase/firebase_api.dart b/lib/core/services/firebase/firebase_api.dart
index 3cb8cad..d7051ae 100644
--- a/lib/core/services/firebase/firebase_api.dart
+++ b/lib/core/services/firebase/firebase_api.dart
@@ -1,5 +1,8 @@
+// ignore_for_file: avoid_print
+
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:hoshan/core/routes/route_generator.dart';
@@ -16,27 +19,44 @@ class FirebasApi {
static Future initialNotifications() async {
await refreshToken();
+ try {
+ await _firebaseMessaging.subscribeToTopic('all_users').timeout(
+ const Duration(seconds: 10),
+ onTimeout: () {
+ print('⏰ Subscribe to topic timed out - continuing anyway');
+ },
+ );
+ print('✅ Subscribed to topic: all_users');
+ } catch (e) {
+ print('❌ Failed to subscribe to topic (app will continue): $e');
+ }
+
initPushNotification();
}
static Future refreshToken() async {
- await _firebaseMessaging.requestPermission();
+ try {
+ print('🔄 Start getting FCM Token...');
+ await _firebaseMessaging.requestPermission();
- fcmToken = await _firebaseMessaging.getToken();
-
- final packageInfo = await PackageInfo.fromPlatform();
- final packageName = packageInfo.packageName;
+ fcmToken = await _firebaseMessaging.getToken().timeout(
+ const Duration(seconds: 10),
+ onTimeout: () {
+ print('⏰ FCM Token request timed out - continuing without token');
+ return null;
+ },
+ );
+
+ final packageInfo = await PackageInfo.fromPlatform();
+ final packageName = packageInfo.packageName;
- if (kDebugMode) {
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
print('📦 Package Name: $packageName');
- print('📱 FCM Token for Firebase:');
- print('$fcmToken');
- print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
- print('');
- print('✅ Copy this token and use it in Firebase Console:');
- print(' Cloud Messaging → Send test message');
+ print('🔥 Firebase Initialized Successfully');
+ print('📱 FCM Token: $fcmToken');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
+ } catch (e) {
+ print('❌ ERROR Getting Token (app will continue): $e');
}
}
@@ -67,5 +87,23 @@ class FirebasApi {
static Future initPushNotification() async {
FirebaseMessaging.instance.getInitialMessage().then(handleMessage);
FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
+ FirebaseMessaging.onMessage.listen((RemoteMessage message) {
+ if (message.notification != null) {
+ if (navigatorKey.currentContext != null) {
+ ScaffoldMessenger.of(navigatorKey.currentContext!).showSnackBar(
+ SnackBar(
+ content: Text(
+ message.notification!.title != null
+ ? '${message.notification!.title}\n${message.notification!.body}'
+ : '${message.notification!.body}',
+ textDirection: TextDirection.rtl,
+ ),
+ behavior: SnackBarBehavior.floating,
+ showCloseIcon: true,
+ ),
+ );
+ }
+ }
+ });
}
}
diff --git a/lib/data/model/ai/credit_model.dart b/lib/data/model/ai/credit_model.dart
index d506673..dcc0f9e 100644
--- a/lib/data/model/ai/credit_model.dart
+++ b/lib/data/model/ai/credit_model.dart
@@ -1,16 +1,19 @@
class CreditModel {
final int? credit;
final int? freeCredit;
-
- CreditModel({this.credit, this.freeCredit});
+ final int? giftCredit;
+
+ CreditModel({this.credit, this.freeCredit, this.giftCredit});
CreditModel copyWith({
int? credit,
int? freeCredit,
+ int? giftCredit,
}) {
return CreditModel(
credit: credit ?? this.credit,
freeCredit: freeCredit ?? this.freeCredit,
+ giftCredit: giftCredit ?? this.giftCredit,
);
}
}
diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart
index f0ead28..ebb48bc 100644
--- a/lib/firebase_options.dart
+++ b/lib/firebase_options.dart
@@ -57,6 +57,22 @@ class DefaultFirebaseOptions {
storageBucket: 'hoshan-42d9f.appspot.com',
);
+ static const FirebaseOptions androidHoushan = FirebaseOptions(
+ apiKey: 'AIzaSyDi2WRiOSEws1alpLitxX0zsX14rT71aPk',
+ appId: '1:581103504002:android:8983465e8b4f637d18829b',
+ messagingSenderId: '581103504002',
+ projectId: 'hoshan-42d9f',
+ storageBucket: 'hoshan-42d9f.appspot.com',
+ );
+
+ static const FirebaseOptions androidHoushanMain = FirebaseOptions(
+ apiKey: 'AIzaSyDi2WRiOSEws1alpLitxX0zsX14rT71aPk',
+ appId: '1:581103504002:android:896e4d41aad9180318829b',
+ messagingSenderId: '581103504002',
+ projectId: 'hoshan-42d9f',
+ storageBucket: 'hoshan-42d9f.appspot.com',
+ );
+
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyAENpjFJ2VeVQEt3_Iud9gfqLvuffb7EUI',
appId: '1:581103504002:ios:4e51253f750a0fc818829b',
diff --git a/lib/main.dart b/lib/main.dart
index 0793dac..a00a3e0 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,3 +1,5 @@
+// ignore_for_file: avoid_print
+
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
@@ -30,50 +32,88 @@ import 'package:hoshan/ui/screens/tools/bloc/tools_bloc.dart';
import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart';
import 'package:hoshan/ui/theme/my_custom_scroll_behavior.dart';
import 'package:hoshan/ui/theme/theme.dart';
+import 'package:package_info_plus/package_info_plus.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:url_strategy/url_strategy.dart';
@pragma('vm:entry-point')
-Future _onBackgroundMessage(RemoteMessage message) async {}
+Future _onBackgroundMessage(RemoteMessage message) async {
+ debugPrint("Handling a background message: ${message.messageId}");
+}
void main() async {
setPathUrlStrategy();
WidgetsFlutterBinding.ensureInitialized();
- // 1. Wrap SharedPreferences in try-catch
try {
await SharedPreferencesHelper.initial();
} catch (e) {
debugPrint("Error initializing SharedPreferences: $e");
}
- // 2. Wrap Tapsell in try-catch (High probability of crash here)
try {
await TapsellService.initialize();
} catch (e) {
debugPrint("Error initializing Tapsell: $e");
}
- // 3. Firebase Initialization
+ print('🚀 Starting Firebase Initialization...');
try {
FirebaseMessaging.onBackgroundMessage(_onBackgroundMessage);
- await Firebase.initializeApp(
- options: DefaultFirebaseOptions.currentPlatform);
- FirebasApi.initialNotifications();
- } catch (e) {
- debugPrint('Error initializing Firebase: $e');
+
+ FirebaseOptions options = DefaultFirebaseOptions.currentPlatform;
+
+ if (defaultTargetPlatform == TargetPlatform.android) {
+ print('🤖 Platform is Android, checking package info...');
+ final packageInfo = await PackageInfo.fromPlatform();
+ print("📦 RUNNING WITH PACKAGE: ${packageInfo.packageName}");
+
+ if (packageInfo.packageName == 'com.houshan.basa') {
+ options = DefaultFirebaseOptions.androidHoushan;
+ print("🔥 Using 'androidHoushan' options (Basa)");
+ } else if (packageInfo.packageName == 'com.houshan.hoshan') {
+ options = DefaultFirebaseOptions.androidHoushanMain;
+ print("🔥 Using 'androidHoushanMain' options (Main)");
+ } else {
+ print("⚠️ Unknown package name, using default options");
+ }
+ }
+
+ if (Firebase.apps.isEmpty) {
+ print('⏳ Calling Firebase.initializeApp...');
+ try {
+ await Firebase.initializeApp(options: options);
+ print('✅ Firebase.initializeApp completed.');
+ } catch (e) {
+ print('⚠️ Firebase.initializeApp failed: $e');
+ if (e.toString().contains('duplicate-app')) {
+ print('ℹ️ Ignoring duplicate-app error and continuing...');
+ } else {
+ rethrow;
+ }
+ }
+ } else {
+ print('ℹ️ Firebase already initialized. Skipping initialization.');
+ }
+
+ print('⏳ Calling FirebasApi.initialNotifications()...');
+ await FirebasApi.initialNotifications();
+ } catch (e, stack) {
+ print('❌❌ Error initializing Firebase: $e');
+ print(stack);
}
- // 4. Downloader Initialization
try {
if (!kIsWeb) {
await FlutterDownloader.initialize(debug: true, ignoreSsl: true);
+ print('✅ FlutterDownloader initialized');
}
} catch (e) {
debugPrint('Error initializing FlutterDownloader: $e');
}
// Run App
+ print('✅✅ Main initialization completed! Starting app...');
if (kReleaseMode) {
await SentryFlutter.init((options) {
options.dsn =
@@ -81,11 +121,11 @@ void main() async {
options.sendDefaultPii = true;
},
- // Init your App.
appRunner: () => runApp(mainApp()));
} else {
runApp(mainApp());
}
+ print('🚀🚀 App started successfully!');
}
MultiBlocProvider mainApp() {
diff --git a/lib/ui/screens/auth/auth_page.dart b/lib/ui/screens/auth/auth_page.dart
index fea54fc..4eaeccf 100644
--- a/lib/ui/screens/auth/auth_page.dart
+++ b/lib/ui/screens/auth/auth_page.dart
@@ -51,11 +51,17 @@ class _AuthPageState extends State {
if (!kIsWeb) {
final appLinks = AppLinks();
_linkSubscription = appLinks.uriLinkStream.listen((uri) async {
- if (uri.scheme == 'houshan' && uri.host == 'auth') {
+ print('🔔 AuthPage Listener Received URI: $uri'); // Debug Log
+
+ final isCustomScheme = uri.scheme == 'houshan' && uri.host == 'auth';
+ final isWebLink = (uri.scheme == 'https' || uri.scheme == 'http') &&
+ uri.host == 'basaweb.houshan.ai';
+
+ if (isCustomScheme || isWebLink) {
final token = uri.queryParameters['token'];
if (token != null && token.isNotEmpty) {
if (kDebugMode) {
- print('Deep link received while app open: $token');
+ print('Deep link received: $uri');
}
await AuthTokenStorage.setToken(token);
await OnBoardingStorage.setAsSeen();
diff --git a/lib/ui/screens/auth/code/gift_code_screen.dart b/lib/ui/screens/auth/code/gift_code_screen.dart
index 1a85bcf..b41f1c1 100644
--- a/lib/ui/screens/auth/code/gift_code_screen.dart
+++ b/lib/ui/screens/auth/code/gift_code_screen.dart
@@ -28,7 +28,7 @@ class _GiftCodeScreenState extends State {
listener: (context, state) async {
if (state is CheckCodeSucceess) {
await context.read().getUserInfo();
- context.go(Routes.giftCredit,
+ context.go(Routes.home,
extra: HomeArgs(message: state.message, freeCredit: 50));
}
},
@@ -105,7 +105,7 @@ class _GiftCodeScreenState extends State {
onPressed: () async {
if (state is CheckCodeLoading) return;
await context.read().getUserInfo();
- context.go(Routes.giftCredit,
+ context.go(Routes.home,
extra: HomeArgs(freeCredit: 50));
},
child: Text(
diff --git a/lib/ui/screens/auth/verification/verification_screen.dart b/lib/ui/screens/auth/verification/verification_screen.dart
index e27d92c..4ce736e 100644
--- a/lib/ui/screens/auth/verification/verification_screen.dart
+++ b/lib/ui/screens/auth/verification/verification_screen.dart
@@ -96,7 +96,7 @@ class _VerificationScreenState extends State {
context.read().changeState(AuthScreens.code);
} else {
await context.read().getUserInfo();
- context.go(Routes.giftCredit);
+ context.go(Routes.home);
}
}
},
diff --git a/lib/ui/screens/chat/bloc/messages_bloc.dart b/lib/ui/screens/chat/bloc/messages_bloc.dart
index ac02740..a74b4e1 100644
--- a/lib/ui/screens/chat/bloc/messages_bloc.dart
+++ b/lib/ui/screens/chat/bloc/messages_bloc.dart
@@ -58,6 +58,9 @@ class MessagesBloc extends Bloc {
if (event is AddMessage) {
final updatedList = List.from(state.messages);
updatedList.add(event.message);
+ if (kDebugMode) {
+ print('📨 AddMessage: Total messages = ${updatedList.length}, Role = ${event.message.role}, File = ${event.message.file?.name}');
+ }
emit(MessagesSuccess(messages: updatedList)); // Copy the current state
}
diff --git a/lib/ui/screens/chat/chat_page.dart b/lib/ui/screens/chat/chat_page.dart
index 9ff7da6..d4370b4 100644
--- a/lib/ui/screens/chat/chat_page.dart
+++ b/lib/ui/screens/chat/chat_page.dart
@@ -1,4 +1,4 @@
-// ignore_for_file: deprecated_member_use_from_same_package, use_build_context_synchronously
+// ignore_for_file: deprecated_member_use_from_same_package, use_build_context_synchronously, avoid_print
import 'dart:math';
@@ -74,6 +74,8 @@ class _ChatPageState extends State {
final ValueNotifier selectedFile = ValueNotifier(null);
final TextEditingController messageText = TextEditingController();
ValueNotifier maxLines = ValueNotifier(5);
+ late final ValueNotifier selectedBotId =
+ ValueNotifier(widget.chatArgs.bot.id ?? 1);
void sendRequest(
{required final String? message,
@@ -82,9 +84,13 @@ class _ChatPageState extends State {
final bool withOutNewMessage = false}) {
final creditState = CreditModel(
credit: UserInfoCubit.userInfoModel.credit ?? 0,
- freeCredit: UserInfoCubit.userInfoModel.freeCredit ?? 0);
- int credit = (creditState.freeCredit ?? 0) + (creditState.credit ?? 0);
+ freeCredit: UserInfoCubit.userInfoModel.freeCredit ?? 0,
+ giftCredit: UserInfoCubit.userInfoModel.gift_credit ?? 0);
+ int credit = (creditState.freeCredit ?? 0) +
+ (creditState.credit ?? 0) +
+ (creditState.giftCredit ?? 0);
if (credit < widget.chatArgs.bot.cost!) {
+ print("crdit= $credit, cost=${widget.chatArgs.bot.cost}");
DialogHandler(context: context).showUpgradeCredit();
messageText.text = message ?? '';
@@ -92,14 +98,26 @@ class _ChatPageState extends State {
}
if (!withOutNewMessage) {
+ if (kDebugMode) {
+ print(
+ '📤 Sending message: text="${message ?? ""}", file=${file?.name}');
+ }
+
+ final messageContent = [];
+
+ if (message != null && message.isNotEmpty) {
+ messageContent.add(Content(type: 'text', text: message));
+ }
+
+ if (file != null && (message == null || message.isEmpty)) {
+ messageContent.add(Content(type: 'text', text: ''));
+ }
+
context.read().add(AddMessage(
message: Messages(
role: 'human',
id: 'hero',
- content: [
- if (message != null && message.isNotEmpty)
- Content(type: 'text', text: message)
- ],
+ content: messageContent,
query: message,
file: file,
retry: retry)));
@@ -107,7 +125,7 @@ class _ChatPageState extends State {
context.read().execute(
request: SendMessageModel(
- botId: bot.id,
+ botId: selectedBotId.value,
file: file,
id: chatId,
messageId: 'hero',
@@ -474,69 +492,209 @@ class _ChatPageState extends State {
? const Radius.circular(0)
: const Radius.circular(10))),
padding: const EdgeInsets.all(8),
- child: message.content != null
- ? Column(
- crossAxisAlignment:
- CrossAxisAlignment.end,
- children: [
- if (message.file != null)
- message.file!.name.isVideo()
- ? GestureDetector(
- onTap: () => DialogHandler(
- context: context)
- .showVideoHero(
- url: message
- .file!.path),
- child: Container(
- constraints:
- const BoxConstraints(
- maxWidth: double.infinity,
- ),
- child: VideoThumbnailWidget(
- videoUrl:
- message.file!.path),
- ),
- )
- : message.file!.name.isImage()
- ? GestureDetector(
- onTap: () =>
- DialogHandler(
+ child:
+ (message.content != null &&
+ message.content!.isNotEmpty) ||
+ message.file != null
+ ? Column(
+ crossAxisAlignment:
+ CrossAxisAlignment.end,
+ children: [
+ Builder(
+ builder: (context) {
+ if (kDebugMode &&
+ !message.fromBot!) {
+ print(
+ '👤 User message: id=${message.id}, file=${message.file?.name}, content=${message.content?.length}');
+ }
+ return const SizedBox.shrink();
+ },
+ ),
+ if (message.file != null)
+ Stack(
+ children: [
+ message.file!.name.isVideo()
+ ? GestureDetector(
+ onTap: () => DialogHandler(
context:
context)
- .showImageHero(
- image: message
+ .showVideoHero(
+ url: message
.file!
.path),
- child: AspectRatio(
- aspectRatio: 1 / 1,
- child: Container(
+ child: Container(
+ constraints:
+ const BoxConstraints(
+ maxWidth: double
+ .infinity,
+ ),
+ child: VideoThumbnailWidget(
+ videoUrl:
+ message
+ .file!
+ .path),
+ ),
+ )
+ : message.file!.name
+ .isImage()
+ ? GestureDetector(
+ onTap: () => DialogHandler(
+ context:
+ context)
+ .showImageHero(
+ image: message
+ .file!
+ .path),
+ child:
+ AspectRatio(
+ aspectRatio:
+ 1 / 1,
+ child:
+ Container(
+ constraints:
+ const BoxConstraints(
+ maxWidth: double
+ .infinity,
+ ),
+ child: ClipRRect(
+ borderRadius: BorderRadius.circular(8),
+ child: CustomeImage(
+ src: message
+ .file!
+ .path,
+ fit: BoxFit
+ .cover,
+ )),
+ ),
+ ),
+ )
+ : message.file!.name
+ .isAudio()
+ ? Player(
+ fileUrl:
+ message
+ .file!
+ .path,
+ inMessages:
+ true,
+ )
+ : Container(
+ decoration: BoxDecoration(
+ color: context
+ .read<
+ ThemeModeCubit>()
+ .isDark()
+ ? AppColors.black[
+ 900]
+ : AppColors
+ .gray
+ .defaultShade,
+ borderRadius:
+ BorderRadius.circular(
+ 10)),
+ padding:
+ const EdgeInsets
+ .all(
+ 8),
+ constraints:
+ const BoxConstraints(
+ minHeight:
+ 64),
+ child: Row(
+ children: [
+ SizedBox(
+ child: message.file!.name.isDocument()
+ ? const Icon(CupertinoIcons.doc)
+ : const SizedBox.shrink(),
+ ),
+ Expanded(
+ child:
+ Padding(
+ padding: const EdgeInsets
+ .symmetric(
+ horizontal:
+ 12.0),
+ child:
+ Text(
+ message
+ .file!
+ .name,
+ textDirection: message.file!.name.startsWithEnglish()
+ ? TextDirection.ltr
+ : TextDirection.rtl,
+ style:
+ const TextStyle(fontSize: 16),
+ overflow:
+ TextOverflow.ellipsis,
+ maxLines:
+ 2,
+ ),
+ )),
+ ],
+ ),
+ ),
+ if (message.id == 'hero')
+ Positioned.fill(
+ child: Container(
+ decoration:
+ BoxDecoration(
+ color: Colors.black
+ .withOpacity(0.5),
+ borderRadius:
+ BorderRadius
+ .circular(8),
+ ),
+ child: Center(
+ child:
+ CircularProgressIndicator(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ if (message.content != null &&
+ message.content!.isNotEmpty)
+ ...List.generate(
+ message.content!.length,
+ (index) {
+ final content =
+ message.content![index];
+ return Column(
+ children: [
+ if (content.audioUrl !=
+ null)
+ Player(
+ fileUrl: content
+ .audioUrl!
+ .url ??
+ '',
+ inMessages: true,
+ ),
+ if (content.imageUrl !=
+ null)
+ Container(
constraints:
const BoxConstraints(
maxWidth:
double.infinity,
),
- child: ClipRRect(
- borderRadius:
- BorderRadius
- .circular(
- 8),
- child:
- CustomeImage(
- src: message
- .file!.path,
- fit: BoxFit
- .cover,
- )),
+ child: AspectRatio(
+ aspectRatio: 1 / 1,
+ child: ImageNetwork(
+ url: content
+ .imageUrl
+ ?.url ??
+ '',
+ showHero: true,
+ radius: 10,
+ ),
+ ),
),
- ),
- )
- : message.file!.name.isAudio()
- ? Player(
- fileUrl: message
- .file!.path,
- inMessages: true,
- )
- : Container(
+ if (content.pdfUrl !=
+ null)
+ Container(
decoration: BoxDecoration(
color: context
.read<
@@ -561,16 +719,10 @@ class _ChatPageState extends State {
64),
child: Row(
children: [
- SizedBox(
- child: message
- .file!
- .name
- .isDocument()
- ? const Icon(
- CupertinoIcons
- .doc)
- : const SizedBox
- .shrink(),
+ const SizedBox(
+ child: Icon(
+ CupertinoIcons
+ .doc),
),
Expanded(
child:
@@ -580,11 +732,14 @@ class _ChatPageState extends State {
horizontal:
12.0),
child: Text(
- message.file!
- .name,
- textDirection: message
- .file!
- .name
+ content.pdfUrl!
+ .url
+ ?.split(
+ '/')
+ .last ??
+ '',
+ textDirection: (content.pdfUrl!.url?.split('/').last ??
+ '')
.startsWithEnglish()
? TextDirection
.ltr
@@ -602,307 +757,86 @@ class _ChatPageState extends State {
],
),
),
- ...List.generate(
- message.content!.length,
- (index) {
- final content =
- message.content![index];
- return Column(
- children: [
- if (content.audioUrl != null)
- Player(
- fileUrl:
- content.audioUrl!.url ??
- '',
- inMessages: true,
- ),
- if (content.imageUrl != null)
- Container(
- constraints:
- const BoxConstraints(
- maxWidth: double.infinity,
- ),
- child: AspectRatio(
- aspectRatio: 1 / 1,
- child: ImageNetwork(
- url: content.imageUrl
- ?.url ??
- '',
- showHero: true,
- radius: 10,
- ),
- ),
- ),
- if (content.pdfUrl != null)
- Container(
- decoration: BoxDecoration(
- color: context
- .read<
- ThemeModeCubit>()
- .isDark()
- ? AppColors
- .black[900]
- : AppColors.gray
- .defaultShade,
- borderRadius:
- BorderRadius
- .circular(10)),
- padding:
- const EdgeInsets.all(8),
- constraints:
- const BoxConstraints(
- minHeight: 64),
- child: Row(
- children: [
- const SizedBox(
- child: Icon(
- CupertinoIcons
- .doc),
- ),
- Expanded(
- child: Padding(
+ if (content.audioUrl == null &&
+ content.imageUrl ==
+ null &&
+ content.pdfUrl ==
+ null)
+ Padding(
padding:
const EdgeInsets
.symmetric(
horizontal:
- 12.0),
- child: Text(
- content.pdfUrl!.url
- ?.split('/')
- .last ??
- '',
- textDirection: (content
- .pdfUrl!
- .url
- ?.split(
- '/')
- .last ??
- '')
- .startsWithEnglish()
- ? TextDirection
- .ltr
- : TextDirection
- .rtl,
- style:
- const TextStyle(
- fontSize:
- 16),
- overflow:
- TextOverflow
- .ellipsis,
- maxLines: 2,
- ),
- )),
- ],
- ),
- ),
- if (content.audioUrl == null &&
- content.imageUrl == null &&
- content.pdfUrl == null)
- Padding(
- padding: const EdgeInsets
- .symmetric(
- horizontal: 8.0),
- child: Builder(
- builder: (context) {
- directionName
- .value = content
- .text !=
- null &&
- content.text!
- .startsWithEnglish()
- ? "LTR"
- : 'RTL';
- return DefaultMarkdownText(
- key: markdownKey,
- text: content.text ??
- '',
- fromBot:
- message.fromBot!,
- color: message
- .fromBot!
- ? Theme.of(
- context)
- .colorScheme
- .onSurface
- : Colors.white);
- }),
- )
- ],
- );
- },
- ),
- if (message.fromBot!)
- Padding(
- padding: const EdgeInsets.only(
- top: 8.0, left: 8.0),
- child: Row(
- mainAxisAlignment:
- MainAxisAlignment
- .spaceBetween,
- children: [
- ValueListenableBuilder(
- valueListenable:
- directionName,
- builder: (context, dir, _) {
- return InkWell(
- onTap: () {
- directionName
- .value = markdownKey
- .currentState
- ?.changeDirection() ??
- 'RTL';
- },
- child: Container(
- padding:
- const EdgeInsets
- .symmetric(
- horizontal:
- 12,
- vertical: 4),
- decoration: BoxDecoration(
- borderRadius:
- BorderRadius
- .circular(
- 4),
- color: context
- .read<
- ThemeModeCubit>()
- .isDark()
- ? AppColors
- .black[
- 900]
- : AppColors
- .primaryColor[
- 50]),
- child: Text(
- dir,
- style: TextStyle(
- color: Theme.of(
- context)
- .colorScheme
- .primary),
- ),
- ),
- );
- }),
- Row(
- mainAxisSize:
- MainAxisSize.min,
+ 8.0),
+ child: Builder(
+ builder:
+ (context) {
+ directionName
+ .value = content
+ .text !=
+ null &&
+ content
+ .text!
+ .startsWithEnglish()
+ ? "LTR"
+ : 'RTL';
+ return DefaultMarkdownText(
+ key:
+ markdownKey,
+ text: content
+ .text ??
+ '',
+ fromBot: message
+ .fromBot!,
+ color: message
+ .fromBot!
+ ? Theme.of(
+ context)
+ .colorScheme
+ .onSurface
+ : Colors
+ .white);
+ }),
+ )
+ ],
+ );
+ },
+ ),
+ if (message.fromBot!)
+ Padding(
+ padding: const EdgeInsets.only(
+ top: 8.0, left: 8.0),
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment
+ .spaceBetween,
children: [
- BlocProvider<
- LikeMessageCubit>(
- create: (context) =>
- LikeMessageCubit()
- ..getLike(
- like: message
- .like),
- child: BlocBuilder<
- LikeMessageCubit,
- LikeMessageState>(
+ ValueListenableBuilder(
+ valueListenable:
+ directionName,
builder:
- (context, state) {
- return DefaultPlaceHolder(
- enabled: state
- is LikeMessageLoading,
- child: Row(
- children: [
- GestureDetector(
- onTap:
- () async {
- await context.read().setLike(
- like: state
- is LikeMessageLiked
- ? null
- : true,
- chatId:
- chatId!,
- messageId:
- message.id!);
- },
- child:
- Padding(
- padding: const EdgeInsets
- .only(
- right:
- 20.0),
- child:
- SizedBox(
- width: 16,
- height:
- 16,
- child: state
- is LikeMessageLiked
- ? Assets
- .icon
- .bold
- .like
- .svg(color: AppColors.green.defaultShade)
- : Assets.icon.outline.like.svg(color: Theme.of(context).colorScheme.primary),
- ),
- ),
- ),
- GestureDetector(
- onTap:
- () async {
- await context.read().setLike(
- like: state
- is LikeMessageDisLiked
- ? null
- : false,
- chatId:
- chatId!,
- messageId:
- message.id!);
- },
- child:
- Padding(
- padding: const EdgeInsets
- .only(
- right:
- 20.0),
- child:
- SizedBox(
- width: 16,
- height:
- 16,
- child: state
- is LikeMessageDisLiked
- ? Assets
- .icon
- .bold
- .dislike
- .svg(color: AppColors.red.defaultShade)
- : Assets.icon.outline.dislike.svg(color: Theme.of(context).colorScheme.primary),
- ),
- ),
- ),
- ],
- ),
- );
- },
- ),
- ),
- if (widget.chatArgs.bot
- .tool !=
- null &&
- !widget
- .chatArgs.bot.tool!)
- MorePopupMenuHandler(
- context: context)
- .morePopUpMenu(
- child: Padding(
- padding:
- const EdgeInsets
- .only(
- right:
- 20.0),
- child:
- CircleIconBtn(
- icon: Assets
- .icon
- .outline
- .magicpen,
+ (context, dir, _) {
+ return InkWell(
+ onTap: () {
+ directionName
+ .value = markdownKey
+ .currentState
+ ?.changeDirection() ??
+ 'RTL';
+ },
+ child: Container(
+ padding:
+ const EdgeInsets
+ .symmetric(
+ horizontal:
+ 12,
+ vertical:
+ 4),
+ decoration: BoxDecoration(
+ borderRadius:
+ BorderRadius
+ .circular(
+ 4),
color: context
.read<
ThemeModeCubit>()
@@ -911,166 +845,290 @@ class _ChatPageState extends State {
.black[
900]
: AppColors
- .primaryColor[50],
- iconColor: Theme.of(
- context)
- .colorScheme
- .primary,
- size: 28,
- iconPadding:
- const EdgeInsets
- .all(
- 6),
- ),
+ .primaryColor[
+ 50]),
+ child: Text(
+ dir,
+ style: TextStyle(
+ color: Theme.of(
+ context)
+ .colorScheme
+ .primary),
),
- items: [
- PopUpMenuItemModel(
- click: () {
- try {
- refreshQuestions
- .value =
- false;
- sendRequest(
- file: message
- .file,
- message:
- 'خلاصهتر بنویس');
- } catch (e) {
- if (kDebugMode) {
- print(
- 'Error is: $e');
- }
- }
- },
- popupMenuItem: PopupMenuItem(
- value: 0,
- child: MorePopupMenuHandler.morePopUpItem(
+ ),
+ );
+ }),
+ Row(
+ mainAxisSize:
+ MainAxisSize.min,
+ children: [
+ BlocProvider<
+ LikeMessageCubit>(
+ create: (context) =>
+ LikeMessageCubit()
+ ..getLike(
+ like: message
+ .like),
+ child: BlocBuilder<
+ LikeMessageCubit,
+ LikeMessageState>(
+ builder: (context,
+ state) {
+ return DefaultPlaceHolder(
+ enabled: state
+ is LikeMessageLoading,
+ child: Row(
+ children: [
+ GestureDetector(
+ onTap:
+ () async {
+ await context.read().setLike(
+ like: state is LikeMessageLiked
+ ? null
+ : true,
+ chatId:
+ chatId!,
+ messageId:
+ message.id!);
+ },
+ child:
+ Padding(
+ padding: const EdgeInsets
+ .only(
+ right:
+ 20.0),
+ child:
+ SizedBox(
+ width:
+ 16,
+ height:
+ 16,
+ child: state is LikeMessageLiked
+ ? Assets.icon.bold.like.svg(color: AppColors.green.defaultShade)
+ : Assets.icon.outline.like.svg(color: Theme.of(context).colorScheme.primary),
+ ),
+ ),
+ ),
+ GestureDetector(
+ onTap:
+ () async {
+ await context.read().setLike(
+ like: state is LikeMessageDisLiked
+ ? null
+ : false,
+ chatId:
+ chatId!,
+ messageId:
+ message.id!);
+ },
+ child:
+ Padding(
+ padding: const EdgeInsets
+ .only(
+ right:
+ 20.0),
+ child:
+ SizedBox(
+ width:
+ 16,
+ height:
+ 16,
+ child: state is LikeMessageDisLiked
+ ? Assets.icon.bold.dislike.svg(color: AppColors.red.defaultShade)
+ : Assets.icon.outline.dislike.svg(color: Theme.of(context).colorScheme.primary),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ },
+ ),
+ ),
+ if (widget.chatArgs.bot
+ .tool !=
+ null &&
+ !widget.chatArgs.bot
+ .tool!)
+ MorePopupMenuHandler(
+ context:
+ context)
+ .morePopUpMenu(
+ child:
+ Padding(
+ padding: const EdgeInsets
+ .only(
+ right:
+ 20.0),
+ child:
+ CircleIconBtn(
icon: Assets
.icon
.outline
- .eraser,
- title:
- 'خلاصهتر بنویس')),
- ),
- PopUpMenuItemModel(
- click: () {
- try {
- refreshQuestions
- .value =
- false;
- sendRequest(
- file: message
- .file,
- message:
- 'کامل بنویس');
- } catch (e) {
- if (kDebugMode) {
- print(
- 'Error is: $e');
- }
- }
- },
- popupMenuItem: PopupMenuItem(
- value: 1,
- child: MorePopupMenuHandler.morePopUpItem(
- icon: Assets
- .icon
- .outline
- .edit2,
- title:
- 'کامل بنویس')),
- ),
- PopUpMenuItemModel(
- popupMenuItem: PopupMenuItem(
- value: 2,
- child: MorePopupMenuHandler.morePopUpItem(
- icon: Assets
- .icon
- .outline
- .voiceCricle,
- title:
- 'لحن نوشته را تغییر بده')),
- click: () async {
- await BottomSheetHandler(
- context)
- .showStringList(
- onSelect:
- (value) {
- try {
- refreshQuestions.value =
- false;
- sendRequest(
- file: message.file,
- message: 'لحن نوشته را تغییر بده به $value');
- } catch (e) {
- if (kDebugMode) {
- print('Error is: $e');
- }
- }
- },
- title: 'انتخاب لحن نوشته',
- values: [
- 'رسمی',
- 'عامیانه',
- 'دوستانه',
- 'حرفه ای',
- 'محاوره ای',
- 'طنز',
- 'جدی'
- ]);
- },
- ),
- PopUpMenuItemModel(
- popupMenuItem: PopupMenuItem(
- value: 3,
- child: MorePopupMenuHandler.morePopUpItem(
- icon: Assets
- .icon
- .outline
- .translate,
- title:
- 'ترجمه کن')),
- click: () async {
- await BottomSheetHandler(
- context)
- .showStringList(
- onSelect:
- (value) {
- try {
- refreshQuestions.value =
- false;
- sendRequest(
- file: message.file,
- message: 'زبان نوشته را تغییر بده به $value');
- } catch (e) {
- if (kDebugMode) {
- print('Error is: $e');
- }
- }
- },
- title:
- 'انتخاب زبان',
- values: [
- '🇮🇷 فارسی',
- 'Arabic 🇸🇦',
- 'Bengali 🇧🇩',
- 'English 🇬🇧',
- 'French 🇫🇷',
- 'German 🇩🇪',
- 'Hindi 🇮🇳',
- 'Italian 🇮🇹'
- ]);
- },
- ),
- ]),
+ .magicpen,
+ color: context
+ .read<
+ ThemeModeCubit>()
+ .isDark()
+ ? AppColors.black[
+ 900]
+ : AppColors
+ .primaryColor[50],
+ iconColor: Theme.of(
+ context)
+ .colorScheme
+ .primary,
+ size: 28,
+ iconPadding:
+ const EdgeInsets
+ .all(
+ 6),
+ ),
+ ),
+ items: [
+ PopUpMenuItemModel(
+ click: () {
+ try {
+ refreshQuestions
+ .value =
+ false;
+ sendRequest(
+ file: message
+ .file,
+ message:
+ 'خلاصهتر بنویس');
+ } catch (e) {
+ if (kDebugMode) {
+ print(
+ 'Error is: $e');
+ }
+ }
+ },
+ popupMenuItem: PopupMenuItem(
+ value: 0,
+ child: MorePopupMenuHandler.morePopUpItem(
+ icon: Assets
+ .icon
+ .outline
+ .eraser,
+ title:
+ 'خلاصهتر بنویس')),
+ ),
+ PopUpMenuItemModel(
+ click: () {
+ try {
+ refreshQuestions
+ .value =
+ false;
+ sendRequest(
+ file: message
+ .file,
+ message:
+ 'کامل بنویس');
+ } catch (e) {
+ if (kDebugMode) {
+ print(
+ 'Error is: $e');
+ }
+ }
+ },
+ popupMenuItem: PopupMenuItem(
+ value: 1,
+ child: MorePopupMenuHandler.morePopUpItem(
+ icon: Assets
+ .icon
+ .outline
+ .edit2,
+ title:
+ 'کامل بنویس')),
+ ),
+ PopUpMenuItemModel(
+ popupMenuItem: PopupMenuItem(
+ value: 2,
+ child: MorePopupMenuHandler.morePopUpItem(
+ icon: Assets
+ .icon
+ .outline
+ .voiceCricle,
+ title:
+ 'لحن نوشته را تغییر بده')),
+ click:
+ () async {
+ await BottomSheetHandler(
+ context)
+ .showStringList(
+ onSelect:
+ (value) {
+ try {
+ refreshQuestions.value = false;
+ sendRequest(file: message.file, message: 'لحن نوشته را تغییر بده به $value');
+ } catch (e) {
+ if (kDebugMode) {
+ print('Error is: $e');
+ }
+ }
+ },
+ title: 'انتخاب لحن نوشته',
+ values: [
+ 'رسمی',
+ 'عامیانه',
+ 'دوستانه',
+ 'حرفه ای',
+ 'محاوره ای',
+ 'طنز',
+ 'جدی'
+ ]);
+ },
+ ),
+ PopUpMenuItemModel(
+ popupMenuItem: PopupMenuItem(
+ value: 3,
+ child: MorePopupMenuHandler.morePopUpItem(
+ icon: Assets
+ .icon
+ .outline
+ .translate,
+ title:
+ 'ترجمه کن')),
+ click:
+ () async {
+ await BottomSheetHandler(
+ context)
+ .showStringList(
+ onSelect:
+ (value) {
+ try {
+ refreshQuestions.value = false;
+ sendRequest(file: message.file, message: 'زبان نوشته را تغییر بده به $value');
+ } catch (e) {
+ if (kDebugMode) {
+ print('Error is: $e');
+ }
+ }
+ },
+ title:
+ 'انتخاب زبان',
+ values: [
+ '🇮🇷 فارسی',
+ 'Arabic 🇸🇦',
+ 'Bengali 🇧🇩',
+ 'English 🇬🇧',
+ 'French 🇫🇷',
+ 'German 🇩🇪',
+ 'Hindi 🇮🇳',
+ 'Italian 🇮🇹'
+ ]);
+ },
+ ),
+ ]),
+ ],
+ ),
],
),
- ],
- ),
- )
- ],
- )
- : null,
+ )
+ ],
+ )
+ : null,
),
const SizedBox(
width: 4,
@@ -1178,6 +1236,9 @@ class _ChatPageState extends State {
Widget aNewMessage() {
return BlocConsumer(
builder: (context, state) {
+ if (kDebugMode) {
+ print('🔄 aNewMessage state: ${state.runtimeType}');
+ }
if (state is ReceiveMessageOnResponsing) {
return Container(
alignment: Alignment.centerLeft,
@@ -1999,6 +2060,114 @@ class _ChatPageState extends State {
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
+ if (bot.tool == null || !bot.tool!)
+ ValueListenableBuilder(
+ valueListenable: selectedBotId,
+ builder: (context, currentBotId, _) {
+ String botName = currentBotId == 1
+ ? 'ChatGPT'
+ : currentBotId == 2
+ ? 'Gemini'
+ : currentBotId == 4
+ ? 'Grok'
+ : 'Claude';
+
+ return PopupMenuButton(
+ color:
+ Theme.of(context).colorScheme.surface,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(12),
+ ),
+ offset: const Offset(0, -10),
+ onSelected: (int value) {
+ print('🤖 Bot selected: $value');
+ selectedBotId.value = value;
+ },
+ itemBuilder: (BuildContext context) =>
+ >[
+ PopupMenuItem(
+ value: 1,
+ child: Text(
+ 'ChatGPT',
+ style: AppTextStyles.body5.copyWith(
+ fontWeight: currentBotId == 1
+ ? FontWeight.bold
+ : FontWeight.normal,
+ ),
+ ),
+ ),
+ PopupMenuItem(
+ value: 2,
+ child: Text(
+ 'Gemini',
+ style: AppTextStyles.body5.copyWith(
+ fontWeight: currentBotId == 2
+ ? FontWeight.bold
+ : FontWeight.normal,
+ ),
+ ),
+ ),
+ PopupMenuItem(
+ value: 4,
+ child: Text(
+ 'Grok',
+ style: AppTextStyles.body5.copyWith(
+ fontWeight: currentBotId == 4
+ ? FontWeight.bold
+ : FontWeight.normal,
+ ),
+ ),
+ ),
+ PopupMenuItem(
+ value: 9,
+ child: Text(
+ 'Claude',
+ style: AppTextStyles.body5.copyWith(
+ fontWeight: currentBotId == 9
+ ? FontWeight.bold
+ : FontWeight.normal,
+ ),
+ ),
+ ),
+ ],
+ child: Container(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 8, vertical: 4),
+ decoration: BoxDecoration(
+ color: Theme.of(context)
+ .colorScheme
+ .primary
+ .withOpacity(0.1),
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ botName,
+ style: AppTextStyles.body6.copyWith(
+ color: Theme.of(context)
+ .colorScheme
+ .primary,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const SizedBox(width: 4),
+ Icon(
+ Icons.keyboard_arrow_up,
+ size: 16,
+ color: Theme.of(context)
+ .colorScheme
+ .primary,
+ ),
+ ],
+ ),
+ ),
+ );
+ },
+ ),
+ if (bot.tool == null || !bot.tool!)
+ const SizedBox(width: 12),
ValueListenableBuilder(
valueListenable: webSearch,
builder: (context, isWebSearchEnabled, _) {
@@ -2163,8 +2332,8 @@ class _ChatPageState extends State {
const EdgeInsets.only(
right: 8.0),
child: CircleIconBtn(
- icon: Assets
- .icon.outline.cardAdd,
+ icon: Assets.icon.outline
+ .folderAdd,
color: Theme.of(context)
.colorScheme
.primary,
diff --git a/lib/ui/screens/chat/cubit/receive_message_cubit.dart b/lib/ui/screens/chat/cubit/receive_message_cubit.dart
index 69906bb..d578366 100644
--- a/lib/ui/screens/chat/cubit/receive_message_cubit.dart
+++ b/lib/ui/screens/chat/cubit/receive_message_cubit.dart
@@ -54,7 +54,6 @@ class ReceiveMessageCubit extends Cubit {
AiResponseModel aiResponseModel = AiResponseModel();
await scrollToEnd();
try {
- // Call your streaming message function and yield states accordingly
await for (String message in request.tool!
? ChatbotRepository.sendMessageTool(request)
: ChatbotRepository.sendMessage(request)) {
@@ -78,7 +77,7 @@ class ReceiveMessageCubit extends Cubit {
for (String json in jsonStrings) {
json = json.replaceAll(
- RegExp(r'[{}"]'), ''); // Remove braces and quotes
+ RegExp(r'[{}"]'), '');
List pairs = json.split(', ');
for (String pair in pairs) {
if (pair.contains('chat_id:')) {
@@ -94,10 +93,10 @@ class ReceiveMessageCubit extends Cubit {
pair.replaceAll('human_message_id: ', '');
} else if (pair.contains('credit:')) {
jsonMap['credit'] = pair.replaceAll('credit: ', '');
- } else if (pair.contains('credit:')) {
- jsonMap['credit'] = pair.replaceAll('credit: ', '');
} else if (pair.contains('free:')) {
jsonMap['free'] = pair.replaceAll('free: ', '');
+ } else if (pair.contains('gift:')) {
+ jsonMap['gift'] = pair.replaceAll('gift: ', '');
} else if (pair.contains('human_message_created_at:')) {
jsonMap['human_message_created_at'] =
pair.replaceAll('human_message_created_at: ', '');
@@ -122,8 +121,16 @@ class ReceiveMessageCubit extends Cubit {
final res = AiResponseModel.fromJson(jsonMap);
if (res.content != null) {
- result += res.content ?? ''; // Add each content to the list
- if (!(res.content!.startsWith('http'))) {
+ result += res.content ?? '';
+ if (res.content!.startsWith('http')) {
+ if (res.content!.isImage()) {
+ emit(ReceiveMessageOnResponsing(text: 'در حال آمادهسازی تصویر'));
+ } else if (res.content!.isAudio()) {
+ emit(ReceiveMessageOnResponsing(text: 'در حال آمادهسازی صوت'));
+ } else if (res.content!.isDocument()) {
+ emit(ReceiveMessageOnResponsing(text: 'در حال آمادهسازی فایل'));
+ }
+ } else {
emit(ReceiveMessageOnResponsing(text: result));
}
}
@@ -138,10 +145,14 @@ class ReceiveMessageCubit extends Cubit {
content: result.isEmpty ? res.content : result,
freeCredit: res.freeCredit,
humanMessageId: res.humanMessageId);
- // Yield the received message line by line
}
await scrollToEnd();
+ if (aiResponseModel.content != null &&
+ aiResponseModel.content!.startsWith('http')) {
+ await Future.delayed(const Duration(milliseconds: 500));
+ }
+
if (aiResponseModel.error ?? true) {
emit(ReceiveMessageOnFail(
oldHumanMessageId: request.messageId ?? '',
diff --git a/lib/ui/screens/gmedia/chats/photo_chat_page.dart b/lib/ui/screens/gmedia/chats/photo_chat_page.dart
index bcb1427..afd631c 100644
--- a/lib/ui/screens/gmedia/chats/photo_chat_page.dart
+++ b/lib/ui/screens/gmedia/chats/photo_chat_page.dart
@@ -126,6 +126,20 @@ class _PhotoChatPageState extends State {
.state is MediaGResponseLoading) {
return;
}
+
+ context.read().add(AddMessage(
+ message: Messages(
+ file: image.xFile,
+ content: [
+ Content(
+ imageUrl: FileUrl(
+ url: image.xFile.path))
+ ],
+ createdAt: DateTime.now()
+ .toIso8601String(),
+ id: 'hero',
+ role: 'user')));
+
context.read().request(
SendMessageModel(
ghost: isGhost.value,
@@ -164,11 +178,30 @@ class _PhotoChatPageState extends State {
.state is MediaGResponseLoading) {
return;
}
+
+ final query = _query.text;
+
+ if (query.isNotEmpty) {
+ context.read().add(
+ AddMessage(
+ message: Messages(
+ query: query,
+ content: [
+ Content(
+ type: 'text',
+ text: query)
+ ],
+ createdAt: DateTime.now()
+ .toIso8601String(),
+ id: 'hero',
+ role: 'user')));
+ }
+
context.read().request(
SendMessageModel(
messageId: DateTime.now()
.toIso8601String(),
- query: _query.text,
+ query: query,
botId: widget.chatArgs.bot.id,
ghost: isGhost.value,
id: chatId));
@@ -255,22 +288,50 @@ class _PhotoChatPageState extends State {
child: CircularProgressIndicator(),
);
}
- // if (state is MessagesSuccess) {
final m = mState.messages;
List> allMessages = groupMessages(m);
- // فیلتر کردن گروههایی که حداقل یک پیام با image_url دارند
- List> messages = allMessages.where((group) {
- return group.any((msg) =>
- msg.content?.any((c) => c.imageUrl != null) ?? false);
- }).toList();
+
+ List> messages = ptp
+ ? allMessages.where((group) {
+ return group.any((msg) =>
+ msg.content?.any((c) => c.imageUrl != null) ??
+ false);
+ }).toList()
+ : allMessages;
return BlocConsumer(
listener: (context, state) async {
if (state is MediaGResponseSucess) {
+ final messages =
+ context.read().state.messages;
+ final heroMessage = messages.firstWhere(
+ (m) => m.id == 'hero',
+ orElse: () => Messages(id: null, role: 'user'),
+ );
+
+ if (heroMessage.id != null) {
+ context
+ .read()
+ .add(DeleteMessageWithId(messageId: 'hero'));
+ }
+
context.read().add(AddMessage(
message: Messages(
query: state.query,
file: state.file,
+ content: state.file != null
+ ? [
+ Content(
+ imageUrl:
+ FileUrl(url: state.file!.path))
+ ]
+ : state.query != null &&
+ state.query!.isNotEmpty
+ ? [
+ Content(
+ type: 'text', text: state.query)
+ ]
+ : null,
createdAt: DateTime.now().toIso8601String(),
error: state.response.error,
id: state.response.humanMessageId,
@@ -300,11 +361,16 @@ class _PhotoChatPageState extends State {
chatId = state.response.chatId;
}
+
+ if (state is MediaGResponseFail) {
+ context
+ .read()
+ .add(DeleteMessageWithId(messageId: 'hero'));
+ }
},
builder: (context, state) {
final newMaxSize = messages.length + 1;
- // استفاده از postFrameCallback برای جلوگیری از setState در build
if (maxSize.value != newMaxSize) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
@@ -318,7 +384,6 @@ class _PhotoChatPageState extends State {
return ListView(
physics: const BouncingScrollPhysics(),
children: [
- // Bot info section
Column(
children: [
const SizedBox(
@@ -497,7 +562,6 @@ class _PhotoChatPageState extends State {
),
],
),
- // Messages list
...messages.asMap().entries.map((entry) {
final index = entry.key;
final ms = entry.value;
@@ -545,30 +609,59 @@ class _PhotoChatPageState extends State {
16)),
child: AspectRatio(
aspectRatio: 3 / 4,
- child: user!.file != null
- ? ClipRRect(
- borderRadius:
- BorderRadius
- .circular(
- 12),
- child: CustomeImage(
- src: user
- .file!.path,
- fit: BoxFit.cover,
- ))
- : ImageNetwork(
- width:
- double.infinity,
- height:
- double.infinity,
- radius: 12,
- showHero: true,
- url: user
- .content
- ?.first
- .imageUrl
- ?.url ??
- ''),
+ child: Stack(
+ fit: StackFit.expand,
+ children: [
+ user!.file != null
+ ? ClipRRect(
+ borderRadius:
+ BorderRadius
+ .circular(
+ 12),
+ child:
+ CustomeImage(
+ src: user
+ .file!
+ .path,
+ fit: BoxFit
+ .cover,
+ ))
+ : ImageNetwork(
+ width: double
+ .infinity,
+ height: double
+ .infinity,
+ radius: 12,
+ showHero: true,
+ url: user
+ .content
+ ?.first
+ .imageUrl
+ ?.url ??
+ ''),
+ if (user.id == 'hero')
+ Container(
+ decoration:
+ BoxDecoration(
+ color: Colors
+ .black
+ .withOpacity(
+ 0.5),
+ borderRadius:
+ BorderRadius
+ .circular(
+ 12),
+ ),
+ child: Center(
+ child:
+ CircularProgressIndicator(
+ color: Colors
+ .white,
+ ),
+ ),
+ ),
+ ],
+ ),
),
),
after: Container(
@@ -684,52 +777,83 @@ class _PhotoChatPageState extends State {
?.url ??
''),
)
- : Padding(
- padding:
- const EdgeInsets.all(
- 16.0),
- child: Directionality(
- textDirection:
- TextDirection.rtl,
- child: Scrollbar(
- thumbVisibility: true,
- trackVisibility: true,
- interactive: true,
- controller:
- yourScrollController,
- radius: const Radius
- .circular(16),
- child:
- SingleChildScrollView(
- controller:
- yourScrollController,
- physics:
- const BouncingScrollPhysics(),
- child: Padding(
- padding:
- const EdgeInsets
- .only(
- left:
- 8.0),
+ : Stack(
+ children: [
+ Padding(
+ padding:
+ const EdgeInsets
+ .all(16.0),
+ child: Directionality(
+ textDirection:
+ TextDirection
+ .rtl,
+ child: Scrollbar(
+ thumbVisibility:
+ true,
+ trackVisibility:
+ true,
+ interactive: true,
+ controller:
+ yourScrollController,
+ radius:
+ const Radius
+ .circular(
+ 16),
child:
- SelectableText(
- user.query ??
- '',
+ SingleChildScrollView(
+ controller:
+ yourScrollController,
+ physics:
+ const BouncingScrollPhysics(),
+ child: Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ left:
+ 8.0),
+ child:
+ SelectableText(
+ user.query ??
+ '',
- style:
- AppTextStyles
+ style: AppTextStyles
.body4
.copyWith(
- color: Colors
- .white,
+ color: Colors
+ .white,
+ ),
+ // overflow: TextOverflow.ellipsis,
+ // textAlign: TextAlign.justify,
+ ),
),
- // overflow: TextOverflow.ellipsis,
- // textAlign: TextAlign.justify,
),
),
),
),
- ),
+ if (user.id == 'hero')
+ Positioned.fill(
+ child: Container(
+ decoration:
+ BoxDecoration(
+ color: Colors
+ .black
+ .withOpacity(
+ 0.5),
+ borderRadius:
+ BorderRadius
+ .circular(
+ 12),
+ ),
+ child: Center(
+ child:
+ CircularProgressIndicator(
+ color: Colors
+ .white,
+ ),
+ ),
+ ),
+ ),
+ ],
),
),
],
diff --git a/lib/ui/screens/gmedia/chats/video_chat_page.dart b/lib/ui/screens/gmedia/chats/video_chat_page.dart
index 024b38a..4016a96 100644
--- a/lib/ui/screens/gmedia/chats/video_chat_page.dart
+++ b/lib/ui/screens/gmedia/chats/video_chat_page.dart
@@ -316,7 +316,6 @@ class _TtaPageState extends State {
1 +
(state is MediaGResponseLoading ? 1 : 0);
- // استفاده از postFrameCallback برای جلوگیری از setState در build
if (maxSize.value != newMaxSize) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
@@ -653,7 +652,7 @@ class _TtaPageState extends State {
BorderRadius.circular(
12),
child: ChatVideoPlayer(
- src: ai?.content?.first
+ src: ai.content?.first
.videoUrl?.url ??
'',
custome:
diff --git a/lib/ui/screens/main/home/bloc/cubit/posts_cubit.dart b/lib/ui/screens/main/home/bloc/cubit/posts_cubit.dart
index bb69811..bdffde2 100644
--- a/lib/ui/screens/main/home/bloc/cubit/posts_cubit.dart
+++ b/lib/ui/screens/main/home/bloc/cubit/posts_cubit.dart
@@ -15,7 +15,7 @@ class PostsCubit extends Cubit {
// Disabled enabled.json check - always show posts
// try {
// final check = await CoursesServices.dio.get('/enabled.json');
- // print('🟢 enabled.json: ${check.data}');
+ // print('� enabled.json: ${check.data}');
// if (check.data == false) {
// emit(PostsFail());
// return;
diff --git a/lib/ui/screens/main/home/home_screen.dart b/lib/ui/screens/main/home/home_screen.dart
index 5c0740f..5348f66 100644
--- a/lib/ui/screens/main/home/home_screen.dart
+++ b/lib/ui/screens/main/home/home_screen.dart
@@ -32,7 +32,6 @@ import 'package:hoshan/ui/theme/colors.dart';
import 'package:hoshan/ui/theme/cubit/theme_mode_cubit.dart';
import 'package:hoshan/ui/theme/responsive.dart';
import 'package:hoshan/ui/theme/text.dart';
-import 'package:hoshan/ui/widgets/ai_Banner.dart';
import 'package:hoshan/ui/widgets/components/bot/bot_grid_card.dart';
import 'package:hoshan/ui/widgets/components/bot/bot_grid_card_placeholder.dart';
import 'package:hoshan/ui/widgets/components/bot/tool_card.dart';
diff --git a/lib/ui/screens/splash/splash_page.dart b/lib/ui/screens/splash/splash_page.dart
index d268c84..d7dff26 100644
--- a/lib/ui/screens/splash/splash_page.dart
+++ b/lib/ui/screens/splash/splash_page.dart
@@ -31,8 +31,10 @@ class _SplashPageState extends State {
@override
void initState() {
super.initState();
+ print('🎯 SplashPage: initState called');
WidgetsBinding.instance.addPostFrameCallback((_) async {
+ print('🎯 SplashPage: PostFrameCallback started');
bool hasDeepLink = false;
if (!kIsWeb) {
try {
@@ -92,11 +94,14 @@ class _SplashPageState extends State {
if (!hasDeepLink) {
String authToken = AuthTokenStorage.getToken();
+ print('🎯 SplashPage: Auth token = ${authToken.isEmpty ? "EMPTY" : "EXISTS"}');
if (mounted) {
if (authToken.isEmpty) {
+ print('🎯 SplashPage: Navigating to auth page');
FirebasApi.deleteToken();
context.go(Routes.auth);
} else {
+ print('🎯 SplashPage: Getting user info');
context.read().getUserInfo();
}
}
diff --git a/lib/ui/widgets/family_banner.dart b/lib/ui/widgets/family_banner.dart
index be464af..0adfddb 100644
--- a/lib/ui/widgets/family_banner.dart
+++ b/lib/ui/widgets/family_banner.dart
@@ -10,23 +10,16 @@ class FamilyBanner extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final hasParent = UserInfoCubit.userInfoModel.parent != null;
+
+ if (hasParent) {
+ return const SizedBox.shrink();
+ }
+
return Padding(
padding: const EdgeInsets.all(16.0),
child: GestureDetector(
onTap: () {
- final hasParent = UserInfoCubit.userInfoModel.parent != null;
-
- if (hasParent) {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text(
- 'شما عضو یک خانواده هستید و نمیتوانید خانواده جدید اضافه کنید',
- ),
- ),
- );
- return;
- }
-
Navigator.push(
context,
MaterialPageRoute(