593 lines
20 KiB
Dart
593 lines
20 KiB
Dart
import 'package:didvan/config/theme_data.dart';
|
|
import 'package:didvan/constants/app_icons.dart';
|
|
import 'package:didvan/constants/assets.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:didvan/views/widgets/search_field.dart';
|
|
import 'package:didvan/views/home/home_state.dart';
|
|
import 'package:didvan/utils/action_sheet.dart';
|
|
import 'package:didvan/models/view/action_sheet_data.dart';
|
|
import 'package:didvan/views/widgets/didvan/checkbox.dart';
|
|
import 'package:didvan/views/widgets/text_divider.dart';
|
|
import 'package:didvan/views/widgets/item_title.dart';
|
|
import 'package:didvan/views/widgets/date_picker_button.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: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');
|
|
}
|
|
|
|
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.only(top: 0, bottom: 16),
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
SvgPicture.asset(
|
|
Assets.horizontalLogoWithText,
|
|
height: 60,
|
|
color: Theme.of(context).colorScheme.title,
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
Navigator.pushNamed(context, Routes.profile);
|
|
},
|
|
child: SizedBox(
|
|
width: 44,
|
|
height: 44,
|
|
child: Center(
|
|
child: SvgPicture.asset(
|
|
'lib/assets/icons/New_Profile.svg',
|
|
width: 30,
|
|
height: 30,
|
|
color: Theme.of(context).colorScheme.title,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
|
child: SearchField(
|
|
title: 'دیدوان',
|
|
focusNode: context.read<HomeState>().searchFieldFocusNode,
|
|
onChanged: (value) {
|
|
final homeState = context.read<HomeState>();
|
|
homeState.search = value;
|
|
if (value.length >= 3) {
|
|
homeState.searchAll(page: 1);
|
|
}
|
|
},
|
|
onFilterButtonPressed: () => _showFilterBottomSheet(context),
|
|
isFiltered: context.watch<HomeState>().filtering,
|
|
value: context.watch<HomeState>().search,
|
|
extraIconPath: 'lib/assets/icons/profile.svg',
|
|
onExtraIconPressed: () {
|
|
print('Extra icon pressed!');
|
|
},
|
|
),
|
|
),
|
|
if (state.stories.isNotEmpty) ...[
|
|
const TextDivider(text: 'دیدهبان'),
|
|
const _DidvanSignalsTitle(),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
child: StorySection(stories: state.stories),
|
|
),
|
|
],
|
|
const SizedBox(height: 12),
|
|
const TextDivider(text: 'پیشخوان استراتژیک'),
|
|
const Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
|
child: 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,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
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);
|
|
}),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Future<void> _showFilterBottomSheet(BuildContext context) async {
|
|
final state = Provider.of<HomeState>(context, listen: false);
|
|
|
|
ActionSheetUtils(context).showBottomSheet(
|
|
data: ActionSheetData(
|
|
titleIcon: DidvanIcons.filter_regular,
|
|
dismissTitle: 'حذف فیلتر',
|
|
confrimTitle: 'نمایش نتایج',
|
|
onDismissed: () => state.resetFilters(false),
|
|
onConfirmed: () => state.searchAll(page: 1),
|
|
content: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
if (state.currentPageIndex != 3) ...[
|
|
ItemTitle(
|
|
title: 'تاریخ ایجاد',
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
icon: DidvanIcons.calendar_range_regular,
|
|
),
|
|
const SizedBox(height: 8),
|
|
StatefulBuilder(
|
|
builder: (context, setState) => Row(
|
|
children: [
|
|
DatePickerButton(
|
|
initialValue: state.startDate,
|
|
emptyText: 'از تاریخ',
|
|
onPicked: (date) =>
|
|
setState(() => state.startDate = date),
|
|
lastDate: state.endDate,
|
|
),
|
|
const SizedBox(width: 8),
|
|
DatePickerButton(
|
|
initialValue: state.endDate,
|
|
emptyText: 'تا تاریخ',
|
|
onPicked: (date) => setState(() => state.endDate = date),
|
|
firstDate: state.startDate,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 28),
|
|
],
|
|
ItemTitle(
|
|
title: 'دسته بندی',
|
|
icon: DidvanIcons.category_regular,
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
),
|
|
const SizedBox(height: 12),
|
|
Wrap(
|
|
children: [
|
|
for (var i = 0; i < state.categoryFilters.length; i++)
|
|
if (state.categoryFilters[i].label != 'هوشان')
|
|
SizedBox(
|
|
width: (MediaQuery.of(context).size.width - 40) / 2,
|
|
child: DidvanCheckbox(
|
|
title: state.categoryFilters[i].label,
|
|
value: state.selectedCats
|
|
.contains(state.categoryFilters[i]),
|
|
onChanged: (value) {
|
|
if (value) {
|
|
state.selectedCats.add(state.categoryFilters[i]);
|
|
return;
|
|
}
|
|
state.selectedCats.remove(state.categoryFilters[i]);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
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",
|
|
color: Theme.of(context).colorScheme.title,
|
|
),
|
|
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: EdgeInsets.only(left: 20),
|
|
child: Row(
|
|
children: [
|
|
DidvanText(
|
|
"مشاهده همه",
|
|
color: Theme.of(context).colorScheme.primary,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
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: [
|
|
Icon(
|
|
DidvanIcons.infography_solid,
|
|
color: Theme.of(context).colorScheme.title,
|
|
),
|
|
const SizedBox(width: 4),
|
|
DidvanText(
|
|
"اینفوگرافی",
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
color: Theme.of(context).colorScheme.title,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
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,
|
|
),
|
|
child: Row(
|
|
children: [
|
|
SvgPicture.asset(
|
|
'lib/assets/icons/voice-square.svg',
|
|
color: Theme.of(context).colorScheme.title,
|
|
width: 30,
|
|
height: 30,
|
|
),
|
|
const SizedBox(width: 5),
|
|
DidvanText(
|
|
"سیگنالهای دیدوان",
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
color: Theme.of(context).colorScheme.title,
|
|
fontSize: 13,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
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,
|
|
color: Theme.of(context).colorScheme.title,
|
|
),
|
|
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(
|
|
"مشاهده همه",
|
|
color: Theme.of(context).colorScheme.primary,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
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,
|
|
viewportFraction: isAnyMobile() ? 0.65 : 0.55,
|
|
itemBuilder: (context, index, realIndex) => Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
|
child: MainPageGeneralItem(
|
|
content: list.contents[index],
|
|
type: list.type,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} |