first commit
This commit is contained in:
33
lib/Screens/Home/Model/banner_model.dart
Normal file
33
lib/Screens/Home/Model/banner_model.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
class Banner {
|
||||
Banner({
|
||||
this.id,
|
||||
this.imageUrl,
|
||||
this.status,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
Banner.fromJson(dynamic json) {
|
||||
id = json['id'];
|
||||
imageUrl = json['imageUrl'];
|
||||
status = json['status'];
|
||||
createdAt = json['created_at'];
|
||||
updatedAt = json['updated_at'];
|
||||
}
|
||||
|
||||
num? id;
|
||||
String? imageUrl;
|
||||
num? status;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = <String, dynamic>{};
|
||||
map['id'] = id;
|
||||
map['imageUrl'] = imageUrl;
|
||||
map['status'] = status;
|
||||
map['created_at'] = createdAt;
|
||||
map['updated_at'] = updatedAt;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
7
lib/Screens/Home/Provider/banner_provider.dart
Normal file
7
lib/Screens/Home/Provider/banner_provider.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../Model/banner_model.dart';
|
||||
import '../Repo/banner_repo.dart';
|
||||
|
||||
BannerRepo imageRepo = BannerRepo();
|
||||
final bannerProvider = FutureProvider<List<Banner>>((ref) => imageRepo.fetchAllIBanners());
|
||||
26
lib/Screens/Home/Repo/banner_repo.dart
Normal file
26
lib/Screens/Home/Repo/banner_repo.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../Const/api_config.dart';
|
||||
import '../../../Repository/constant_functions.dart';
|
||||
import '../../../http_client/customer_http_client_get.dart';
|
||||
import '../Model/banner_model.dart';
|
||||
|
||||
class BannerRepo {
|
||||
Future<List<Banner>> fetchAllIBanners() async {
|
||||
CustomHttpClientGet clientGet = CustomHttpClientGet(client: http.Client());
|
||||
final uri = Uri.parse('${APIConfig.url}/banners');
|
||||
|
||||
final response = await clientGet.get(url: uri);
|
||||
if (response.statusCode == 200) {
|
||||
final parsedData = jsonDecode(response.body) as Map<String, dynamic>;
|
||||
|
||||
final partyList = parsedData['data'] as List<dynamic>;
|
||||
return partyList.map((user) => Banner.fromJson(user)).toList();
|
||||
// Parse into Party objects
|
||||
} else {
|
||||
throw Exception('Failed to fetch Users');
|
||||
}
|
||||
}
|
||||
}
|
||||
64
lib/Screens/Home/components/bottom_nav.dart
Normal file
64
lib/Screens/Home/components/bottom_nav.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile_pos/Screens/Settings/settings_screen.dart';
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:nb_utils/nb_utils.dart';
|
||||
|
||||
class BottomNav extends StatefulWidget {
|
||||
const BottomNav({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<BottomNav> createState() => _BottomNavState();
|
||||
}
|
||||
|
||||
class _BottomNavState extends State<BottomNav> {
|
||||
int _selectedIndex = 0;
|
||||
|
||||
void _onItemTapped(int index) {
|
||||
setState(() {
|
||||
_selectedIndex = index;
|
||||
switch (_selectedIndex) {
|
||||
case 0:
|
||||
Navigator.pushNamed(context, '/home');
|
||||
break;
|
||||
case 1:
|
||||
Navigator.pushNamed(context, '/order');
|
||||
break;
|
||||
case 2:
|
||||
Navigator.pushNamed(context, '/featuredProduct');
|
||||
break;
|
||||
case 3:
|
||||
const SettingScreen().launch(context);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
elevation: 6.0,
|
||||
selectedItemColor: kMainColor,
|
||||
// ignore: prefer_const_literals_to_create_immutables
|
||||
items: [
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.home),
|
||||
label: 'Home',
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.flare_sharp),
|
||||
label: 'Maan',
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.backpack),
|
||||
label: 'Package',
|
||||
),
|
||||
const BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
|
||||
],
|
||||
currentIndex: _selectedIndex,
|
||||
onTap: _onItemTapped,
|
||||
);
|
||||
}
|
||||
}
|
||||
113
lib/Screens/Home/components/grid_items.dart
Normal file
113
lib/Screens/Home/components/grid_items.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
|
||||
class GridItems {
|
||||
final String title, icon, route;
|
||||
|
||||
GridItems({required this.title, required this.icon, required this.route});
|
||||
}
|
||||
|
||||
List<GridItems> getFreeIcons({required BuildContext context, bool? brunchPermission, bool? hrmPermission}) {
|
||||
List<GridItems> freeIcons = [
|
||||
GridItems(
|
||||
title: lang.S.of(context).sale,
|
||||
icon: 'assets/sales.svg',
|
||||
route: 'Sales',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).posSale,
|
||||
icon: 'images/dash_pos.svg',
|
||||
route: 'Pos Sale',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).parties,
|
||||
icon: 'assets/parties.svg',
|
||||
route: 'Parties',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).purchase,
|
||||
icon: 'assets/purchase.svg',
|
||||
route: 'Purchase',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).product,
|
||||
icon: 'assets/products.svg',
|
||||
route: 'Products',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).dueList,
|
||||
icon: 'assets/duelist.svg',
|
||||
route: 'Due List',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).stockList,
|
||||
icon: 'assets/h_stock.svg',
|
||||
route: 'Stock',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).reports,
|
||||
icon: 'assets/reports.svg',
|
||||
route: 'Reports',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).saleList,
|
||||
icon: 'assets/salelist.svg',
|
||||
route: 'Sales List',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).purchaseList,
|
||||
icon: 'assets/purchaseLisst.svg',
|
||||
route: 'Purchase List',
|
||||
),
|
||||
GridItems(
|
||||
// TODO: Shakil change this to `Profit & Loss`
|
||||
title: lang.S.of(context).profitAndLoss,
|
||||
icon: 'assets/h_lossProfit.svg',
|
||||
route: 'Loss/Profit',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).ledger,
|
||||
icon: 'assets/ledger.svg',
|
||||
route: 'ledger',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).income,
|
||||
icon: 'assets/h_income.svg',
|
||||
route: 'Income',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).expense,
|
||||
icon: 'assets/expense.svg',
|
||||
route: 'Expense',
|
||||
),
|
||||
GridItems(
|
||||
title: lang.S.of(context).vatAndTax,
|
||||
icon: 'assets/tax.svg',
|
||||
route: 'tax',
|
||||
),
|
||||
// GridItems(
|
||||
// title: 'Warehouse',
|
||||
// icon: 'assets/tax.svg',
|
||||
// route: 'warehouse',
|
||||
// ),
|
||||
GridItems(
|
||||
title: lang.S.of(context).customPrint,
|
||||
icon: 'assets/printer.svg',
|
||||
route: 'customPrint',
|
||||
),
|
||||
if (brunchPermission == true)
|
||||
GridItems(
|
||||
title: lang.S.of(context).branch,
|
||||
icon: 'assets/branch.svg',
|
||||
route: 'branch',
|
||||
),
|
||||
if (hrmPermission ?? false)
|
||||
GridItems(
|
||||
title: lang.S.of(context).hrm,
|
||||
icon: 'assets/hrm/hrm.svg',
|
||||
route: 'hrm',
|
||||
),
|
||||
];
|
||||
|
||||
return freeIcons;
|
||||
}
|
||||
132
lib/Screens/Home/home.dart
Normal file
132
lib/Screens/Home/home.dart
Normal file
@@ -0,0 +1,132 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:mobile_pos/Screens/DashBoard/dashboard.dart';
|
||||
import 'package:mobile_pos/Screens/Home/home_screen.dart';
|
||||
import 'package:mobile_pos/Screens/Report/reports.dart';
|
||||
import 'package:mobile_pos/Screens/Settings/settings_screen.dart';
|
||||
import 'package:mobile_pos/Screens/pos_sale/pos_sale.dart';
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
import 'package:mobile_pos/model/business_info_model.dart' as visible;
|
||||
|
||||
import '../../GlobalComponents/glonal_popup.dart';
|
||||
import '../../Provider/profile_provider.dart';
|
||||
import '../../service/check_actions_when_no_branch.dart';
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
const Home({super.key});
|
||||
|
||||
@override
|
||||
_HomeState createState() => _HomeState();
|
||||
}
|
||||
|
||||
class _HomeState extends State<Home> {
|
||||
int _tabIndex = 0;
|
||||
late final PageController pageController = PageController(initialPage: _tabIndex);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _handleNavigation(
|
||||
int index,
|
||||
BuildContext context,
|
||||
) {
|
||||
setState(() => _tabIndex = index);
|
||||
pageController.jumpToPage(index);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async =>
|
||||
await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(lang.S.of(context).areYouSure),
|
||||
content: Text(lang.S.of(context).doYouWantToExitTheApp),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.pop(context, false), child: Text(lang.S.of(context).no)),
|
||||
TextButton(onPressed: () => Navigator.pop(context, true), child: Text(lang.S.of(context).yes)),
|
||||
],
|
||||
),
|
||||
) ??
|
||||
false,
|
||||
child: Consumer(builder: (context, ref, __) {
|
||||
ref.watch(getExpireDateProvider(ref));
|
||||
|
||||
return GlobalPopup(
|
||||
child: Scaffold(
|
||||
body: PageView(
|
||||
controller: pageController,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
onPageChanged: (v) => setState(() => _tabIndex = v),
|
||||
children: [
|
||||
HomeScreen(),
|
||||
PosSaleScreen(),
|
||||
DashboardScreen(),
|
||||
Reports(),
|
||||
SettingScreen(),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
currentIndex: _tabIndex,
|
||||
backgroundColor: Colors.white,
|
||||
// onTap: (i) => _handleNavigation(i, context, visibility),
|
||||
onTap: (i) => _handleNavigation(
|
||||
i,
|
||||
context,
|
||||
),
|
||||
items: [
|
||||
_buildNavItem(index: 0, activeIcon: 'cHome', icon: 'home', label: lang.S.of(context).home),
|
||||
_buildNavItem(
|
||||
index: 1,
|
||||
activeIcon: 'cPos',
|
||||
icon: 'pos',
|
||||
label: lang.S.of(context).pos,
|
||||
),
|
||||
_buildNavItem(
|
||||
index: 2,
|
||||
activeIcon: 'dashbord1',
|
||||
icon: 'dashbord',
|
||||
label: lang.S.of(context).dashboard,
|
||||
),
|
||||
_buildNavItem(
|
||||
index: 3,
|
||||
activeIcon: 'cFile',
|
||||
icon: 'file',
|
||||
label: lang.S.of(context).reports,
|
||||
),
|
||||
_buildNavItem(
|
||||
index: 4,
|
||||
activeIcon: 'cSetting',
|
||||
icon: 'setting',
|
||||
label: lang.S.of(context).setting,
|
||||
),
|
||||
],
|
||||
type: BottomNavigationBarType.fixed,
|
||||
selectedItemColor: kMainColor,
|
||||
unselectedItemColor: kGreyTextColor,
|
||||
selectedLabelStyle: const TextStyle(fontSize: 14),
|
||||
unselectedLabelStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
BottomNavigationBarItem _buildNavItem(
|
||||
{required int index, required String activeIcon, required String icon, required String label}) {
|
||||
return BottomNavigationBarItem(
|
||||
icon: _tabIndex == index
|
||||
? SvgPicture.asset('assets/$activeIcon.svg', height: 28, width: 28, fit: BoxFit.scaleDown)
|
||||
: SvgPicture.asset('assets/$icon.svg',
|
||||
colorFilter: const ColorFilter.mode(kGreyTextColor, BlendMode.srcIn), height: 24, width: 24),
|
||||
label: label,
|
||||
);
|
||||
}
|
||||
}
|
||||
500
lib/Screens/Home/home_screen.dart
Normal file
500
lib/Screens/Home/home_screen.dart
Normal file
@@ -0,0 +1,500 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:mobile_pos/Const/api_config.dart';
|
||||
import 'package:mobile_pos/Repository/check_addon_providers.dart';
|
||||
import 'package:mobile_pos/Screens/DashBoard/dashboard.dart';
|
||||
import 'package:mobile_pos/Screens/Home/components/grid_items.dart';
|
||||
import 'package:mobile_pos/Screens/Profile%20Screen/profile_details.dart';
|
||||
import 'package:mobile_pos/core/theme/_app_colors.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
import 'package:nb_utils/nb_utils.dart';
|
||||
import 'package:restart_app/restart_app.dart';
|
||||
|
||||
import '../../Provider/profile_provider.dart';
|
||||
import '../../constant.dart';
|
||||
import '../../currency.dart';
|
||||
import '../../service/check_actions_when_no_branch.dart';
|
||||
import '../Customers/Provider/customer_provider.dart';
|
||||
import '../DashBoard/global_container.dart';
|
||||
import '../Home/Model/banner_model.dart' as b;
|
||||
import '../../service/check_user_role_permission_provider.dart';
|
||||
import '../branch/branch_list.dart';
|
||||
import '../branch/repo/branch_repo.dart';
|
||||
import '../subscription/package_screen.dart';
|
||||
import 'Provider/banner_provider.dart';
|
||||
|
||||
class HomeScreen extends ConsumerStatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends ConsumerState<HomeScreen> {
|
||||
PageController pageController = PageController(initialPage: 0, viewportFraction: 0.8);
|
||||
|
||||
bool _isRefreshing = false;
|
||||
|
||||
Future<void> refreshAllProviders({required WidgetRef ref}) async {
|
||||
if (_isRefreshing) return; // Prevent multiple refresh calls
|
||||
|
||||
_isRefreshing = true;
|
||||
try {
|
||||
ref.refresh(summaryInfoProvider);
|
||||
ref.refresh(bannerProvider);
|
||||
ref.refresh(businessInfoProvider);
|
||||
ref.refresh(partiesProvider);
|
||||
ref.refresh(getExpireDateProvider(ref));
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
} finally {
|
||||
_isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Consumer(builder: (_, ref, __) {
|
||||
final businessInfo = ref.watch(businessInfoProvider);
|
||||
final summaryInfo = ref.watch(summaryInfoProvider);
|
||||
final banner = ref.watch(bannerProvider);
|
||||
final permissionService = PermissionService(ref);
|
||||
return businessInfo.when(data: (details) {
|
||||
final icons = getFreeIcons(
|
||||
context: context,
|
||||
hrmPermission: (details.data?.addons?.hrmAddon == true),
|
||||
brunchPermission: (((details.data?.addons?.multiBranchAddon == true) &&
|
||||
(details.data?.enrolledPlan?.allowMultibranch == 1) &&
|
||||
(details.data?.user?.branchId == null)))
|
||||
? true
|
||||
: false);
|
||||
return Scaffold(
|
||||
backgroundColor: kBackgroundColor,
|
||||
appBar: AppBar(
|
||||
backgroundColor: kWhite,
|
||||
titleSpacing: 5,
|
||||
surfaceTintColor: kWhite,
|
||||
actions: [
|
||||
if ((details.data?.addons?.multiBranchAddon ?? false) && (details.data?.user?.activeBranch != null))
|
||||
TextButton.icon(
|
||||
label: Text(
|
||||
'${details.data?.user?.activeBranch?.name}',
|
||||
style: theme.textTheme.bodyMedium?.copyWith(color: kTitleColor),
|
||||
),
|
||||
style: ButtonStyle(
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadiusGeometry.circular(2),
|
||||
),
|
||||
),
|
||||
textStyle: WidgetStatePropertyAll(
|
||||
theme.textTheme.bodyMedium?.copyWith(color: kTitleColor),
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (details.data?.user?.branchId != null) {
|
||||
return;
|
||||
}
|
||||
bool switchBranch = await BranchListScreen.switchDialog(context: context, isLogin: false);
|
||||
if (switchBranch) {
|
||||
EasyLoading.show();
|
||||
|
||||
final switched =
|
||||
await BranchRepo().exitBranch(id: details.data?.user?.activeBranchId.toString() ?? '');
|
||||
|
||||
if (switched) {
|
||||
Restart.restartApp();
|
||||
}
|
||||
EasyLoading.dismiss();
|
||||
}
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
'assets/branch_icon.svg',
|
||||
height: 16,
|
||||
width: 16,
|
||||
),
|
||||
),
|
||||
IconButton(onPressed: () async => refreshAllProviders(ref: ref), icon: const Icon(Icons.refresh))
|
||||
],
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
const ProfileDetails().launch(context);
|
||||
},
|
||||
child: Container(
|
||||
height: 50,
|
||||
width: 50,
|
||||
decoration: details.data?.pictureUrl == null
|
||||
? BoxDecoration(
|
||||
image:
|
||||
const DecorationImage(image: AssetImage('images/no_shop_image.png'), fit: BoxFit.cover),
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
)
|
||||
: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: NetworkImage('${APIConfig.domain}${details.data?.pictureUrl}'),
|
||||
fit: BoxFit.cover),
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
details.data?.user?.role == 'staff'
|
||||
? '${details.data?.companyName ?? ''} [${details.data?.user?.name ?? ''}]'
|
||||
: details.data?.companyName ?? '',
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
// onTap: () {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (BuildContext context) {
|
||||
// return goToPackagePagePopup(
|
||||
// context: context,
|
||||
// enrolledPlan: details.enrolledPlan);
|
||||
// });
|
||||
// },
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
text: '${details.data?.enrolledPlan?.plan?.subscriptionName ?? 'No Active'} Plan',
|
||||
children: [
|
||||
// if (details.enrolledPlan?.duration != null &&
|
||||
// details.enrolledPlan!.duration! <= 7)
|
||||
// TextSpan(
|
||||
// text: ' (${getDayLeftInExpiring(
|
||||
// expireDate: details.willExpire,
|
||||
// shortMSG: false,
|
||||
// )})',
|
||||
// style: theme.textTheme.bodySmall?.copyWith(
|
||||
// fontSize: 13,
|
||||
// color: kPeraColor,
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
fontSize: 13,
|
||||
color: kPeraColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
)),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
resizeToAvoidBottomInset: true,
|
||||
body: RefreshIndicator.adaptive(
|
||||
onRefresh: () async => refreshAllProviders(ref: ref),
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (permissionService.hasPermission(Permit.dashboardRead.value)) ...{
|
||||
summaryInfo.when(data: (summary) {
|
||||
return Container(
|
||||
padding: EdgeInsets.fromLTRB(16, 16, 16, 12),
|
||||
decoration: BoxDecoration(
|
||||
color: kMainColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
lang.S.of(context).quickOver,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 18,
|
||||
color: kWhite,
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) => DashboardScreen())),
|
||||
child: Text(
|
||||
lang.S.of(context).viewAll,
|
||||
style: theme.textTheme.bodySmall?.copyWith(color: kWhite, fontSize: 16),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Flexible(
|
||||
child: GlobalContainer(
|
||||
minVerticalPadding: 0,
|
||||
minTileHeight: 0,
|
||||
titlePadding: EdgeInsets.zero,
|
||||
// isShadow: true,
|
||||
textColor: true,
|
||||
title: lang.S.of(context).sales,
|
||||
subtitle: '$currency${formatAmount(summary.data!.sales.toString())}',
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: GlobalContainer(
|
||||
minVerticalPadding: 0,
|
||||
minTileHeight: 0,
|
||||
// isShadow: true,
|
||||
textColor: true,
|
||||
alainRight: true,
|
||||
titlePadding: EdgeInsets.zero,
|
||||
title: lang.S.of(context).purchased,
|
||||
subtitle: '$currency${formatAmount(summary.data!.purchase.toString())}',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Flexible(
|
||||
child: GlobalContainer(
|
||||
minVerticalPadding: 0,
|
||||
textColor: true,
|
||||
minTileHeight: 0,
|
||||
titlePadding: EdgeInsets.zero,
|
||||
title: lang.S.of(context).income,
|
||||
subtitle: '$currency${formatAmount(summary.data!.income.toString())}',
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: GlobalContainer(
|
||||
minVerticalPadding: 0,
|
||||
minTileHeight: 0,
|
||||
textColor: true,
|
||||
alainRight: true,
|
||||
titlePadding: EdgeInsets.zero,
|
||||
title: lang.S.of(context).expense,
|
||||
subtitle: '$currency${formatAmount(summary.data!.expense.toString())}',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}, error: (e, stack) {
|
||||
return Text(e.toString());
|
||||
}, loading: () {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}),
|
||||
SizedBox(height: 16),
|
||||
},
|
||||
|
||||
GridView.count(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
childAspectRatio: 3.0,
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisSpacing: 10,
|
||||
crossAxisCount: 2,
|
||||
children: List.generate(
|
||||
icons.length,
|
||||
(index) => HomeGridCards(
|
||||
gridItems: icons[index],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
///________________Banner_______________________________________
|
||||
banner.when(data: (imageData) {
|
||||
List<b.Banner> images = [];
|
||||
if (imageData.isNotEmpty) {
|
||||
images.addAll(imageData.where(
|
||||
(element) => element.status == 1,
|
||||
));
|
||||
}
|
||||
|
||||
if (images.isNotEmpty) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
lang.S.of(context).whatNew,
|
||||
textAlign: TextAlign.start,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Container(
|
||||
height: 150,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
),
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: images.length,
|
||||
itemBuilder: (_, index) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
const PackageScreen().launch(context);
|
||||
},
|
||||
child: Padding(
|
||||
padding: EdgeInsetsDirectional.only(end: 10), // Spacing between items
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: Image.network(
|
||||
"${APIConfig.domain}${images[index].imageUrl}",
|
||||
width: MediaQuery.of(context).size.width * 0.7, // 80% width
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Container(
|
||||
height: 150,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
image: AssetImage('images/banner1.png'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}, error: (e, stack) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: Center(
|
||||
child: Text(
|
||||
lang.S.of(context).noDataFound,
|
||||
style: theme.textTheme.titleMedium,
|
||||
//'No Data Found'
|
||||
),
|
||||
),
|
||||
);
|
||||
}, loading: () {
|
||||
return const CircularProgressIndicator();
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}, error: (e, stack) {
|
||||
return Center(child: Text(e.toString()));
|
||||
}, loading: () {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class HomeGridCards extends StatefulWidget {
|
||||
const HomeGridCards({
|
||||
super.key,
|
||||
required this.gridItems,
|
||||
// this.visibility,
|
||||
});
|
||||
|
||||
final GridItems gridItems;
|
||||
// final business.Visibility? visibility;
|
||||
|
||||
@override
|
||||
State<HomeGridCards> createState() => _HomeGridCardsState();
|
||||
}
|
||||
|
||||
class _HomeGridCardsState extends State<HomeGridCards> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer(builder: (context, ref, __) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
bool result = await checkActionWhenNoBranch(context: context, actionName: widget.gridItems.title, ref: ref);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pushNamed('/${widget.gridItems.route}');
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8), color: kWhite, boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xff171717).withOpacity(0.07),
|
||||
offset: const Offset(0, 3),
|
||||
blurRadius: 50,
|
||||
spreadRadius: -4)
|
||||
]),
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
widget.gridItems.icon.toString(),
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.gridItems.title.toString(),
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(color: DAppColors.kNeutral700),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String getSubscriptionExpiring({required String? expireDate, required bool shortMSG}) {
|
||||
if (expireDate == null) {
|
||||
return shortMSG ? 'N/A' : lang.S.current.subscribeNow;
|
||||
}
|
||||
DateTime expiringDay = DateTime.parse(expireDate).add(const Duration(days: 1));
|
||||
if (expiringDay.isBefore(DateTime.now())) {
|
||||
return lang.S.current.expired;
|
||||
}
|
||||
if (expiringDay.difference(DateTime.now()).inDays < 1) {
|
||||
return shortMSG
|
||||
? '${expiringDay.difference(DateTime.now()).inHours}\n${lang.S.current.hoursLeft}'
|
||||
: '${expiringDay.difference(DateTime.now()).inHours} ${lang.S.current.hoursLeft}';
|
||||
} else {
|
||||
return shortMSG
|
||||
? '${expiringDay.difference(DateTime.now()).inDays}\n${lang.S.current.daysLeft}'
|
||||
: '${expiringDay.difference(DateTime.now()).inDays} ${lang.S.current.daysLeft}';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user