liquid glass for ai
This commit is contained in:
parent
461eee1ed7
commit
63ab4c38d2
|
|
@ -116,6 +116,9 @@
|
|||
android:screenOrientation="portrait"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||
android:value="true" />
|
||||
|
||||
</application>
|
||||
|
||||
|
|
|
|||
241
lib/main.dart
241
lib/main.dart
|
|
@ -1,42 +1,39 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:app_links/app_links.dart';
|
||||
import 'package:bot_toast/bot_toast.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:home_widget/home_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:provider/single_child_widget.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/firebase_options.dart';
|
||||
import 'package:didvan/models/notification_message.dart';
|
||||
import 'package:didvan/models/requests/news.dart';
|
||||
import 'package:didvan/models/requests/radar.dart';
|
||||
import 'package:didvan/providers/media.dart';
|
||||
import 'package:didvan/providers/theme.dart';
|
||||
import 'package:didvan/providers/user.dart';
|
||||
import 'package:didvan/routes/route_generator.dart';
|
||||
import 'package:didvan/routes/routes.dart';
|
||||
import 'package:didvan/services/app_home_widget/home_widget_repository.dart';
|
||||
import 'package:didvan/services/media/media.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/services/notification/firebase_api.dart';
|
||||
import 'package:didvan/services/notification/notification_service.dart';
|
||||
import 'package:didvan/utils/my_custom_scroll_behavior.dart';
|
||||
import 'package:didvan/providers/media.dart';
|
||||
import 'package:didvan/providers/theme.dart';
|
||||
import 'package:didvan/providers/user.dart';
|
||||
import 'package:didvan/views/ai/ai_chat_state.dart';
|
||||
import 'package:didvan/views/ai/ai_state.dart';
|
||||
import 'package:didvan/views/ai/bot_assistants_state.dart';
|
||||
import 'package:didvan/views/ai/history_ai_chat_state.dart';
|
||||
import 'package:didvan/views/podcasts/podcasts_state.dart';
|
||||
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:home_widget/home_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
import 'package:app_links/app_links.dart';
|
||||
|
||||
import 'services/network/request.dart';
|
||||
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
Uri? initialURI;
|
||||
|
|
@ -52,29 +49,34 @@ void main() async {
|
|||
runZonedGuarded(
|
||||
() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
try {
|
||||
if (!kIsWeb) {
|
||||
HomeWidget.registerBackgroundCallback(_backgroundCallbackHomeWidget);
|
||||
HomeWidget.registerInteractivityCallback(_backgroundCallbackHomeWidget);
|
||||
HomeWidget.registerInteractivityCallback(
|
||||
_backgroundCallbackHomeWidget);
|
||||
await NotificationService.initializeNotification();
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
try {
|
||||
await FlutterDownloader.initialize(debug: true, ignoreSsl: true);
|
||||
} catch (e) {
|
||||
e.printError();
|
||||
}
|
||||
} catch (e) {
|
||||
e.printError();
|
||||
}
|
||||
}
|
||||
|
||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform);
|
||||
await FirebaseApi().initNotification();
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
debugPrint("Initialization Error: $e");
|
||||
}
|
||||
|
||||
await SentryFlutter.init(
|
||||
(options) {
|
||||
options.dsn = 'https://a4cfcaa7d67471240d295c25c968d91d@o4508585857384448.ingest.de.sentry.io/4508585886548048';
|
||||
options.dsn =
|
||||
'https://a4cfcaa7d67471240d295c25c968d91d@o4508585857384448.ingest.de.sentry.io/4508585886548048';
|
||||
options.tracesSampleRate = 1.0;
|
||||
options.profilesSampleRate = 1.0;
|
||||
},
|
||||
|
|
@ -95,9 +97,24 @@ class Didvan extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
|
||||
late AppLinks _appLinks;
|
||||
late final AppLinks _appLinks;
|
||||
StreamSubscription<Uri>? _linkSubscription;
|
||||
|
||||
final List<SingleChildWidget> _applicationProviders = [
|
||||
ChangeNotifierProvider<PodcastsState>(create: (_) => PodcastsState()),
|
||||
ChangeNotifierProvider<MediaProvider>(create: (_) => MediaProvider()),
|
||||
ChangeNotifierProvider<UserProvider>(create: (_) => UserProvider()),
|
||||
ChangeNotifierProvider<ThemeProvider>(create: (_) => ThemeProvider()),
|
||||
ChangeNotifierProvider<StudioDetailsState>(
|
||||
create: (_) => StudioDetailsState()),
|
||||
ChangeNotifierProvider<HistoryAiChatState>(
|
||||
create: (_) => HistoryAiChatState()),
|
||||
ChangeNotifierProvider<AiState>(create: (_) => AiState()),
|
||||
ChangeNotifierProvider<AiChatState>(create: (_) => AiChatState()),
|
||||
ChangeNotifierProvider<BotAssistantsState>(
|
||||
create: (_) => BotAssistantsState()),
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
|
@ -124,49 +141,47 @@ class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
|
|||
}
|
||||
|
||||
void _navigateTo(Uri uri) {
|
||||
if (mounted) {
|
||||
String path = uri.path;
|
||||
final Map<String, String> params = uri.queryParameters;
|
||||
if (!mounted) return;
|
||||
|
||||
final String? token = params['token'];
|
||||
final Map<String, String> params = uri.queryParameters;
|
||||
final String? token = params['token'];
|
||||
|
||||
if (token != null) {
|
||||
//todo: this didnt work
|
||||
print("DEBUG: received token in url, token: $token, path: $path");
|
||||
RequestService.token = token;
|
||||
if (token != null) {
|
||||
debugPrint("DeepLink Token Received: $token");
|
||||
RequestService.token = token;
|
||||
}
|
||||
|
||||
final String path = uri.path;
|
||||
|
||||
if (path.startsWith('/news/')) {
|
||||
final String idStr = path.split('/news/').last;
|
||||
final int? id = int.tryParse(idStr);
|
||||
if (id != null) {
|
||||
navigatorKey.currentState?.pushNamed(
|
||||
Routes.newsDetails,
|
||||
arguments: {'id': id, 'args': const NewsRequestArgs(page: 0)},
|
||||
);
|
||||
}
|
||||
|
||||
if (path.startsWith('/news/')) {
|
||||
final id = path.split('/news/').last;
|
||||
if (id.isNotEmpty) {
|
||||
navigatorKey.currentState?.pushNamed(
|
||||
Routes.newsDetails,
|
||||
arguments: {'id': int.parse(id), 'args': const NewsRequestArgs(page: 0)},
|
||||
);
|
||||
}
|
||||
} else if (path.startsWith('/radar/')) {
|
||||
final id = path.split('/radar/').last;
|
||||
if (id.isNotEmpty) {
|
||||
navigatorKey.currentState?.pushNamed(
|
||||
Routes.radarDetails,
|
||||
arguments: {'id': int.parse(id), 'args': const RadarRequestArgs(page: 0)},
|
||||
);
|
||||
}
|
||||
} else if (path.startsWith('/radar/')) {
|
||||
final String idStr = path.split('/radar/').last;
|
||||
final int? id = int.tryParse(idStr);
|
||||
if (id != null) {
|
||||
navigatorKey.currentState?.pushNamed(
|
||||
Routes.radarDetails,
|
||||
arguments: {'id': id, 'args': const RadarRequestArgs(page: 0)},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) async {
|
||||
if (!kIsWeb) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
var r = await HomeWidget.getWidgetData("cRoute", defaultValue: '');
|
||||
if (r.toString() != Routes.splash) {
|
||||
await HomeWidgetRepository.decideWhereToGo();
|
||||
NotificationMessage? data = HomeWidgetRepository.data;
|
||||
if (data != null) {
|
||||
await HomeWidgetRepository.decideWhereToGoNotif();
|
||||
}
|
||||
if (!kIsWeb && state == AppLifecycleState.resumed) {
|
||||
final route = await HomeWidget.getWidgetData("cRoute", defaultValue: '');
|
||||
if (route.toString() != Routes.splash) {
|
||||
await HomeWidgetRepository.decideWhereToGo();
|
||||
if (HomeWidgetRepository.data != null) {
|
||||
await HomeWidgetRepository.decideWhereToGoNotif();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -175,60 +190,60 @@ class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider<PodcastsState>(create: (context) => PodcastsState()),
|
||||
ChangeNotifierProvider<MediaProvider>(create: (context) => MediaProvider()),
|
||||
ChangeNotifierProvider<UserProvider>(create: (context) => UserProvider()),
|
||||
ChangeNotifierProvider<ThemeProvider>(create: (context) => ThemeProvider()),
|
||||
ChangeNotifierProvider<StudioDetailsState>(create: (context) => StudioDetailsState()),
|
||||
ChangeNotifierProvider<HistoryAiChatState>(create: (context) => HistoryAiChatState()),
|
||||
ChangeNotifierProvider<AiState>(create: (context) => AiState()),
|
||||
ChangeNotifierProvider<AiChatState>(create: (context) => AiChatState()),
|
||||
ChangeNotifierProvider<BotAssistantsState>(create: (context) => BotAssistantsState()),
|
||||
],
|
||||
providers: _applicationProviders,
|
||||
child: Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) => Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: SafeArea(
|
||||
child: MaterialApp(
|
||||
scrollBehavior: MyCustomScrollBehavior(),
|
||||
navigatorKey: navigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Didvan',
|
||||
theme: LightThemeConfig.themeData.copyWith(
|
||||
bottomSheetTheme: const BottomSheetThemeData(
|
||||
surfaceTintColor: Colors.transparent,
|
||||
backgroundColor: Colors.transparent),
|
||||
textTheme: LightThemeConfig.themeData.textTheme.apply(
|
||||
fontFamily: themeProvider.fontFamily,
|
||||
)),
|
||||
darkTheme: DarkThemeConfig.themeData.copyWith(
|
||||
bottomSheetTheme: const BottomSheetThemeData(
|
||||
surfaceTintColor: Colors.transparent,
|
||||
backgroundColor: Colors.transparent),
|
||||
textTheme: DarkThemeConfig.themeData.textTheme.apply(
|
||||
fontFamily: themeProvider.fontFamily,
|
||||
)),
|
||||
color: LightThemeConfig.themeData.primaryColor,
|
||||
themeMode: themeProvider.themeMode,
|
||||
onGenerateRoute: (settings) =>
|
||||
RouteGenerator.generateRoute(settings),
|
||||
builder: BotToastInit(),
|
||||
navigatorObservers: [BotToastNavigatorObserver()],
|
||||
initialRoute: "/",
|
||||
localizationsDelegates: const [
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [
|
||||
Locale("fa", "IR"),
|
||||
],
|
||||
locale: const Locale("fa", "IR"),
|
||||
builder: (context, themeProvider, child) {
|
||||
final lightTheme = LightThemeConfig.themeData.copyWith(
|
||||
bottomSheetTheme: const BottomSheetThemeData(
|
||||
surfaceTintColor: Colors.transparent,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
),
|
||||
),
|
||||
textTheme: LightThemeConfig.themeData.textTheme.apply(
|
||||
fontFamily: themeProvider.fontFamily,
|
||||
),
|
||||
);
|
||||
|
||||
final darkTheme = DarkThemeConfig.themeData.copyWith(
|
||||
bottomSheetTheme: const BottomSheetThemeData(
|
||||
surfaceTintColor: Colors.transparent,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
textTheme: DarkThemeConfig.themeData.textTheme.apply(
|
||||
fontFamily: themeProvider.fontFamily,
|
||||
),
|
||||
);
|
||||
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: SafeArea(
|
||||
child: MaterialApp(
|
||||
scrollBehavior: MyCustomScrollBehavior(),
|
||||
navigatorKey: navigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Didvan',
|
||||
theme: lightTheme,
|
||||
darkTheme: darkTheme,
|
||||
color: lightTheme.primaryColor,
|
||||
themeMode: themeProvider.themeMode,
|
||||
onGenerateRoute: (settings) =>
|
||||
RouteGenerator.generateRoute(settings),
|
||||
builder: BotToastInit(),
|
||||
navigatorObservers: [BotToastNavigatorObserver()],
|
||||
initialRoute: "/",
|
||||
localizationsDelegates: const [
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [
|
||||
Locale("fa", "IR"),
|
||||
],
|
||||
locale: const Locale("fa", "IR"),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ class MainPageContentType {
|
|||
final List<String> subtitles;
|
||||
final int? duration;
|
||||
final String? description;
|
||||
final String? riskScore;
|
||||
|
||||
MainPageContentType({
|
||||
required this.id,
|
||||
|
|
@ -19,6 +20,7 @@ class MainPageContentType {
|
|||
required this.subtitles,
|
||||
this.duration,
|
||||
this.description,
|
||||
this.riskScore,
|
||||
});
|
||||
|
||||
factory MainPageContentType.fromJson(Map<String, dynamic> json) =>
|
||||
|
|
@ -32,5 +34,6 @@ class MainPageContentType {
|
|||
subtitles: List<String>.from(json['subtitles']),
|
||||
duration: json['duration'],
|
||||
description: json['description'],
|
||||
riskScore: json['score'],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,6 @@ class UserProvider extends CoreProvier {
|
|||
|
||||
int get unreadMessageCount => _unreadMessageCount;
|
||||
|
||||
// static final List<MapEntry> _radarMarkQueue = [];
|
||||
// static final List<MapEntry> _newsMarkQueue = [];
|
||||
// static final List<MapEntry> _studioMarkQueue = [];
|
||||
static final List<MapEntry> _statisticMarkQueue = [];
|
||||
static final List<Map> _itemMarkQueue = [];
|
||||
|
||||
|
|
@ -76,7 +73,7 @@ class UserProvider extends CoreProvier {
|
|||
}
|
||||
} else {
|
||||
print(
|
||||
"UserProvider: Welcome message API failed. Status: ${service.statusCode}, Error: ${service.errorMessage}"); // Log failure
|
||||
"UserProvider: Welcome message API failed. Status: ${service.statusCode}, Error: ${service.errorMessage}");
|
||||
_welcomeMessage = null;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -109,6 +106,7 @@ class UserProvider extends CoreProvier {
|
|||
final RequestService service = RequestService(RequestHelper.userInfo);
|
||||
await service.httpGet();
|
||||
|
||||
// اگر توکن نامعتبر است (401)، فالس برمیگردانیم تا توکن پاک شود
|
||||
if (service.statusCode == 401) {
|
||||
print("UserProvider: getUserInfo failed - Unauthorized (401).");
|
||||
isAuthenticated = false;
|
||||
|
|
@ -150,6 +148,13 @@ class UserProvider extends CoreProvier {
|
|||
print(
|
||||
"UserProvider: getUserInfo failed. Status: ${service.statusCode}, Error: ${service.errorMessage}");
|
||||
isAuthenticated = false;
|
||||
|
||||
// اصلاح مهم: اگر خطا 401 نیست (مثلاً مشکل سرور یا اینترنت)، Exception پرتاب میکنیم
|
||||
// تا در Splash وارد بخش catch شود و توکن پاک نشود.
|
||||
if (service.statusCode != 401) {
|
||||
throw Exception("Server Error or Connection Issue: ${service.statusCode}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -295,56 +300,6 @@ class UserProvider extends CoreProvier {
|
|||
}
|
||||
}
|
||||
|
||||
// static Future<void> changeRadarMark(int id, bool value) async {
|
||||
// _radarMarkQueue.add(MapEntry(id, value));
|
||||
// Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
// final MapEntry? lastChange =
|
||||
// _radarMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
// if (lastChange == null) return;
|
||||
// final service = RequestService(RequestHelper.mark(id, 'radar'));
|
||||
// if (lastChange.value) {
|
||||
// await service.post();
|
||||
// } else {
|
||||
// await service.delete();
|
||||
// }
|
||||
// _radarMarkQueue.removeWhere((element) => element.key == id);
|
||||
// });
|
||||
// }
|
||||
|
||||
// static Future<void> changeStudioMark(int id, bool value) async {
|
||||
// _studioMarkQueue.add(MapEntry(id, value));
|
||||
// Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
// final MapEntry? lastChange =
|
||||
// _studioMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
// if (lastChange == null) return;
|
||||
// final service = RequestService(RequestHelper.mark(id, 'studio'));
|
||||
// if (lastChange.value) {
|
||||
// await service.post();
|
||||
// } else {
|
||||
// await service.delete();
|
||||
// }
|
||||
// _studioMarkQueue.removeWhere((element) => element.key == id);
|
||||
// });
|
||||
// }
|
||||
|
||||
// static Future<void> changeNewsMark(int id, bool value) async {
|
||||
// _newsMarkQueue.add(MapEntry(id, value));
|
||||
// Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
// final MapEntry? lastChange =
|
||||
// _newsMarkQueue.lastWhereOrNull((item) => item.key == id);
|
||||
// if (lastChange == null) return;
|
||||
// final service = RequestService(RequestHelper.mark(id, 'news'));
|
||||
// if (lastChange.value) {
|
||||
// await service.post();
|
||||
// } else {
|
||||
// await service.delete();
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// }
|
||||
// _newsMarkQueue.removeWhere((element) => element.key == id);
|
||||
// });
|
||||
// }
|
||||
|
||||
static Future<void> changeStatisticMark(int id, bool value) async {
|
||||
_statisticMarkQueue.add(MapEntry(id, value));
|
||||
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
|
|
@ -387,12 +342,4 @@ class UserProvider extends CoreProvier {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Future<void> getUnreadMessageCount() async {
|
||||
// final RequestService service = RequestService(RequestHelper.directs);
|
||||
// await service.httpGet();
|
||||
// if (service.isSuccess) {
|
||||
// _unreadMessageCount = service.result['unread'] ?? 0;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#include <flutter/runtime_effect.glsl>
|
||||
|
||||
uniform vec2 uResolution;
|
||||
uniform float uDistortionStrength;
|
||||
uniform float uBlurIntensity;
|
||||
uniform float uDispersion;
|
||||
uniform sampler2D uTexture;
|
||||
uniform vec2 uWidgetOffset;
|
||||
uniform vec2 uTextureSize;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec2 fragCoord = FlutterFragCoord();
|
||||
// 1. محاسبه مختصات UV جهانی
|
||||
vec2 globalPos = fragCoord + uWidgetOffset;
|
||||
vec2 uv = globalPos / uTextureSize;
|
||||
|
||||
// 2. ساخت ماسک لبه (فقط 8 درصد دور کادر برای لیکویید شدن)
|
||||
vec2 localUV = fragCoord / uResolution;
|
||||
|
||||
float distToEdgeX = min(localUV.x, 1.0 - localUV.x);
|
||||
float distToEdgeY = min(localUV.y, 1.0 - localUV.y);
|
||||
float distToEdge = min(distToEdgeX, distToEdgeY);
|
||||
|
||||
// ضخامت لبه شیشهای
|
||||
float borderThickness = 0.1;
|
||||
|
||||
// نرم کردن ماسک (از 0 تا 1)
|
||||
float borderMask = 1.0 - smoothstep(borderThickness - 0.09, borderThickness, distToEdge);
|
||||
|
||||
// اگر کاملاً در مرکز هستیم، فقط تکسچر را نشان بده
|
||||
if (borderMask <= 0.01) {
|
||||
fragColor = texture(uTexture, uv);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. اعوجاج (Distortion) در لبهها
|
||||
vec2 distortionDir = vec2(0.5) - localUV;
|
||||
// اعمال اعوجاج فقط در محدوده ماسک
|
||||
vec2 distortedUV = uv + (distortionDir * uDistortionStrength * 0.01 * borderMask);
|
||||
|
||||
// 4. بلور (Blur) و تجزیه رنگ (Dispersion)
|
||||
vec4 finalColor = vec4(0.0);
|
||||
|
||||
if (uBlurIntensity > 0.0) {
|
||||
// --- تغییر اصلی: افزایش ضریب برای منشور بیشتر ---
|
||||
// مقدار قبلی 0.008 بود، به 0.035 افزایش یافت تا رنگها بیشتر پخش شوند
|
||||
float dispersion = uDispersion * 0.010 * borderMask;
|
||||
|
||||
// نمونهبرداری با فاصله بیشتر برای کانالهای رنگی
|
||||
vec4 colR = texture(uTexture, distortedUV + vec2(dispersion, 0.0));
|
||||
vec4 colG = texture(uTexture, distortedUV);
|
||||
vec4 colB = texture(uTexture, distortedUV - vec2(dispersion, 0.0));
|
||||
|
||||
vec4 baseColor = vec4(colR.r, colG.g, colB.b, 1.0);
|
||||
|
||||
// بلور گاوسی ساده شده
|
||||
float blurStep = uBlurIntensity * 0.001 * borderMask;
|
||||
|
||||
vec4 blurCol = (
|
||||
texture(uTexture, distortedUV + vec2(blurStep, blurStep)) +
|
||||
texture(uTexture, distortedUV + vec2(-blurStep, -blurStep)) +
|
||||
texture(uTexture, distortedUV + vec2(blurStep, -blurStep)) +
|
||||
texture(uTexture, distortedUV + vec2(-blurStep, blurStep))
|
||||
) * 0.25; // اصلاح: ضریب 0.02 خیلی تیره بود، 0.25 میانگین دقیقتری است
|
||||
|
||||
// ترکیب رنگ اصلی با بلور
|
||||
// کاهش شدت میکس بلور (از 0.7 به 0.5) تا رنگهای منشور شفافتر دیده شوند
|
||||
finalColor = mix(baseColor, blurCol, 0.5);
|
||||
} else {
|
||||
finalColor = texture(uTexture, distortedUV);
|
||||
}
|
||||
|
||||
// 5. میکس نهایی (مرکز شفاف + لبههای شیشهای)
|
||||
vec4 clearCenter = texture(uTexture, uv);
|
||||
fragColor = mix(clearCenter, finalColor, borderMask);
|
||||
|
||||
// هایلایت سفید لبه
|
||||
float shine = smoothstep(0.0, borderThickness * 0.5, distToEdge) * (1.0 - smoothstep(borderThickness * 0.5, borderThickness, distToEdge));
|
||||
fragColor += vec4(shine * 0.15 * borderMask);
|
||||
}
|
||||
|
|
@ -964,7 +964,8 @@ class _AiChatPageState extends State<AiChatPage> with TickerProviderStateMixin {
|
|||
.withOpacity(0.9),
|
||||
border: Border.all(
|
||||
color: message.role.toString().contains('user')
|
||||
? const Color.fromARGB(0, 0, 0, 0) :Theme.of(context).colorScheme.border,
|
||||
? const Color.fromARGB(0, 0, 0, 0)
|
||||
: Theme.of(context).colorScheme.border,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
|
|
@ -1332,7 +1333,7 @@ class _AiChatPageState extends State<AiChatPage> with TickerProviderStateMixin {
|
|||
margin: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.file_copy),
|
||||
SvgPicture.asset('lib/assets/icons/copy.svg',),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
|
|
|
|||
|
|
@ -454,7 +454,9 @@ class _HistoryAiChatPageState extends State<HistoryAiChatPage> {
|
|||
DateTime.parse(chat
|
||||
.updatedAt
|
||||
.toString())
|
||||
.toPersianDateStr(monthString: ''),
|
||||
.toPersianDateStr(
|
||||
monthString:
|
||||
''),
|
||||
style:
|
||||
const TextStyle(
|
||||
fontSize:
|
||||
|
|
|
|||
|
|
@ -51,7 +51,10 @@ class _PasswordInputState extends State<PasswordInput> {
|
|||
onTap: () => state.currentPageIndex++,
|
||||
child: DidvanText(
|
||||
'فراموشی رمز عبور',
|
||||
style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.normal),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall
|
||||
?.copyWith(fontWeight: FontWeight.normal),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ class _ResetPasswordState extends State<ResetPassword> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final authState = context.watch<AuthenticationState>();
|
||||
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: AuthenticationLayout(
|
||||
|
|
@ -50,7 +52,7 @@ class _ResetPasswordState extends State<ResetPassword> {
|
|||
obsecureText: true,
|
||||
prefixSvgPath: 'lib/assets/icons/key.svg',
|
||||
),
|
||||
const Spacer(),
|
||||
const SizedBox(height: 32),
|
||||
DidvanButton(
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState!.validate()) {
|
||||
|
|
@ -79,8 +81,8 @@ class _ResetPasswordState extends State<ResetPassword> {
|
|||
},
|
||||
title: authState.hasPassword ? 'تغییر رمز عبور' : 'تایید رمز عبور',
|
||||
),
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
SizedBox(
|
||||
height: 48 + bottomInset,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/models/view/app_bar_data.dart';
|
||||
import 'package:didvan/views/comments/comments_state.dart';
|
||||
import 'package:didvan/views/comments/widgets/comment.dart';
|
||||
|
|
@ -75,17 +74,22 @@ class _CommentsState extends State<Comments> {
|
|||
builder: (context, state, child) => SliverStateHandler<CommentsState>(
|
||||
onRetry: state.getComments,
|
||||
state: state,
|
||||
itemPadding: const EdgeInsets.only( bottom: 20),
|
||||
itemPadding: (widget.pageData['type'] == 'news' ||
|
||||
widget.pageData['type'] == 'radar')
|
||||
? const EdgeInsets.only(bottom: 20, left: 20, right: 20)
|
||||
: const EdgeInsets.only(bottom: 20),
|
||||
childCount: state.comments.length,
|
||||
placeholder: const _CommentPlaceholder(),
|
||||
centerEmptyState: false,
|
||||
enableEmptyState: state.comments.isEmpty,
|
||||
paddingEmptyState: 0,
|
||||
emptyState: EmptyState(
|
||||
asset: Assets.emptyChat,
|
||||
emptyState: const EmptyState(
|
||||
asset: 'lib/assets/images/empty_states/Empty_List.png',
|
||||
title: 'لیست خالی است',
|
||||
titleColor: const Color.fromARGB(255, 0, 126, 167),
|
||||
subtitle: 'در حال حاضر آیتمی در این بخش ثبت نشده است. هر زمان مورد جدیدی اضافه شود، در اینجا نمایش داده میشود.',
|
||||
height: 500,
|
||||
titleColor: Color.fromARGB(255, 0, 126, 167),
|
||||
subtitle:
|
||||
'در حال حاضر آیتمی در این بخش ثبت نشده است. هر زمان مورد جدیدی اضافه شود، در اینجا نمایش داده میشود.',
|
||||
),
|
||||
builder: (context, state, index) => Comment(
|
||||
key: ValueKey(
|
||||
|
|
@ -337,4 +341,4 @@ class _CommentPlaceholder extends StatelessWidget {
|
|||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -262,8 +262,8 @@ class _MessageState extends State<Message> with SingleTickerProviderStateMixin {
|
|||
),
|
||||
),
|
||||
DidvanText(
|
||||
DateTimeUtils.timeWithAmPm(
|
||||
widget.message.createdAt).toPersianDigit(),
|
||||
DateTimeUtils.timeWithAmPm(widget.message.createdAt)
|
||||
.toPersianDigit(),
|
||||
style: Theme.of(context).textTheme.labelSmall,
|
||||
color: Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -641,7 +641,6 @@ class _FadeInSlide extends StatefulWidget {
|
|||
Key? key,
|
||||
required this.child,
|
||||
this.delay = Duration.zero,
|
||||
// ignore: unused_element_parameter
|
||||
this.duration = const Duration(milliseconds: 400),
|
||||
this.slideOffset = 50.0,
|
||||
}) : super(key: key);
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ class _FilteredBookmarksState extends State<FilteredBookmarks> {
|
|||
onMarkChanged: (id, value) =>
|
||||
_onBookmarkChanged(id, value, true, item.type),
|
||||
enableBookmark: true,
|
||||
useCardStyle: true, // **اعمال استایل کارت در لیست بوکمارک**
|
||||
useCardStyle: true,
|
||||
);
|
||||
},
|
||||
childCount: state.bookmarks.length +
|
||||
|
|
@ -174,4 +174,4 @@ class _FilteredBookmarksState extends State<FilteredBookmarks> {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/main.dart';
|
||||
|
|
@ -258,7 +260,8 @@ class SwotSection extends StatelessWidget {
|
|||
final double? headerSize;
|
||||
final double? moreSize;
|
||||
|
||||
const SwotSection({super.key, required this.swotItems, this.headerSize, this.moreSize});
|
||||
const SwotSection(
|
||||
{super.key, required this.swotItems, this.headerSize, this.moreSize});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -314,7 +317,9 @@ class SwotSection extends StatelessWidget {
|
|||
? Theme.of(context).textTheme.titleSmall
|
||||
: TextStyle(fontSize: moreSize),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: moreSize == null ? FontWeight.bold : FontWeight.normal,
|
||||
fontWeight: moreSize == null
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -1074,6 +1079,8 @@ class MainPageSection extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.all(9.5),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -1093,15 +1100,42 @@ class MainPageSection extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 13,
|
||||
height: 9,
|
||||
),
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 19,
|
||||
)
|
||||
],
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final riskValue = double.tryParse(item.riskScore ?? '0') ?? 0;
|
||||
final isNegative = riskValue < 0;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: (isNegative ? Colors.red : Colors.green)
|
||||
.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
isNegative
|
||||
? "lib/assets/images/features/Badge.svg"
|
||||
: "lib/assets/images/features/Badge-Green.svg",
|
||||
height: 9,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
"عدد ریسک : ${riskValue.abs().toInt().toString().toPersianDigit()}",
|
||||
style: TextStyle(
|
||||
color: isNegative ? Colors.red : Colors.green,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 12,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/models/notification_message.dart';
|
||||
import 'package:didvan/models/view/action_sheet_data.dart';
|
||||
import 'package:didvan/providers/theme.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/services/app_home_widget/home_widget_repository.dart';
|
||||
import 'package:didvan/utils/action_sheet.dart';
|
||||
import 'package:didvan/views/home/explore/explore.dart';
|
||||
import 'package:didvan/views/home/main/main_page.dart';
|
||||
|
|
@ -13,12 +18,6 @@ import 'package:didvan/views/home/search/search.dart';
|
|||
import 'package:didvan/views/ai_section/ai_section_page.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/didvan/bnb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import '../../services/app_home_widget/home_widget_repository.dart';
|
||||
|
||||
final GlobalKey<ScaffoldState> homeScaffKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
|
|
@ -36,74 +35,71 @@ class _HomeState extends State<Home>
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final state = context.read<HomeState>();
|
||||
DesignConfig.updateSystemUiOverlayStyle();
|
||||
|
||||
_tabController = TabController(length: 5, vsync: this, initialIndex: 0);
|
||||
state.tabController = _tabController;
|
||||
|
||||
_tabController.addListener(() {
|
||||
if (_tabController.indexIsChanging) {
|
||||
state.currentPageIndex = _tabController.index;
|
||||
} else {
|
||||
state.currentPageIndex = _tabController.index;
|
||||
}
|
||||
state.currentPageIndex = _tabController.index;
|
||||
});
|
||||
|
||||
if (!kIsWeb) {
|
||||
Future.delayed(Duration.zero, () {
|
||||
HomeWidgetRepository.fetchWidget();
|
||||
HomeWidgetRepository.decideWhereToGo();
|
||||
NotificationMessage? data = HomeWidgetRepository.data;
|
||||
if (data != null) {
|
||||
HomeWidgetRepository.decideWhereToGoNotif();
|
||||
Future.microtask(() async {
|
||||
await HomeWidgetRepository.fetchWidget();
|
||||
await HomeWidgetRepository.decideWhereToGo();
|
||||
if (HomeWidgetRepository.data != null) {
|
||||
await HomeWidgetRepository.decideWhereToGoNotif();
|
||||
}
|
||||
if (mounted) {
|
||||
AppInitializer.handleCLick(state, _tabController);
|
||||
}
|
||||
AppInitializer.handleCLick(state, _tabController);
|
||||
});
|
||||
}
|
||||
|
||||
state.refresh();
|
||||
context.read<ThemeProvider>().addListener(() {
|
||||
state.refresh();
|
||||
if (mounted) state.refresh();
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
PreferredSizeWidget? getAppBar() {
|
||||
return null;
|
||||
Future<void> _handleBackPress() async {
|
||||
if (context.read<HomeState>().tabController.index == 0) {
|
||||
if (kIsWeb) {
|
||||
return;
|
||||
}
|
||||
ActionSheetUtils(context).openDialog(
|
||||
data: ActionSheetData(
|
||||
content: const DidvanText('آیا قصد خروج از برنامه را دارید؟'),
|
||||
onConfirmed: () {
|
||||
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
|
||||
},
|
||||
isBackgroundDropBlur: true,
|
||||
confrimTitle: 'بله',
|
||||
dismissTitle: 'خیر',
|
||||
),
|
||||
);
|
||||
} else {
|
||||
_tabController.animateTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
key: homeScaffKey,
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
// ignore: deprecated_member_use
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
resizeToAvoidBottomInset: false,
|
||||
drawer: null,
|
||||
// ignore: deprecated_member_use
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (context.read<HomeState>().tabController.index == 0) {
|
||||
if (kIsWeb) {
|
||||
return true;
|
||||
}
|
||||
ActionSheetUtils(context).openDialog(
|
||||
data: ActionSheetData(
|
||||
content: const DidvanText(
|
||||
'آیا قصد خروج از برنامه را دارید؟',
|
||||
),
|
||||
onConfirmed: () {
|
||||
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
|
||||
},
|
||||
isBackgroundDropBlur: true,
|
||||
confrimTitle: 'بله',
|
||||
dismissTitle: 'خیر',
|
||||
));
|
||||
} else {
|
||||
_tabController.animateTo(0);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: Consumer<HomeState>(
|
||||
onPopInvoked: (didPop) async {
|
||||
if (didPop) return;
|
||||
await _handleBackPress();
|
||||
},
|
||||
child: Scaffold(
|
||||
key: homeScaffKey,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Consumer<HomeState>(
|
||||
builder: (context, state, child) => AnimatedCrossFade(
|
||||
duration: DesignConfig.lowAnimationDuration,
|
||||
crossFadeState: state.filtering
|
||||
|
|
@ -127,26 +123,24 @@ class _HomeState extends State<Home>
|
|||
secondChild: const SearchPage(),
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: Consumer<HomeState>(
|
||||
builder: (context, state, child) => DidvanBNB(
|
||||
currentTabIndex: state.currentPageIndex,
|
||||
onTabChanged: (index) {
|
||||
if (index < _tabController.length) {
|
||||
state.currentPageIndex = index;
|
||||
FocusScope.of(context).unfocus();
|
||||
state.resetFilters(false);
|
||||
_tabController.animateTo(index);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
.animate()
|
||||
.slideY(
|
||||
duration: 500.ms,
|
||||
begin: 1,
|
||||
curve: Curves.easeOut,
|
||||
bottomNavigationBar: Consumer<HomeState>(
|
||||
builder: (context, state, child) => DidvanBNB(
|
||||
currentTabIndex: state.currentPageIndex,
|
||||
onTabChanged: (index) {
|
||||
if (index < _tabController.length) {
|
||||
state.currentPageIndex = index;
|
||||
FocusScope.of(context).unfocus();
|
||||
state.resetFilters(false);
|
||||
_tabController.animateTo(index);
|
||||
}
|
||||
},
|
||||
),
|
||||
).animate().slideY(
|
||||
duration: 500.ms,
|
||||
begin: 1,
|
||||
curve: Curves.easeOut,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,34 @@
|
|||
// ignore_for_file: unnecessary_import
|
||||
// lib/views/home/main/main_page.dart
|
||||
|
||||
// ignore_for_file: unnecessary_import, deprecated_member_use
|
||||
|
||||
import 'package:didvan/views/home/explore/explore.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/models/home_page_content/content.dart';
|
||||
import 'package:didvan/models/home_page_content/home_page_list.dart';
|
||||
import 'package:didvan/models/home_page_content/swot.dart';
|
||||
import 'package:didvan/services/app_initalizer.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
import 'package:didvan/views/home/explore/explore.dart';
|
||||
import 'package:didvan/views/home/home_state.dart';
|
||||
import 'package:didvan/views/home/main/main_page_state.dart';
|
||||
import 'package:didvan/views/home/new_statistic/new_statistics_state.dart';
|
||||
import 'package:didvan/views/home/main/widgets/main_content.dart';
|
||||
import 'package:didvan/views/home/main/widgets/story_section.dart';
|
||||
import 'package:didvan/views/home/main/widgets/simple_explore_card.dart';
|
||||
import 'package:didvan/views/home/main/widgets/didvan_plus_section.dart';
|
||||
import 'package:didvan/views/home/main/widgets/didvan_voice_section.dart';
|
||||
import 'package:didvan/views/home/new_statistic/new_statistics_state.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
|
||||
import 'package:didvan/views/widgets/carousel_3d.dart';
|
||||
import 'package:didvan/views/home/home_state.dart';
|
||||
import 'package:didvan/views/widgets/text_divider.dart';
|
||||
import 'package:didvan/views/widgets/home_app_bar.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform;
|
||||
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
bool isAnyMobile() {
|
||||
if (kIsWeb) {
|
||||
|
|
@ -45,9 +43,7 @@ bool isAnyMobile() {
|
|||
}
|
||||
|
||||
class MainPage extends StatefulWidget {
|
||||
const MainPage({
|
||||
super.key,
|
||||
});
|
||||
const MainPage({super.key});
|
||||
|
||||
@override
|
||||
State<MainPage> createState() => _MainPageState();
|
||||
|
|
@ -73,6 +69,7 @@ class _MainPageState extends State<MainPage> {
|
|||
'🏠 MainPage build - didvanPlus: ${state.didvanPlus != null}');
|
||||
debugPrint(
|
||||
'🏠 MainPage build - didvanVoice: ${state.didvanVoice != null}');
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
const HomeAppBar(
|
||||
|
|
@ -83,6 +80,7 @@ class _MainPageState extends State<MainPage> {
|
|||
child: ListView(
|
||||
padding: const EdgeInsets.only(top: 0, bottom: 16),
|
||||
children: [
|
||||
// --- Stories Section ---
|
||||
if (state.stories.isNotEmpty) ...[
|
||||
const TextDivider(text: 'دیدهبان')
|
||||
.animate()
|
||||
|
|
@ -95,12 +93,16 @@ class _MainPageState extends State<MainPage> {
|
|||
child: StorySection(stories: state.stories),
|
||||
).animate().fadeIn(delay: 600.ms, duration: 500.ms),
|
||||
],
|
||||
|
||||
// --- Didvan Plus ---
|
||||
if (state.didvanPlus != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
DidvanPlusSection(didvanPlus: state.didvanPlus!)
|
||||
.animate()
|
||||
.fadeIn(delay: 650.ms, duration: 500.ms),
|
||||
],
|
||||
|
||||
// --- Strategic Dashboard ---
|
||||
const SizedBox(height: 12),
|
||||
const TextDivider(text: 'پیشخوان استراتژیک')
|
||||
.animate()
|
||||
|
|
@ -109,6 +111,8 @@ class _MainPageState extends State<MainPage> {
|
|||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: MainPageMainContent(),
|
||||
).animate().fadeIn(delay: 800.ms, duration: 500.ms),
|
||||
|
||||
// --- Explore Latest ---
|
||||
if (state.content != null &&
|
||||
state.content!.lists.isNotEmpty) ...[
|
||||
const _ExploreLatestTitle()
|
||||
|
|
@ -119,10 +123,16 @@ class _MainPageState extends State<MainPage> {
|
|||
swotItems: state.swotItems,
|
||||
).animate().fadeIn(delay: 1000.ms, duration: 500.ms),
|
||||
],
|
||||
|
||||
// --- SWOT Items ---
|
||||
if (state.swotItems.isNotEmpty)
|
||||
SwotSection(swotItems: state.swotItems,headerSize: 13,moreSize: 12,)
|
||||
.animate()
|
||||
.fadeIn(delay: 1100.ms, duration: 500.ms),
|
||||
SwotSection(
|
||||
swotItems: state.swotItems,
|
||||
headerSize: 13,
|
||||
moreSize: 12,
|
||||
).animate().fadeIn(delay: 1100.ms, duration: 500.ms),
|
||||
|
||||
// --- Didvan Voice ---
|
||||
if (state.didvanVoice != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
const _DidvanVoiceTitle()
|
||||
|
|
@ -133,6 +143,8 @@ class _MainPageState extends State<MainPage> {
|
|||
.animate()
|
||||
.fadeIn(delay: 1200.ms, duration: 500.ms),
|
||||
],
|
||||
|
||||
// --- Commented Out Section (Industry Pulse) ---
|
||||
// const _IndustryPulseTitle()
|
||||
// .animate()
|
||||
// .fadeIn(delay: 1100.ms, duration: 500.ms),
|
||||
|
|
@ -149,18 +161,15 @@ class _MainPageState extends State<MainPage> {
|
|||
}
|
||||
}
|
||||
|
||||
// --- Sub Widgets ---
|
||||
|
||||
class _DidvanSignalsTitle extends StatelessWidget {
|
||||
const _DidvanSignalsTitle();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 16,
|
||||
top: 0,
|
||||
),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
|
|
@ -221,12 +230,7 @@ class _ExploreLatestTitle extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 16,
|
||||
top: 0,
|
||||
),
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
|
@ -284,10 +288,7 @@ class _ExploreLatestSlider extends StatelessWidget {
|
|||
itemsData = [];
|
||||
|
||||
for (var list in lists) {
|
||||
if (list.type == 'video' ||
|
||||
list.type == 'podcast' ||
|
||||
list.type == 'news' ||
|
||||
list.type == 'radar') {
|
||||
if (['video', 'podcast', 'news', 'radar'].contains(list.type)) {
|
||||
continue;
|
||||
}
|
||||
if (list.contents.isNotEmpty) {
|
||||
|
|
@ -318,18 +319,14 @@ class _ExploreLatestSlider extends StatelessWidget {
|
|||
itemsData.add((type: 'swot', content: null, swotItem: swotItems.first));
|
||||
}
|
||||
|
||||
if (items.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
if (items.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Carousel3D(
|
||||
items: items,
|
||||
height: 220,
|
||||
autoPlayDuration: const Duration(seconds: 5),
|
||||
showControls: true,
|
||||
onItemChanged: (index) {
|
||||
// Optional: Handle item change if needed
|
||||
},
|
||||
onItemChanged: (index) {},
|
||||
onItemTap: (index) {
|
||||
final data = itemsData[index];
|
||||
if (data.swotItem != null) {
|
||||
|
|
@ -351,6 +348,10 @@ class _ExploreLatestSlider extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ------------------------- COMMENTED OUT SECTIONS --------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// class _IndustryPulseTitle extends StatelessWidget {
|
||||
// const _IndustryPulseTitle();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/models/didvan_plus_model.dart';
|
||||
import 'package:didvan/services/network/request_helper.dart';
|
||||
import 'package:didvan/services/network/request.dart';
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import 'package:didvan/views/widgets/didvan/card.dart';
|
|||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/infography_tag.dart';
|
||||
import 'package:didvan/views/widgets/ink_wrapper.dart';
|
||||
import 'package:didvan/views/widgets/liked_button.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ class SimpleExploreCard extends StatelessWidget {
|
|||
return 'lib/assets/icons/Startup.svg';
|
||||
case 'radar':
|
||||
return 'lib/assets/icons/Pouyesh_Ofogh_New.svg';
|
||||
case 'trend': // رادار روند
|
||||
case 'trend':
|
||||
case 'trends':
|
||||
return 'lib/assets/icons/Ravand.svg';
|
||||
case 'technology': // رادار تکنولوزی/فناوری
|
||||
case 'technology':
|
||||
case 'tech':
|
||||
return 'lib/assets/icons/Technology.svg';
|
||||
case 'risk': // رادار ریسک
|
||||
case 'risk':
|
||||
return 'lib/assets/icons/RiskRadar.svg';
|
||||
case 'survey':
|
||||
case 'delphi':
|
||||
|
|
|
|||
|
|
@ -292,14 +292,13 @@ class _PodcastTabPageState extends State<PodcastTabPage> {
|
|||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
final podcast = state.studios[index];
|
||||
|
||||
// NEW: بررسی اینکه آیا این آیتم، آخرین آیتم در لیست است
|
||||
|
||||
final bool isLast = index == state.studios.length - 1;
|
||||
|
||||
return PodcastListCard(
|
||||
podcast: podcast,
|
||||
onTap: () => _navigateToDetails(index),
|
||||
isLastItem: isLast, // NEW: ارسال پارامتر به ویجت کارت
|
||||
isLastItem: isLast,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
@ -310,4 +309,4 @@ class _PodcastTabPageState extends State<PodcastTabPage> {
|
|||
onRetry: () => context.read<PodcastsState>().getStudios(page: 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
import 'package:chewie/chewie.dart';
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/studio_details_data.dart';
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ import 'package:persian_number_utility/persian_number_utility.dart';
|
|||
class PodcastListCard extends StatelessWidget {
|
||||
final OverviewData podcast;
|
||||
final VoidCallback onTap;
|
||||
final bool isLastItem; // NEW: پارامتر جدید برای تشخیص آیتم آخر
|
||||
final bool isLastItem;
|
||||
|
||||
const PodcastListCard({
|
||||
super.key,
|
||||
required this.podcast,
|
||||
required this.onTap,
|
||||
this.isLastItem = false, // NEW: مقداردهی اولیه پارامتر
|
||||
this.isLastItem = false,
|
||||
});
|
||||
|
||||
String _formatDuration(int? duration) {
|
||||
|
|
@ -143,7 +143,6 @@ class PodcastListCard extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
// NEW: چک میکنیم که آیا آیتم آخر است یا نه
|
||||
if (!isLastItem)
|
||||
Divider(
|
||||
color: Colors.grey[300],
|
||||
|
|
@ -155,4 +154,4 @@ class PodcastListCard extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,13 +46,13 @@ class _NewStatisticState extends State<NewStatistic> {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// ignore: prefer_const_constructors
|
||||
HomeAppBar(
|
||||
showSearchField: true,
|
||||
),
|
||||
Center(
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: DidvanText(
|
||||
'دستهبندیهای کلان',
|
||||
|
|
@ -102,8 +102,7 @@ class _NewStatisticState extends State<NewStatistic> {
|
|||
itemsInStatics(context, state, 1, DidvanIcons.currency_solid),
|
||||
itemsInStatics(context, state, 2, DidvanIcons.bitcoin_solid),
|
||||
itemsInStatics(context, state, 3, DidvanIcons.metal_solid),
|
||||
itemsInStatics(
|
||||
context, state, 4, DidvanIcons.commodity_solid),
|
||||
itemsInStatics(context, state, 4, DidvanIcons.commodity_solid),
|
||||
itemsInStatics(context, state, 5, DidvanIcons.industry_solid,
|
||||
hasDivider: false),
|
||||
const SizedBox(
|
||||
|
|
@ -369,4 +368,4 @@ class StatHeader extends StatelessWidget {
|
|||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,11 +112,11 @@ class _MentionsState extends State<Mentions> {
|
|||
enableEmptyState: state.comments.isEmpty,
|
||||
paddingEmptyState: 0,
|
||||
emptyState: const EmptyState(
|
||||
asset: 'lib/assets/images/empty_states/Empty_List.png',
|
||||
title: 'دوستان خود را فراخوانی کنید',
|
||||
titleColor: Color.fromARGB(255, 0, 126, 167),
|
||||
height: 550,
|
||||
),
|
||||
asset: 'lib/assets/images/empty_states/Empty_List.png',
|
||||
title: 'دوستان خود را فراخوانی کنید',
|
||||
titleColor: Color.fromARGB(255, 0, 126, 167),
|
||||
height: 550,
|
||||
),
|
||||
builder: (context, state, index) => Mention(
|
||||
key: ValueKey(
|
||||
state.comments[index].id.toString() +
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ class _NewsState extends State<News> {
|
|||
title: Text(
|
||||
'دنیای فولاد',
|
||||
style: theme.textTheme.headlineSmall?.copyWith(
|
||||
color: DesignConfig.isDark? const Color.fromARGB(255, 0, 90, 119) : const Color.fromARGB(255, 0, 53, 70),
|
||||
color: DesignConfig.isDark
|
||||
? const Color.fromARGB(255, 0, 90, 119)
|
||||
: const Color.fromARGB(255, 0, 53, 70),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 19),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
|
|
@ -438,7 +440,6 @@ class _CategoryExpansionGroupState extends State<_CategoryExpansionGroup> {
|
|||
textDirection: TextDirection.ltr,
|
||||
child: CupertinoSwitch(
|
||||
value: item.selected ?? false,
|
||||
// ignore: deprecated_member_use
|
||||
activeColor:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
onChanged: (value) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ final List<OnboardingEntity> onboardingPages = [
|
|||
OnboardingEntity(
|
||||
imagePath: 'lib/assets/images/onboarding/1.png',
|
||||
title: 'هوشان',
|
||||
description: 'ارائه ابزارهای هوش مصنوعی مورد نیاز مدیران اعم از خلاصهساز، ساخت عکس، تحلیل و ترسیم نمودار، تبدیل متن به صوت، ساخت ویدیو و ترجمه، امکان پرسش و پاسخ از مدلهای زبانی مختلف و یا جستجوی هوشمند در محتوای داخلی از طریق دستیار اختصاصی هوش مصنوعی دیدوان.',
|
||||
description:
|
||||
'ارائه ابزارهای هوش مصنوعی مورد نیاز مدیران اعم از خلاصهساز، ساخت عکس، تحلیل و ترسیم نمودار، تبدیل متن به صوت، ساخت ویدیو و ترجمه، امکان پرسش و پاسخ از مدلهای زبانی مختلف و یا جستجوی هوشمند در محتوای داخلی از طریق دستیار اختصاصی هوش مصنوعی دیدوان.',
|
||||
),
|
||||
];
|
||||
|
||||
|
|
@ -168,7 +169,9 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10,),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Padding(
|
||||
|
|
@ -184,7 +187,8 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||
theme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22,
|
||||
color: const Color.fromARGB(255, 0, 126, 167),
|
||||
color:
|
||||
const Color.fromARGB(255, 0, 126, 167),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 13),
|
||||
|
|
@ -193,10 +197,10 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||
textDirection: TextDirection.rtl,
|
||||
textAlign: TextAlign.start,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: const Color.fromARGB(255, 41, 41, 41),
|
||||
height: 1.6,
|
||||
fontSize: 14
|
||||
),
|
||||
color:
|
||||
const Color.fromARGB(255, 41, 41, 41),
|
||||
height: 1.6,
|
||||
fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -208,7 +212,6 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||
},
|
||||
),
|
||||
),
|
||||
|
||||
if (_currentPage > 0)
|
||||
Positioned(
|
||||
top: 16,
|
||||
|
|
@ -234,7 +237,6 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
|
||||
Positioned(
|
||||
bottom: 30,
|
||||
left: 24,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import 'package:chewie/chewie.dart';
|
|||
import 'package:didvan/config/design_config.dart';
|
||||
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/models/studio_details_data.dart';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
|
|
@ -44,7 +46,10 @@ class ChatRoomItem extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
chatRoom.lastMessage.writedByAdmin? chatRoom.lastMessage.readed ?'lib/assets/icons/sms.svg' :'lib/assets/icons/sms-notification.svg'
|
||||
chatRoom.lastMessage.writedByAdmin
|
||||
? chatRoom.lastMessage.readed
|
||||
? 'lib/assets/icons/sms.svg'
|
||||
: 'lib/assets/icons/sms-notification.svg'
|
||||
: 'lib/assets/icons/sms-tracking.svg',
|
||||
height: 24,
|
||||
width: 24,
|
||||
|
|
@ -87,8 +92,12 @@ class ChatRoomItem extends StatelessWidget {
|
|||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10, 8, 10, 8),
|
||||
child: Text(
|
||||
chatRoom.lastMessage.writedByAdmin? chatRoom.lastMessage.readed
|
||||
? 'پاسخ داده شده' : 'خوانده نشده' : 'در انتظار پاسخ',),
|
||||
chatRoom.lastMessage.writedByAdmin
|
||||
? chatRoom.lastMessage.readed
|
||||
? 'پاسخ داده شده'
|
||||
: 'خوانده نشده'
|
||||
: 'در انتظار پاسخ',
|
||||
),
|
||||
),
|
||||
),
|
||||
// Icon(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: avoid_print, deprecated_member_use
|
||||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/app_icons.dart';
|
||||
|
|
@ -159,11 +161,12 @@ class _ProfilePageState extends State<ProfilePage>
|
|||
image:
|
||||
(user.photo != null && user.photo!.isNotEmpty)
|
||||
? DecorationImage(
|
||||
image: NetworkImage('https://api.didvan.app${user.photo!}',
|
||||
headers: {
|
||||
'Authorization':
|
||||
'Bearer ${RequestService.token}',
|
||||
}),
|
||||
image: NetworkImage(
|
||||
'https://api.didvan.app${user.photo!}',
|
||||
headers: {
|
||||
'Authorization':
|
||||
'Bearer ${RequestService.token}',
|
||||
}),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: null,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// ignore_for_file: deprecated_member_use, avoid_print
|
||||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/constants/assets.dart';
|
||||
import 'package:didvan/main.dart';
|
||||
import 'package:didvan/providers/media.dart';
|
||||
|
|
@ -40,7 +39,7 @@ class _SplashState extends State<Splash> with TickerProviderStateMixin {
|
|||
|
||||
_pulseController = AnimationController(
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
vsync: this,
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_pulseAnimation = Tween<double>(
|
||||
|
|
@ -195,18 +194,6 @@ class _SplashState extends State<Splash> with TickerProviderStateMixin {
|
|||
],
|
||||
|
||||
const Spacer(flex: 3),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: Text(
|
||||
'توسعه یافته توسط فرتاک',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: colorScheme.onBackground.withOpacity(0.4),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -251,15 +238,16 @@ class _SplashState extends State<Splash> with TickerProviderStateMixin {
|
|||
await mediaProvider.getDownloadsList();
|
||||
}
|
||||
|
||||
// اگر اینجا خطای سرور رخ دهد (به خاطر تغییر در user.dart)، کد به بلوک catch میرود
|
||||
final result = await userProvider.getUserInfo();
|
||||
|
||||
if (!result) {
|
||||
// این بخش فقط زمانی اجرا میشود که سرور پاسخ ۴۰۱ (نامعتبر بودن توکن) داده باشد
|
||||
print("no results were returned for user info");
|
||||
try {
|
||||
StorageService.delete(key: 'token');
|
||||
} catch (e) {
|
||||
print("error in case of no user info result: $e");
|
||||
// catch
|
||||
}
|
||||
|
||||
navigatorKey.currentState!.pushNamedAndRemoveUntil(
|
||||
|
|
@ -281,7 +269,6 @@ class _SplashState extends State<Splash> with TickerProviderStateMixin {
|
|||
|
||||
if (destinationRoute == Routes.home) {
|
||||
print("destination route was home and init uri is $initialURI");
|
||||
// (routeArguments as Map)['deepLinkUri'] = initialURI;
|
||||
initialURI = null;
|
||||
}
|
||||
|
||||
|
|
@ -296,6 +283,7 @@ class _SplashState extends State<Splash> with TickerProviderStateMixin {
|
|||
arguments: routeArguments,
|
||||
);
|
||||
} catch (e) {
|
||||
// اگر خطای سرور رخ دهد، اینجا گرفته میشود و دکمه تلاش مجدد نشان داده میشود
|
||||
setState(() {
|
||||
_errorOccured = true;
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -149,8 +149,7 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
_isAiSpeaking = false;
|
||||
});
|
||||
}
|
||||
|
||||
// <<< راهحل مشکل ۲: ریست کردن پاسخ قبلی
|
||||
|
||||
if (_currentAiResponse != null) {
|
||||
setState(() {
|
||||
_currentAiResponse = null;
|
||||
|
|
@ -178,7 +177,6 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
// <<< راهحل مشکل ۲: بررسی وضعیت قبل از شروع ضبط
|
||||
if (mounted && _isPreparing) {
|
||||
setState(() {
|
||||
_isPreparing = false;
|
||||
|
|
@ -188,11 +186,9 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
_preparingController.stop();
|
||||
_waveController.repeat();
|
||||
} else if (mounted) {
|
||||
// اگر کاربر انگشت خود را برداشته بود (_isPreparing false شده)
|
||||
await _audioRecorder.stop(); // ضبط را متوقف کن
|
||||
await _audioRecorder.stop();
|
||||
_waveController.stop();
|
||||
}
|
||||
// >>>
|
||||
}
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
|
|
@ -200,7 +196,6 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
_isRecording = false;
|
||||
_statusText = 'خطا در شروع ضبط صدا';
|
||||
});
|
||||
// <<< راهحل مشکل ۲: توقف انیمیشنها در صورت خطا
|
||||
_preparingController.stop();
|
||||
_waveController.stop();
|
||||
// >>>
|
||||
|
|
@ -475,8 +470,8 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
top: 0,
|
||||
child: _buildVisualization(),
|
||||
),
|
||||
// وقتی پاسخ هست، کارت پاسخ را نمایش میدهیم
|
||||
if (_currentAiResponse != null && _currentAiResponse!.isNotEmpty)
|
||||
if (_currentAiResponse != null &&
|
||||
_currentAiResponse!.isNotEmpty)
|
||||
Positioned(
|
||||
bottom: 120,
|
||||
left: 24,
|
||||
|
|
@ -484,7 +479,6 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
child: _buildResponsePreview(),
|
||||
)
|
||||
else
|
||||
// در غیر این صورت، متن status را نمایش میدهیم
|
||||
Positioned(
|
||||
bottom: 130,
|
||||
left: 24,
|
||||
|
|
@ -709,7 +703,8 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFF00AAFF).withOpacity(0.4),
|
||||
color: const Color(0xFF00AAFF)
|
||||
.withOpacity(0.4),
|
||||
blurRadius: 12,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
|
|
@ -872,7 +867,8 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFF00AAFF).withOpacity(0.4),
|
||||
color:
|
||||
const Color(0xFF00AAFF).withOpacity(0.4),
|
||||
blurRadius: 15,
|
||||
spreadRadius: 2,
|
||||
),
|
||||
|
|
@ -953,7 +949,8 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: _currentAiResponse ?? ''));
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: _currentAiResponse ?? ''));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: const DidvanText(
|
||||
|
|
@ -1033,15 +1030,13 @@ class _AiVoiceChatDialogState extends State<AiVoiceChatDialog>
|
|||
_startRecording();
|
||||
}
|
||||
},
|
||||
// <<< راهحل مشکل ۲: (بدون تغییر، همچنان پابرجاست)
|
||||
onLongPressEnd: (_) {
|
||||
if (_isRecording) {
|
||||
_stopRecording();
|
||||
} else if (_isPreparing) {
|
||||
// کاربر انگشت خود را در حین آمادهسازی برداشت
|
||||
setState(() {
|
||||
_isPreparing = false;
|
||||
_statusText = 'برای شروع مکالمه، دکمه میکروفون را نگه دارید';
|
||||
_statusText = 'برای شروع مکالمه، دکمه میکروفون را نگه دارید';
|
||||
});
|
||||
_preparingController.stop();
|
||||
_waveController.stop();
|
||||
|
|
@ -1236,4 +1231,4 @@ class PreparingSpinnerPainter extends CustomPainter {
|
|||
bool shouldRepaint(covariant PreparingSpinnerPainter oldDelegate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'package:didvan/config/design_config.dart';
|
||||
import 'package:didvan/config/theme_data.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
|
|
@ -312,7 +314,10 @@ class _NavBarItemState extends State<_NavBarItem>
|
|||
duration: const Duration(milliseconds: 150),
|
||||
child: DidvanText(
|
||||
widget.title,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 11),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(fontSize: 11),
|
||||
color: Theme.of(context).colorScheme.caption,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -491,9 +491,53 @@ class _DidvanPageViewState extends State<DidvanPageView> {
|
|||
const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 4),
|
||||
child: MultitypeOverview(
|
||||
item: item.relatedContents[i],
|
||||
onMarkChanged: (id, value) {},
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
final relatedItem =
|
||||
item.relatedContents[i];
|
||||
if (relatedItem.type ==
|
||||
'news') {
|
||||
Navigator.of(context)
|
||||
.pushNamed(
|
||||
Routes.newsDetails,
|
||||
arguments: {
|
||||
'id': relatedItem.id,
|
||||
'args':
|
||||
const NewsRequestArgs(
|
||||
page: 0),
|
||||
'onMarkChanged':
|
||||
(id, value) {},
|
||||
'hasUnmarkConfirmation':
|
||||
false,
|
||||
},
|
||||
);
|
||||
} else if (relatedItem
|
||||
.type ==
|
||||
'radar') {
|
||||
Navigator.of(context)
|
||||
.pushNamed(
|
||||
Routes.radarDetails,
|
||||
arguments: {
|
||||
'id': relatedItem.id,
|
||||
'args':
|
||||
const RadarRequestArgs(
|
||||
page: 0),
|
||||
'onMarkChanged':
|
||||
(id, value) {},
|
||||
'onCommentsChanged':
|
||||
(id, count) {},
|
||||
'hasUnmarkConfirmation':
|
||||
false,
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
child: MultitypeOverview(
|
||||
item:
|
||||
item.relatedContents[i],
|
||||
onMarkChanged:
|
||||
(id, value) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GlassShader {
|
||||
ui.FragmentProgram? _program;
|
||||
ui.FragmentShader? _shader;
|
||||
|
||||
Future<void> initialize() async {
|
||||
_program = await ui.FragmentProgram.fromAsset(
|
||||
'lib/shaders/liquid_glass_lens.frag');
|
||||
_shader = _program!.fragmentShader();
|
||||
}
|
||||
|
||||
ui.FragmentShader? get shader => _shader;
|
||||
|
||||
void updateUniforms({
|
||||
required Size widgetSize,
|
||||
required Size textureSize,
|
||||
required Offset widgetOffset,
|
||||
required double distortion,
|
||||
required double blur,
|
||||
required double dispersion,
|
||||
required ui.Image texture,
|
||||
}) {
|
||||
if (_shader == null) return;
|
||||
|
||||
// uniform vec2 uResolution;
|
||||
// uniform float uDistortionStrength;
|
||||
// uniform float uBlurIntensity;
|
||||
// uniform float uDispersion;
|
||||
// uniform sampler2D uTexture;
|
||||
// uniform vec2 uWidgetOffset;
|
||||
// uniform vec2 uTextureSize;
|
||||
|
||||
_shader!.setFloat(0, widgetSize.width);
|
||||
_shader!.setFloat(1, widgetSize.height);
|
||||
_shader!.setFloat(2, distortion);
|
||||
_shader!.setFloat(3, blur);
|
||||
_shader!.setFloat(4, dispersion);
|
||||
_shader!.setImageSampler(0, texture);
|
||||
_shader!.setFloat(5, widgetOffset.dx);
|
||||
_shader!.setFloat(6, widgetOffset.dy);
|
||||
_shader!.setFloat(7, textureSize.width);
|
||||
_shader!.setFloat(8, textureSize.height);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'glass_logic.dart';
|
||||
|
||||
class ShaderPainter extends CustomPainter {
|
||||
ShaderPainter(this.shader);
|
||||
final ui.FragmentShader shader;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()..shader = shader;
|
||||
canvas.drawRect(Offset.zero & size, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
||||
}
|
||||
|
||||
class LiquidGlassContainer extends StatefulWidget {
|
||||
final Widget child;
|
||||
final GlobalKey backgroundKey;
|
||||
final GlassShader shader;
|
||||
final double distortion;
|
||||
final double blur;
|
||||
final double dispersion;
|
||||
final BorderRadius? borderRadius;
|
||||
|
||||
const LiquidGlassContainer({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.backgroundKey,
|
||||
required this.shader,
|
||||
this.distortion = 1.0,
|
||||
this.blur = 5.0,
|
||||
this.dispersion = 1.0,
|
||||
this.borderRadius,
|
||||
});
|
||||
|
||||
@override
|
||||
State<LiquidGlassContainer> createState() => _LiquidGlassContainerState();
|
||||
}
|
||||
|
||||
class _LiquidGlassContainerState extends State<LiquidGlassContainer>
|
||||
with SingleTickerProviderStateMixin {
|
||||
ui.Image? _capturedImage;
|
||||
late Ticker _ticker;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ticker = createTicker((_) => _captureBackground());
|
||||
_ticker.start();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_ticker.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _captureBackground() async {
|
||||
final boundaryContext = widget.backgroundKey.currentContext;
|
||||
if (boundaryContext == null) return;
|
||||
final renderObject = boundaryContext.findRenderObject();
|
||||
if (renderObject is! RenderRepaintBoundary) return;
|
||||
|
||||
try {
|
||||
final image = await renderObject.toImage(pixelRatio: 1.0);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_capturedImage = image;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Offset offsetFromBackground = Offset.zero;
|
||||
Size bgSize = Size.zero;
|
||||
|
||||
final RenderBox? box = context.findRenderObject() as RenderBox?;
|
||||
final RenderBox? backgroundBox =
|
||||
widget.backgroundKey.currentContext?.findRenderObject() as RenderBox?;
|
||||
|
||||
if (box != null && backgroundBox != null) {
|
||||
final absolutePos = box.localToGlobal(Offset.zero);
|
||||
final backgroundPos = backgroundBox.localToGlobal(Offset.zero);
|
||||
offsetFromBackground = absolutePos - backgroundPos;
|
||||
bgSize = backgroundBox.size;
|
||||
}
|
||||
|
||||
return ClipRRect(
|
||||
borderRadius: widget.borderRadius ?? BorderRadius.zero,
|
||||
child: Stack(
|
||||
children: [
|
||||
if (_capturedImage != null &&
|
||||
widget.shader.shader != null &&
|
||||
backgroundBox != null)
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: ShaderPainter(widget.shader.shader!),
|
||||
),
|
||||
),
|
||||
Builder(builder: (ctx) {
|
||||
if (_capturedImage != null &&
|
||||
widget.shader.shader != null &&
|
||||
backgroundBox != null) {
|
||||
widget.shader.updateUniforms(
|
||||
widgetSize: (box?.size ?? Size.zero),
|
||||
textureSize: bgSize,
|
||||
widgetOffset: offsetFromBackground,
|
||||
distortion: widget.distortion,
|
||||
blur: widget.blur,
|
||||
dispersion: widget.dispersion,
|
||||
texture: _capturedImage!,
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}),
|
||||
widget.child,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,9 @@ class HomeAppBar extends StatelessWidget {
|
|||
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 10,),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: Row(
|
||||
|
|
@ -105,8 +107,8 @@ class HomeAppBar extends StatelessWidget {
|
|||
),
|
||||
Container(
|
||||
color: const Color.fromARGB(255, 224, 224, 224),
|
||||
height: 20,
|
||||
width: 1.5,
|
||||
height: 20,
|
||||
width: 1.5,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
|
|
|
|||
|
|
@ -534,7 +534,6 @@ class _HistoryDrawerContentState extends State<HistoryDrawerContent> {
|
|||
...last7DaysChats.map((chat) =>
|
||||
_buildChatItem(chat, historyState)),
|
||||
],
|
||||
// '۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'
|
||||
if (last30DaysChats.isNotEmpty) ...[
|
||||
_buildSectionHeader('۳۰ روز اخیر'),
|
||||
...last30DaysChats.map((chat) =>
|
||||
|
|
@ -616,7 +615,8 @@ class _HistoryDrawerContentState extends State<HistoryDrawerContent> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
DidvanText(
|
||||
_formatDateFromString(chat.updatedAt).toPersianDigit(),
|
||||
_formatDateFromString(chat.updatedAt)
|
||||
.toPersianDigit(),
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ class LogoAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||
void _onChanged(String value, BuildContext context) {
|
||||
final state = context.read<HomeState>();
|
||||
|
||||
// Use the improved search functionality from HomeState
|
||||
if (value.length >= 2) {
|
||||
state.onSearchChanged(value);
|
||||
} else if (value.isEmpty) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class MultitypeOverview extends StatelessWidget {
|
|||
final bool enableCaption;
|
||||
final bool enableBookmark;
|
||||
final bool showDivider;
|
||||
final bool useCardStyle; // **جدید: برای کنترل استایل کارت**
|
||||
final bool useCardStyle;
|
||||
|
||||
const MultitypeOverview({
|
||||
Key? key,
|
||||
|
|
@ -32,11 +32,10 @@ class MultitypeOverview extends StatelessWidget {
|
|||
this.enableCaption = false,
|
||||
this.enableBookmark = false,
|
||||
this.showDivider = true,
|
||||
this.useCardStyle = false, // **مقدار پیشفرض false**
|
||||
this.useCardStyle = false,
|
||||
}) : super(key: key);
|
||||
|
||||
get _targetPageArgs {
|
||||
// ...
|
||||
if (item.type == 'radar') {
|
||||
return const RadarRequestArgs(page: 0);
|
||||
}
|
||||
|
|
@ -47,7 +46,6 @@ class MultitypeOverview extends StatelessWidget {
|
|||
}
|
||||
|
||||
String? get _targetPageRouteName {
|
||||
// ...
|
||||
if (item.type == 'radar') {
|
||||
return Routes.radarDetails;
|
||||
}
|
||||
|
|
@ -64,7 +62,6 @@ class MultitypeOverview extends StatelessWidget {
|
|||
}
|
||||
|
||||
String get _icon {
|
||||
// ...
|
||||
switch (item.type) {
|
||||
case 'radar':
|
||||
return 'lib/assets/icons/Pouyesh_Ofogh_New.svg';
|
||||
|
|
@ -88,7 +85,6 @@ class MultitypeOverview extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// محتوای داخلی کارت
|
||||
final innerContent = Column(
|
||||
children: [
|
||||
Row(
|
||||
|
|
@ -249,7 +245,6 @@ class MultitypeOverview extends StatelessWidget {
|
|||
],
|
||||
],
|
||||
),
|
||||
// **اگر useCardStyle فعال نباشد، فاصله و خط جداکننده قبلی را اضافه میکنیم**
|
||||
if (!useCardStyle) ...[
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
|
|
@ -262,7 +257,6 @@ class MultitypeOverview extends StatelessWidget {
|
|||
],
|
||||
);
|
||||
|
||||
// **اعمال استایل کارت (Container با Border و Padding) به صورت شرطی**
|
||||
if (useCardStyle) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
|
|
@ -281,7 +275,7 @@ class MultitypeOverview extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
return innerContent; // در غیر این صورت، فقط محتوای داخلی را برمیگرداند.
|
||||
return innerContent;
|
||||
}
|
||||
|
||||
static Widget get placeholder => const DidvanCard(
|
||||
|
|
@ -306,4 +300,4 @@ class MultitypeOverview extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import 'package:didvan/views/widgets/bookmark_button.dart';
|
|||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/liked_button.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -197,4 +196,4 @@ class NewsOverview extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import 'package:didvan/views/widgets/bookmark_button.dart';
|
|||
import 'package:didvan/views/widgets/didvan/card.dart';
|
||||
import 'package:didvan/views/widgets/didvan/divider.dart';
|
||||
import 'package:didvan/views/widgets/didvan/text.dart';
|
||||
import 'package:didvan/views/widgets/liked_button.dart';
|
||||
import 'package:didvan/views/widgets/shimmer_placeholder.dart';
|
||||
import 'package:didvan/views/widgets/skeleton_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
@ -176,8 +175,7 @@ class RadarOverview extends StatelessWidget {
|
|||
svgIconOn: 'lib/assets/icons/bookmark_fill.svg',
|
||||
svgIconOff: 'lib/assets/icons/archive-tick.svg',
|
||||
color: const Color.fromARGB(255, 0, 126, 167),
|
||||
unbookmarkedColor:
|
||||
Theme.of(context).colorScheme.caption,
|
||||
unbookmarkedColor: Theme.of(context).colorScheme.caption,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class EmptyConnection extends StatelessWidget {
|
|||
title: 'اتصال اینترنت برقرار نیست',
|
||||
titleColor: const Color.fromARGB(255, 0, 126, 167),
|
||||
action: onRetry,
|
||||
buttonTitle: 'تلاش مجدد' ,
|
||||
buttonTitle: 'تلاش مجدد',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,11 @@ class EmptyState extends StatelessWidget {
|
|||
final isSvg = asset.toLowerCase().endsWith('.svg');
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: subtitle != null ? MainAxisAlignment.start : MainAxisAlignment.center,
|
||||
crossAxisAlignment: subtitle != null ? CrossAxisAlignment.start : CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
subtitle != null ? MainAxisAlignment.start : MainAxisAlignment.center,
|
||||
crossAxisAlignment: subtitle != null
|
||||
? CrossAxisAlignment.start
|
||||
: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// ignore_for_file: prefer_const_constructors
|
||||
|
||||
import 'package:didvan/models/enums.dart';
|
||||
import 'package:didvan/providers/core.dart';
|
||||
import 'package:didvan/views/widgets/state_handlers/empty_connection.dart';
|
||||
|
|
|
|||
24
pubspec.lock
24
pubspec.lock
|
|
@ -933,6 +933,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
liquid_glass_renderer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: liquid_glass_renderer
|
||||
sha256: "789be157494b38cdef7607bb9b63e7fe3fab76fae16149e52fa313c2d858cb3f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0-dev.4"
|
||||
list_counter:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -949,6 +957,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1005,6 +1021,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
motor:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: motor
|
||||
sha256: d6fd00496a2b934f8f54e660acc0d039d0e4bf8e667b6977b0480be97385779e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ dependencies:
|
|||
syncfusion_flutter_charts: ^31.1.19
|
||||
flutter_animate: ^4.5.2
|
||||
syncfusion_flutter_pdfviewer: ^31.1.21
|
||||
liquid_glass_renderer: ^0.2.0-dev.4
|
||||
# image_gallery_saver: ^2.0.3
|
||||
# fading_edge_scrollview: ^4.1.1
|
||||
|
||||
|
|
@ -135,6 +136,10 @@ dev_dependencies:
|
|||
|
||||
# The following section is specific to Flutter.
|
||||
flutter:
|
||||
shaders:
|
||||
- lib/shaders/liquid_glass_lens.frag
|
||||
# - lib/shaders/static_liquid.frag
|
||||
# - lib/shaders/water_ripple.frag
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
|
|
|
|||
Loading…
Reference in New Issue