didvan-app/lib/views/home/main/main_page.dart

427 lines
14 KiB
Dart

import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/main.dart';
import 'package:didvan/models/home_page_content/home_page_list.dart';
import 'package:didvan/models/home_page_content/swot.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/views/home/main/main_page_state.dart';
import 'package:didvan/views/home/main/widgets/banner.dart';
import 'package:didvan/views/home/main/widgets/general_item.dart';
import 'package:didvan/views/home/main/widgets/main_content.dart';
import 'package:didvan/views/home/main/widgets/podcast_item.dart';
import 'package:didvan/views/home/main/widgets/story_section.dart';
import 'package:didvan/views/widgets/didvan/slider.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/state_handlers/state_handler.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:didvan/services/network/request.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:didvan/views/home/main/widgets/swot_item_card.dart';
import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform;
import 'package:flutter/material.dart'; // برای دسترسی به TargetPlatform
// این پکیج فقط برای نسخه وب استفاده می‌شود
import 'package:universal_html/html.dart' as html;
/// تشخیص می‌دهد که آیا دستگاه یک موبایل است (چه نیتیو و چه وب)
bool isAnyMobile() {
// اگر کد روی وب در حال اجراست
if (kIsWeb) {
final userAgent = html.window.navigator.userAgent.toLowerCase();
return userAgent.contains('mobile') ||
userAgent.contains('android') ||
userAgent.contains('ios');
}
// اگر کد روی پلتفرم نیتیو در حال اجراست
// defaultTargetPlatform پلتفرم اصلی (مثلا اندروید یا iOS) را برمی‌گرداند
return defaultTargetPlatform == TargetPlatform.android ||
defaultTargetPlatform == TargetPlatform.iOS;
}
class MainPage extends StatefulWidget {
const MainPage({
super.key,
});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
@override
void initState() {
super.initState();
print("DEBUG: _MainPageState initstate called");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("DEBUG: addPostFrameCallback called");
context.read<MainPageState>().init();
});
super.initState();
}
@override
Widget build(BuildContext context) {
print("DEBUG: _MainPageState build called");
return StateHandler<MainPageState>(
onRetry: () =>
{print("DEBUG: _MainPageState onRetry called"), context.read<MainPageState>().init},
state: context.watch<MainPageState>(),
builder: (context, state) {
print("DEBUG: FutureBuilder waiting");
print("DEBUG: FutureBuilder state.stories.isNotEmpty: ${state.stories.isNotEmpty}");
print("DEBUG: FutureBuilder state.content: ${state.content!.lists}");
print("DEBUG: FutureBuilder state.content != null: ${state.content != null}");
print(
"DEBUG: FutureBuilder state.content!.lists.isNotEmpty: ${state.content!.lists.isNotEmpty}");
return ListView(
padding: const EdgeInsets.symmetric(vertical: 16),
children: [
if (state.stories.isNotEmpty) StorySection(stories: state.stories),
const SizedBox(height: 12),
const MainPageMainContent(),
Builder(builder: (context) {
final List<Widget> pageContent = [];
if (state.content != null && state.content!.lists.isNotEmpty) {
final lists = state.content!.lists;
for (int i = 0; i < lists.length; i++) {
final currentList = lists[i];
if (i == 4) {
pageContent.add(
Padding(
padding: const EdgeInsets.only(top: 32),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
bottom: 16,
top: 28,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const InfoTitle(),
GestureDetector(
onTap: () => {
Navigator.of(context)
.pushNamed(Routes.infography)
},
child: Row(
children: [
DidvanText(
"همه",
color: Theme.of(context)
.colorScheme
.primary,
),
Icon(
DidvanIcons.angle_left_light,
color: Theme.of(context)
.colorScheme
.primary,
)
],
),
)
],
),
),
const MainPageBanner(
isFirst: false,
),
],
),
),
);
}
pageContent.add(_MainPageSection(
list: currentList,
isLast: i == lists.length - 1,
));
if (currentList.type == 'startup') {
pageContent.add(_SwotSection(swotItems: state.swotItems));
}
}
}
print("DEBUG: FutureBuilder error");
return Column(children: pageContent);
}),
],
);
},
);
}
}
class _SwotSection extends StatelessWidget {
final List<SwotItem> swotItems;
const _SwotSection({required this.swotItems});
@override
Widget build(BuildContext context) {
if (swotItems.isEmpty) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.all(0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Title Row
Padding(
padding: const EdgeInsets.only(right: 20, top: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SvgPicture.asset(
"lib/assets/images/features/Saha Solid.svg",
),
const SizedBox(width: 5),
DidvanText(
"ماژول فرصت و تهدید",
style: Theme.of(context).textTheme.titleMedium,
color: Theme.of(context).colorScheme.title,
),
],
),
GestureDetector(
onTap: () {
AppInitializer.openWebLink(
navigatorKey.currentContext!,
'http://opportunity-threat.didvan.com/?accessToken=${RequestService.token}',
mode: LaunchMode.inAppWebView,
);
},
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Row(
children: [
DidvanText(
"همه",
color: Theme.of(context).colorScheme.primary,
),
Icon(
DidvanIcons.angle_left_light,
color: Theme.of(context).colorScheme.primary,
),
],
),
),
),
],
),
),
const SizedBox(height: 16),
/// Swot Items Slider
DidvanSlider(
height: 330,
itemCount: 7,
viewportFraction: isAnyMobile() ? 0.65 : 0.55,
itemBuilder: (context, index, realIndex) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 0.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SwotItemCard(item: swotItems[index]),
),
),
),
],
),
);
}
}
class InfoTitle extends StatelessWidget {
const InfoTitle({super.key});
@override
Widget build(BuildContext context) {
return Row(
children: [
const Icon(DidvanIcons.infography_solid),
const SizedBox(width: 4),
DidvanText(
"اینفوگرافی",
style: Theme.of(context).textTheme.titleMedium,
color: Theme.of(context).colorScheme.title,
),
],
);
}
}
class _MainPageSection extends StatelessWidget {
final MainPageList list;
final bool isLast;
const _MainPageSection({required this.list, required this.isLast});
void _moreHandler(BuildContext context) {
if (list.link.startsWith('http')) {
AppInitializer.openWebLink(
context,
'${list.link}?accessToken=${RequestService.token}',
mode: LaunchMode.inAppWebView,
);
return;
}
Navigator.of(context).pushNamed(list.link);
}
IconData? _generateIcon() {
switch (list.type) {
case 'news':
return DidvanIcons.foolad_solid;
case 'radar':
return DidvanIcons.scanning_solid;
case 'video':
return DidvanIcons.video_solid;
case 'podcast':
return DidvanIcons.podcast_solid;
case 'trend':
return DidvanIcons.chart_solid;
case 'technology':
return DidvanIcons.technology_solid;
case 'risk':
return DidvanIcons.exclamation_triangle_solid;
case 'startup':
return DidvanIcons.startup_solid;
case 'delphi':
return DidvanIcons.saha_solid;
default:
return null;
}
}
int _maxSublistCount() {
int max = 1;
for (var i = 0; i < list.contents.length; i++) {
if (list.contents[i].subtitles.length > max) {
max = list.contents[i].subtitles.length;
}
}
return max - 1;
}
@override
Widget build(BuildContext context) {
final icon = _generateIcon();
if (list.contents.isEmpty) {
return const SizedBox();
}
if (list.type == 'delphi') {
return Column(
children: [
_buildSectionHeader(context, icon),
_buildSectionSlider(context),
],
);
}
return Column(
children: [
_buildSectionHeader(context, icon),
_buildSectionSlider(context),
],
);
}
Padding _buildSectionHeader(BuildContext context, IconData? icon) {
return Padding(
padding: const EdgeInsets.only(
left: 16,
right: 16,
bottom: 16,
top: 28,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
if (icon != null) Icon(icon),
const SizedBox(width: 4),
DidvanText(
list.header,
style: Theme.of(context).textTheme.titleMedium,
color: Theme.of(context).colorScheme.title,
),
],
),
GestureDetector(
onTap: () => _moreHandler(context),
child: Row(
children: [
DidvanText(
list.more,
color: Theme.of(context).colorScheme.primary,
),
Icon(
DidvanIcons.angle_left_light,
color: Theme.of(context).colorScheme.primary,
)
],
),
)
],
),
);
}
Widget _buildSectionSlider(BuildContext context) {
if (list.type == 'podcast') {
return Padding(
padding: const EdgeInsets.only(top: 28),
child: Column(
children: list.contents
.map(
(e) => Padding(
padding: const EdgeInsets.only(
bottom: 12,
left: 28,
right: 28,
),
child: MainPagePodcastItem(
content: e,
),
),
)
.toList(),
),
);
}
return DidvanSlider(
height: 260 + (_maxSublistCount() - (list.type == 'radar' ? 1 : 0)) * 20,
itemCount: list.contents.length,
// -- START: کد اصلاح شده در اینجا قرار دارد --
// از isMobile() برای تنظیم اندازه آیتم‌ها بر اساس موبایل یا دسکتاپ بودن استفاده می‌کنیم
viewportFraction: isAnyMobile() ? 0.65 : 0.55,
// -- END: کد اصلاح شده --
itemBuilder: (context, index, realIndex) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: MainPageGeneralItem(
content: list.contents[index],
type: list.type,
),
),
);
}
}