diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 791d5a1..c7c4c6a 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -17,7 +17,6 @@
android:icon="@mipmap/ic_launcher"
android:label="Didvan"
android:requestLegacyExternalStorage="true"
-
android:usesCleartextTraffic="true">
-
-
-
-
-
-
-
-
-
-
-
-
@@ -110,19 +92,23 @@
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
with WidgetsBindingObserver {
+ late AppLinks _appLinks;
+ StreamSubscription? _linkSubscription;
@override
void didChangeDependencies() {
super.didChangeDependencies();
@@ -104,17 +107,46 @@ class _DidvanState extends State with WidgetsBindingObserver {
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
+ _initDeepLinks();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
+ _linkSubscription?.cancel();
if (MediaService.currentPodcast != null) {
MediaService.audioPlayer.dispose();
}
super.dispose();
}
+ Future _initDeepLinks() async {
+ _appLinks = AppLinks();
+
+ // بررسی لینک اولیه در زمان باز شدن اپلیکیشن
+ final initialUri = await _appLinks.getInitialLink();
+ if (initialUri != null) {
+ _navigateTo(initialUri);
+ }
+
+ // گوش دادن به لینکهای جدید زمانی که اپلیکیشن در حال اجراست
+ _linkSubscription = _appLinks.uriLinkStream.listen((uri) {
+ _navigateTo(uri);
+ });
+ }
+
+ /// تابع کمکی برای ناوبری
+ void _navigateTo(Uri uri) {
+ if (mounted) {
+ String path = uri.path;
+ if (uri.fragment.isNotEmpty) {
+ path = "/${uri.fragment}";
+ }
+ navigatorKey.currentState?.pushNamed(path);
+ }
+ }
+
+
bool b = true;
@override
diff --git a/lib/routes/route_generator.dart b/lib/routes/route_generator.dart
index 617a4dd..7ba82ad 100644
--- a/lib/routes/route_generator.dart
+++ b/lib/routes/route_generator.dart
@@ -1,6 +1,8 @@
// ignore_for_file: avoid_print
import 'package:didvan/models/ai/ai_chat_args.dart';
+import 'package:didvan/models/requests/news.dart';
+import 'package:didvan/models/requests/radar.dart';
import 'package:didvan/models/story_model.dart';
import 'package:didvan/views/ai/ai_chat_page.dart';
import 'package:didvan/views/ai/ai_chat_state.dart';
@@ -74,6 +76,35 @@ import '../views/notification_time/notification_time.dart';
class RouteGenerator {
static Route generateRoute(RouteSettings settings) {
+ final uri = Uri.parse(settings.name ?? '');
+ if (uri.pathSegments.isNotEmpty) {
+ if (uri.pathSegments.first == 'news' && uri.pathSegments.length > 1) {
+ final id = int.tryParse(uri.pathSegments[1]);
+ if (id != null) {
+ return _createRoute(
+ ChangeNotifierProvider(
+ create: (context) => NewsDetailsState(),
+ child: NewsDetails(
+ pageData: {'id': id, 'args': const NewsRequestArgs(page: 0)},
+ ),
+ ),
+ );
+ }
+ }
+ if (uri.pathSegments.first == 'radar' && uri.pathSegments.length > 1) {
+ final id = int.tryParse(uri.pathSegments[1]);
+ if (id != null) {
+ return _createRoute(
+ ChangeNotifierProvider(
+ create: (context) => RadarDetailsState(),
+ child: RadarDetails(
+ pageData: {'id': id, 'args': const RadarRequestArgs(page: 0)},
+ ),
+ ),
+ );
+ }
+ }
+ }
if (!kIsWeb) {
HomeWidget.saveWidgetData("cRoute", settings.name!);
}
diff --git a/lib/services/network/request.dart b/lib/services/network/request.dart
index 3443318..bad60ff 100644
--- a/lib/services/network/request.dart
+++ b/lib/services/network/request.dart
@@ -61,6 +61,7 @@ class RequestService {
_requestBody == null ? null : jsonEncode(_requestBody);
Future httpGet() async {
+ log('req is: $url', name: 'RequestService');
try {
final response = await http
.get(
diff --git a/lib/views/authentication/authentication.dart b/lib/views/authentication/authentication.dart
index 46e0afe..9f72ffb 100644
--- a/lib/views/authentication/authentication.dart
+++ b/lib/views/authentication/authentication.dart
@@ -46,9 +46,14 @@ class _AuthenticationState extends State {
body: Consumer(
builder: (context, state, child) => WillPopScope(
onWillPop: () async {
- if (state.currentPageIndex == 0) {
+ if (state.currentPageIndex == 0) {
return true;
}
+ // Check if on OTP screen and no password exists
+ if (state.currentPageIndex == 2 && !state.hasPassword) {
+ state.currentPageIndex = 0; // Go back to username screen
+ return false;
+ }
state.currentPageIndex--;
return false;
},
diff --git a/lib/views/authentication/authentication_state.dart b/lib/views/authentication/authentication_state.dart
index 00de5d3..0ad37e7 100644
--- a/lib/views/authentication/authentication_state.dart
+++ b/lib/views/authentication/authentication_state.dart
@@ -15,6 +15,7 @@ class AuthenticationState extends CoreProvier {
String password = '';
String _verificationCode = '';
bool isShowCustomDialog = true;
+ bool hasPassword = true;
set currentPageIndex(int value) {
_currentPageIndex = value;
@@ -36,6 +37,7 @@ class AuthenticationState extends CoreProvier {
appState = AppState.idle;
final bool hasPassword = service.result['hasPassword'];
+ this.hasPassword = hasPassword;
if (hasPassword) {
currentPageIndex = 1;
diff --git a/lib/views/authentication/screens/reset_password.dart b/lib/views/authentication/screens/reset_password.dart
index 134ef53..4a655c0 100644
--- a/lib/views/authentication/screens/reset_password.dart
+++ b/lib/views/authentication/screens/reset_password.dart
@@ -22,6 +22,7 @@ class _ResetPasswordState extends State {
@override
Widget build(BuildContext context) {
+ final authState = context.watch();
return Form(
key: _formKey,
child: AuthenticationLayout(
@@ -74,7 +75,7 @@ class _ResetPasswordState extends State {
}
}
},
- title: 'تغییر رمز عبور',
+ title: authState.hasPassword ? 'تغییر رمز عبور' : 'تایید رمز عبور',
),
const SizedBox(
height: 48,
diff --git a/lib/views/authentication/widgets/authentication_app_bar.dart b/lib/views/authentication/widgets/authentication_app_bar.dart
index eccc62a..fb50158 100644
--- a/lib/views/authentication/widgets/authentication_app_bar.dart
+++ b/lib/views/authentication/widgets/authentication_app_bar.dart
@@ -1,3 +1,5 @@
+// lib/views/authentication/widgets/authentication_app_bar.dart
+
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/views/authentication/authentication_state.dart';
@@ -16,14 +18,26 @@ class AuthenticationAppBar extends StatelessWidget {
return Row(
children: [
DidvanIconButton(
- icon: DidvanIcons.back_regular,
- onPressed: () {
- if (state.currentPageIndex == 0) {
- Navigator.of(context).pop();
- return;
- }
- state.currentPageIndex--;
- }),
+ icon: DidvanIcons.back_regular,
+ onPressed: () {
+ // اگر در صفحه اول باشیم، از صفحه احراز هویت خارج میشویم
+ if (state.currentPageIndex == 0) {
+ Navigator.of(context).pop();
+ return;
+ }
+
+ // ** منطق جدید برای بازگشت از صفحه OTP **
+ // اگر کاربر رمز عبور نداشته و در صفحه OTP باشد
+ if (state.currentPageIndex == 2 && !state.hasPassword) {
+ // او را به صفحه اول (ورود شماره) برمیگردانیم
+ state.currentPageIndex = 0;
+ return;
+ }
+
+ // در غیر این صورت، به صفحه قبلی برمیگردیم
+ state.currentPageIndex--;
+ },
+ ),
const SizedBox(
width: 4,
),
@@ -36,4 +50,4 @@ class AuthenticationAppBar extends StatelessWidget {
],
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/home/main/main_page_state.dart b/lib/views/home/main/main_page_state.dart
index 95e1f4a..08aefbf 100644
--- a/lib/views/home/main/main_page_state.dart
+++ b/lib/views/home/main/main_page_state.dart
@@ -43,14 +43,13 @@ class MainPageState extends CoreProvier {
try {
swotItems = await SwotService.fetchSwotItems();
} catch (e) {
- // در صورت بروز خطا، میتوانید اینجا آن را مدیریت کنید
+
}
}
Future _fetchStories() async {
try {
stories = await StoryService.getStories();
- // ignore: avoid_print
print("Fetched ${stories.length} stories.");
} catch (e) {
stories = [];
diff --git a/lib/views/home/main/widgets/story_section.dart b/lib/views/home/main/widgets/story_section.dart
index e6d84a5..9d26a91 100644
--- a/lib/views/home/main/widgets/story_section.dart
+++ b/lib/views/home/main/widgets/story_section.dart
@@ -23,14 +23,11 @@ class StorySection extends StatelessWidget {
child: _StoryCircle(
userStories: userStories,
onTap: () {
- bool allStoriesViewed = stories.every((userStories) =>
- userStories.stories.every((story) => story.isViewed.value));
-
Navigator.of(context).pushNamed(
Routes.storyViewer,
arguments: {
'stories': stories,
- 'tappedIndex': allStoriesViewed ? 0 : index,
+ 'tappedIndex': index,
},
);
},
@@ -50,9 +47,11 @@ class _StoryCircle extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ // ValueNotifier برای پیگیری وضعیت مشاهده همه استوریها
final allStoriesViewed = ValueNotifier(
userStories.stories.every((story) => story.isViewed.value));
+ // افزودن Listener به هر استوری
for (var story in userStories.stories) {
story.isViewed.addListener(() {
allStoriesViewed.value =
@@ -65,6 +64,7 @@ class _StoryCircle extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
+ // استفاده از ValueListenableBuilder برای تغییر رنگ حاشیه
ValueListenableBuilder(
valueListenable: allStoriesViewed,
builder: (context, isViewed, child) {
@@ -104,7 +104,7 @@ class _StoryCircle extends StatelessWidget {
child: ClipOval(
child: Image.asset(
userStories.user
- .profileImageUrl,
+ .profileImageUrl, // Assuming this is a local asset
fit: BoxFit.cover,
width: 50.0,
height: 50.0,
@@ -131,4 +131,4 @@ class _StoryCircle extends StatelessWidget {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/views/story_viewer/story_viewer_page.dart b/lib/views/story_viewer/story_viewer_page.dart
index 33bd89e..7fe14e5 100644
--- a/lib/views/story_viewer/story_viewer_page.dart
+++ b/lib/views/story_viewer/story_viewer_page.dart
@@ -92,14 +92,14 @@ class _UserStoryViewerState extends State
super.initState();
_animationController = AnimationController(vsync: this);
- final allStoriesInGroupViewed =
- widget.userStories.stories.every((story) => story.isViewed.value);
+ // final allStoriesInGroupViewed =
+ // widget.userStories.stories.every((story) => story.isViewed.value);
- if (allStoriesInGroupViewed) {
- for (final story in widget.userStories.stories) {
- story.isViewed.value = false;
- }
- }
+ // if (allStoriesInGroupViewed) {
+ // for (final story in widget.userStories.stories) {
+ // story.isViewed.value = false;
+ // }
+ // }
_currentStoryIndex =
widget.userStories.stories.indexWhere((story) => !story.isViewed.value);
@@ -244,12 +244,12 @@ class _UserStoryViewerState extends State
return CachedNetworkImage(
placeholder: (context, url) => const ShimmerPlaceholder(),
imageUrl: story.url,
- fit: BoxFit.cover,
+ fit: BoxFit.fill,
width: double.infinity,
height: double.infinity);
case MediaType.gif:
return Image.network(story.url,
- fit: BoxFit.cover, width: double.infinity, height: double.infinity);
+ fit: BoxFit.fill, width: double.infinity, height: double.infinity);
case MediaType.video:
if (_videoController?.value.isInitialized ?? false) {
return FittedBox(
diff --git a/lib/views/widgets/didvan/text_field.dart b/lib/views/widgets/didvan/text_field.dart
index 33f739e..b538666 100644
--- a/lib/views/widgets/didvan/text_field.dart
+++ b/lib/views/widgets/didvan/text_field.dart
@@ -4,6 +4,7 @@ import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/utils/extension.dart';
import 'package:didvan/views/widgets/animated_visibility.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -108,49 +109,51 @@ class _DidvanTextFieldState extends State {
? TextDirection.ltr
: TextDirection.rtl,
child: Padding(
- padding: const EdgeInsets.fromLTRB(8,8,0,15),
- child: TextFormField(
- inputFormatters: [
- if (!widget.acceptSpace)
- FilteringTextInputFormatter.allow(
- RegExp("[0-9a-zA-Z\u0600-\u06FF]")),
- ],
- autofocus: widget.autoFocus,
- obscureText: _hideContent,
- textAlign: widget.textAlign ?? TextAlign.start,
- keyboardType: widget.textInputType,
- textInputAction: widget.textInputAction,
- focusNode: _focusNode,
- controller: _controller,
- onFieldSubmitted: widget.onSubmitted,
- onChanged: _onChanged,
- validator: _validator,
- maxLines: _hideContent ? 1 : widget.maxLine,
- minLines: widget.minLine,
- maxLength: widget.maxLength,
- obscuringCharacter: '*',
- buildCounter: widget.showLen
- ? null
- : (context,
- {required currentLength,
- required isFocused,
- required maxLength}) =>
- const SizedBox(),
- style: (widget.isSmall
- ? Theme.of(context).textTheme.bodySmall!
- : Theme.of(context).textTheme.bodyMedium!)
- .copyWith(
- fontFamily: DesignConfig.fontFamily.padRight(3)),
- decoration: InputDecoration(
- suffixIcon: _suffixBuilder(),
- enabled: widget.enabled,
- border: InputBorder.none,
- hintText: widget.hintText,
- errorStyle: const TextStyle(height: 0.01),
- hintStyle: (widget.isSmall
+ padding: const EdgeInsets.fromLTRB(kIsWeb?8:8,kIsWeb?4:8,kIsWeb?8:0,kIsWeb?0:8),
+ child: Center(
+ child: TextFormField(
+ inputFormatters: [
+ if (!widget.acceptSpace)
+ FilteringTextInputFormatter.allow(
+ RegExp("[0-9a-zA-Z\u0600-\u06FF]")),
+ ],
+ autofocus: widget.autoFocus,
+ obscureText: _hideContent,
+ textAlign: widget.textAlign ?? TextAlign.start,
+ keyboardType: widget.textInputType,
+ textInputAction: widget.textInputAction,
+ focusNode: _focusNode,
+ controller: _controller,
+ onFieldSubmitted: widget.onSubmitted,
+ onChanged: _onChanged,
+ validator: _validator,
+ maxLines: _hideContent ? 1 : widget.maxLine,
+ minLines: widget.minLine,
+ maxLength: widget.maxLength,
+ obscuringCharacter: '*',
+ buildCounter: widget.showLen
+ ? null
+ : (context,
+ {required currentLength,
+ required isFocused,
+ required maxLength}) =>
+ const SizedBox(),
+ style: (widget.isSmall
? Theme.of(context).textTheme.bodySmall!
: Theme.of(context).textTheme.bodyMedium!)
- .copyWith(color: Theme.of(context).colorScheme.hint),
+ .copyWith(
+ fontFamily: DesignConfig.fontFamily.padRight(3)),
+ decoration: InputDecoration(
+ suffixIcon: _suffixBuilder(),
+ enabled: widget.enabled,
+ border: InputBorder.none,
+ hintText: widget.hintText,
+ errorStyle: const TextStyle(height: 0.01),
+ hintStyle: (widget.isSmall
+ ? Theme.of(context).textTheme.bodySmall!
+ : Theme.of(context).textTheme.bodyMedium!)
+ .copyWith(color: Theme.of(context).colorScheme.hint),
+ ),
),
),
),
diff --git a/pubspec.lock b/pubspec.lock
index a079ef9..7d7cc0f 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -33,6 +33,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.8.4"
+ app_links:
+ dependency: "direct main"
+ description:
+ name: app_links
+ sha256: "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.4.0"
+ app_links_linux:
+ dependency: transitive
+ description:
+ name: app_links_linux
+ sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.3"
+ app_links_platform_interface:
+ dependency: transitive
+ description:
+ name: app_links_platform_interface
+ sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
+ app_links_web:
+ dependency: transitive
+ description:
+ name: app_links_web
+ sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
args:
dependency: transitive
description:
@@ -669,6 +701,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.2"
+ gtk:
+ dependency: transitive
+ description:
+ name: gtk
+ sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
highlight:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 08b2548..3a1e4ef 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-version: 4.0.1+4380
+version: 4.0.3+5000
environment:
sdk: ">=2.19.0 <3.0.0"
@@ -113,6 +113,7 @@ dependencies:
sms_autofill: ^2.4.1
shimmer: ^3.0.0
device_info_plus: ^11.5.0
+ app_links: ^6.4.0
# image_gallery_saver: ^2.0.3
# fading_edge_scrollview: ^4.1.1
dev_dependencies: