Vaibhav Surve a5dd5e19fc Add Windows runner implementation for Flutter application
- Created CMakeLists.txt for Flutter and runner components.
- Implemented resource script (Runner.rc) for application metadata.
- Developed main entry point (main.cpp) for the Windows application.
- Added FlutterWindow class to manage the Flutter view within a Win32 window.
- Implemented utility functions for console management and command line argument parsing.
- Established Win32Window class for high DPI-aware window handling.
- Included application icon and manifest for proper Windows integration.
- Set up build configurations and dependencies for the Flutter application on Windows.
2025-04-23 09:55:31 +05:30

437 lines
18 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
import 'package:get/get.dart';
import 'package:marco/controller/dashboard/job_controller.dart';
import 'package:marco/helpers/theme/app_theme.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
import 'package:marco/helpers/utils/utils.dart';
import 'package:marco/helpers/widgets/my_breadcrumb.dart';
import 'package:marco/helpers/widgets/my_breadcrumb_item.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_container.dart';
import 'package:marco/helpers/widgets/my_flex.dart';
import 'package:marco/helpers/widgets/my_flex_item.dart';
import 'package:marco/helpers/widgets/my_list_extension.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/images.dart';
import 'package:marco/model/chart_model.dart';
import 'package:marco/view/layouts/layout.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class JobScreen extends StatefulWidget {
const JobScreen({super.key});
@override
State<JobScreen> createState() => _JobScreenState();
}
class _JobScreenState extends State<JobScreen> with UIMixin {
JobController controller = Get.put(JobController());
@override
Widget build(BuildContext context) {
return Layout(
child: GetBuilder(
init: controller,
tag: 'job_dashboard_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium("Job", fontSize: 18, fontWeight: 600),
MyBreadcrumb(
children: [
MyBreadcrumbItem(name: 'Dashboard'),
MyBreadcrumbItem(name: 'Job', active: true),
],
),
],
),
),
MySpacing.height(flexSpacing),
Padding(
padding: MySpacing.x(flexSpacing / 2),
child: MyFlex(
children: [
MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.briefcase, '245', 'EMPLOYEES IN SYSTEM', contentTheme.primary)),
MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.file_text, '3201', 'CANDIDATES IN DATA', contentTheme.secondary)),
MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.map_pin, '56', 'LOCATIONS SERVED', contentTheme.success)),
MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.user_plus, '312', 'RECRUITER NETWORK', contentTheme.info)),
MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.credit_card, '689', 'ACTIVE SUBSCRIPTIONS', contentTheme.purple)),
MyFlexItem(sizes: 'xxl-2 xl-4 lg-4 md-4 sm-6', child: stats(LucideIcons.cloud_upload, '82%', 'RESUME UPLOAD RATE', contentTheme.pink)),
MyFlexItem(sizes: 'lg-4', child: workingFormat()),
MyFlexItem(sizes: 'lg-8 md-6', child: listingPerformance()),
MyFlexItem(sizes: 'lg-4 md-6', child: recentCandidate()),
MyFlexItem(sizes: 'lg-4 md-6', child: mostViewedCVs()),
MyFlexItem(sizes: 'lg-4 md-6', child: recentChat()),
MyFlexItem(child: recentApplication()),
],
)),
],
);
},
),
);
}
Widget stats(IconData? icon, String title, String subTitle, Color color) {
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
child: Row(
children: [
MyContainer(
paddingAll: 12,
color: color,
child: Icon(icon, color: contentTheme.light, size: 16),
),
MySpacing.width(16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.titleMedium(title, fontWeight: 600),
MySpacing.height(4),
MyText.labelSmall(subTitle, xMuted: true, maxLines: 1, overflow: TextOverflow.ellipsis),
],
),
)
],
),
);
}
Widget workingFormat() {
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
height: 408,
child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [
MyText.bodyMedium("Working Format", height: .8, fontWeight: 600),
SfCircularChart(legend: Legend(isVisible: true, position: LegendPosition.bottom, overflowMode: LegendItemOverflowMode.wrap), series: [
DoughnutSeries<ChartSampleData, String>(
explode: true,
dataSource: <ChartSampleData>[
ChartSampleData(x: 'OnSite', y: 55, text: '55%'),
ChartSampleData(x: 'Remote', y: 31, text: '31%'),
ChartSampleData(x: 'Hybrid', y: 7.7, text: '7.7%'),
],
xValueMapper: (ChartSampleData data, _) => data.x as String,
yValueMapper: (ChartSampleData data, _) => data.y,
dataLabelMapper: (ChartSampleData data, _) => data.text,
dataLabelSettings: DataLabelSettings(isVisible: true))
])
]),
);
}
Widget listingPerformance() {
Widget isSelectTime(String title, int index) {
bool isSelect = controller.isSelectedListingPerformanceTime == index;
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 0, position: MyShadowPosition.bottom),
paddingAll: 4,
color: isSelect ? contentTheme.secondary.withValues(alpha:0.15) : null,
onTap: () => controller.onSelectListingPerformanceTimeToggle(index),
child: MyText.labelSmall(title, fontWeight: 600, color: isSelect ? contentTheme.secondary : null),
);
}
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: MyText.bodyMedium("Listing Performance", fontWeight: 600, overflow: TextOverflow.ellipsis),
),
isSelectTime("Day", 0),
MySpacing.width(12),
isSelectTime("Week", 1),
MySpacing.width(12),
isSelectTime("Month", 2),
],
),
MySpacing.height(24),
SizedBox(
height: 310,
child: SfCartesianChart(
margin: MySpacing.zero,
plotAreaBorderWidth: 0,
primaryXAxis: CategoryAxis(majorGridLines: MajorGridLines(width: 0)),
primaryYAxis: NumericAxis(
maximum: 20,
minimum: 0,
interval: 4,
axisLine: AxisLine(width: 0),
majorTickLines: MajorTickLines(size: 0),
),
series: [
ColumnSeries<ChartSampleData, String>(
width: .7,
spacing: .2,
dataSource: controller.chartData,
color: theme.colorScheme.primary,
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
yValueMapper: (ChartSampleData sales, _) => sales.y,
name: 'Views'),
ColumnSeries<ChartSampleData, String>(
dataSource: controller.chartData,
width: .7,
spacing: .2,
color: theme.colorScheme.secondary,
xValueMapper: (ChartSampleData sales, _) => sales.x as String,
yValueMapper: (ChartSampleData sales, _) => sales.secondSeriesYValue,
name: 'Application')
],
legend: Legend(isVisible: true, position: LegendPosition.bottom),
tooltipBehavior: controller.columnToolTip),
)
],
),
);
}
Widget recentCandidate() {
Widget candidatesData(String image, title, subtitle) {
return Row(
children: [
MyContainer.rounded(
paddingAll: 0,
height: 44,
width: 44,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Image.asset(image, fit: BoxFit.cover),
),
MySpacing.width(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium(title, fontWeight: 600),
MyText.bodySmall(subtitle, fontWeight: 600, xMuted: true, maxLines: 1, overflow: TextOverflow.visible)
],
),
)
],
);
}
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium("Recent Candidate", fontWeight: 600),
MySpacing.height(24),
candidatesData(Images.avatars[3], "Sophia Williams", controller.dummyTexts[0]),
MySpacing.height(24),
candidatesData(Images.avatars[4], "Ethan Johnson", controller.dummyTexts[1]),
MySpacing.height(24),
candidatesData(Images.avatars[5], "Olivia Martinez", controller.dummyTexts[2]),
MySpacing.height(24),
candidatesData(Images.avatars[6], "Liam Brown", controller.dummyTexts[3]),
MySpacing.height(24),
candidatesData(Images.avatars[7], "Ava Davis", controller.dummyTexts[4]),
MySpacing.height(24),
candidatesData(Images.avatars[8], "Mason Lee", controller.dummyTexts[5]),
],
));
}
Widget mostViewedCVs() {
Widget cv(String title) {
return Row(
children: [
MyContainer.rounded(
paddingAll: 0,
height: 44,
width: 44,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: contentTheme.primary.withAlpha(40),
child: Icon(LucideIcons.file_text, color: contentTheme.primary),
),
MySpacing.width(12),
Expanded(child: MyText.bodyMedium(title, fontWeight: 600, overflow: TextOverflow.ellipsis)),
InkWell(onTap: () {}, child: Icon(LucideIcons.download))
],
);
}
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium("Most Viewed CV's", fontWeight: 600),
MySpacing.height(24),
cv("Isabella Green"),
MySpacing.height(24),
cv("James Turner"),
MySpacing.height(24),
cv("Charlotte Scott"),
MySpacing.height(24),
cv("Oliver King"),
MySpacing.height(24),
cv("Lucas Carter"),
MySpacing.height(24),
cv("Mia Brooks"),
],
),
);
}
Widget recentChat() {
Widget chat(String image, name, message) {
return Row(
children: [
MyContainer.rounded(
paddingAll: 0,
height: 44,
width: 44,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Image.asset(image, fit: BoxFit.cover),
),
MySpacing.width(16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium(name, fontWeight: 600),
MyText.labelSmall(message, fontWeight: 600, maxLines: 1, muted: true, overflow: TextOverflow.ellipsis),
],
)),
MySpacing.width(28),
Icon(LucideIcons.message_square, size: 20)
],
);
}
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
MyText.bodyMedium("Recent Chat", fontWeight: 600),
MySpacing.height(24),
chat(Images.avatars[0], "Sophia", controller.dummyTexts[6]),
MySpacing.height(24),
chat(Images.avatars[1], "Liam", controller.dummyTexts[5]),
MySpacing.height(24),
chat(Images.avatars[2], "Charlotte", controller.dummyTexts[4]),
MySpacing.height(24),
chat(Images.avatars[3], "Oliver", controller.dummyTexts[3]),
MySpacing.height(24),
chat(Images.avatars[4], "Amelia", controller.dummyTexts[2]),
MySpacing.height(24),
chat(Images.avatars[5], "James", controller.dummyTexts[1])
]));
}
Widget recentApplication() {
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 24,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium("Recent Application", fontWeight: 600),
MySpacing.height(24),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
sortAscending: true,
columnSpacing: 88,
onSelectAll: (_) => {},
headingRowColor: WidgetStatePropertyAll(contentTheme.primary.withAlpha(40)),
dataRowMaxHeight: 60,
showBottomBorder: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
border: TableBorder.all(borderRadius: BorderRadius.circular(4), style: BorderStyle.solid, width: .4, color: Colors.grey),
columns: [
DataColumn(label: MyText.labelLarge('S.No', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Candidate', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Category', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Designation', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Mail', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Location', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Date', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Type', color: contentTheme.primary)),
DataColumn(label: MyText.labelLarge('Action', color: contentTheme.primary)),
],
rows: controller.recentApplication
.mapIndexed((index, data) => DataRow(cells: [
DataCell(MyText.bodyMedium("#${data.id}", fontWeight: 600)),
DataCell(Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MyContainer(
height: 40,
width: 40,
paddingAll: 0,
child: Image.asset(Images.avatars[index % Images.avatars.length], fit: BoxFit.cover),
),
MySpacing.width(24),
MyText.labelMedium(data.candidate, fontWeight: 600)
],
)),
DataCell(MyText.labelMedium(data.category, fontWeight: 600)),
DataCell(MyText.labelMedium(data.designation, fontWeight: 600)),
DataCell(MyText.labelMedium(data.mail, fontWeight: 600)),
DataCell(MyText.labelMedium(data.location, fontWeight: 600)),
DataCell(MyText.labelMedium("${Utils.getDateStringFromDateTime(data.date)}", fontWeight: 600)),
DataCell(MyText.labelMedium(data.type, fontWeight: 600)),
DataCell(Row(
children: [
MyContainer(
onTap: () {},
color: contentTheme.primary,
paddingAll: 8,
child: Icon(LucideIcons.download, size: 16, color: contentTheme.onPrimary),
),
MySpacing.width(12),
MyContainer(
onTap: () {},
color: contentTheme.secondary,
paddingAll: 8,
child: Icon(LucideIcons.pencil, size: 16, color: contentTheme.onPrimary),
),
],
))
]))
.toList()),
)
],
),
);
}
}