- Implemented AttendenceLogScreen to display employee attendance logs. - Created RegularizationRequestsTab to manage regularization requests. - Added TodaysAttendanceTab for viewing today's attendance. - Removed outdated dashboard chart implementation. - Updated dashboard screen to integrate new attendance overview and project progress charts. - Refactored employee detail and employee screens to use updated controllers. - Organized expense-related imports and components for better structure. - Adjusted daily progress report to use the correct controller.
97 lines
2.9 KiB
Dart
97 lines
2.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:marco/helpers/widgets/my_spacing.dart';
|
|
import 'package:marco/helpers/widgets/my_text.dart';
|
|
|
|
/// Returns a formatted color for the expense status.
|
|
Color getExpenseStatusColor(String? status, {String? colorCode}) {
|
|
if (colorCode != null && colorCode.isNotEmpty) {
|
|
try {
|
|
return Color(int.parse(colorCode.replaceFirst('#', '0xff')));
|
|
} catch (_) {}
|
|
}
|
|
switch (status) {
|
|
case 'Approval Pending':
|
|
return Colors.orange;
|
|
case 'Process Pending':
|
|
return Colors.blue;
|
|
case 'Rejected':
|
|
return Colors.red;
|
|
case 'Paid':
|
|
return Colors.green;
|
|
default:
|
|
return Colors.black;
|
|
}
|
|
}
|
|
|
|
/// Formats amount to ₹ currency string.
|
|
String formatExpenseAmount(double amount) {
|
|
return NumberFormat.currency(
|
|
locale: 'en_IN', symbol: '₹ ', decimalDigits: 2)
|
|
.format(amount);
|
|
}
|
|
|
|
/// Label/Value block as reusable widget.
|
|
Widget labelValueBlock(String label, String value) => Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
MyText.bodySmall(label, fontWeight: 600),
|
|
MySpacing.height(4),
|
|
MyText.bodySmall(value,
|
|
fontWeight: 500, softWrap: true, maxLines: null),
|
|
],
|
|
);
|
|
|
|
/// Skeleton loader for lists.
|
|
Widget buildLoadingSkeleton() => ListView.builder(
|
|
padding: const EdgeInsets.all(16),
|
|
itemCount: 5,
|
|
itemBuilder: (_, __) => Container(
|
|
margin: const EdgeInsets.only(bottom: 16),
|
|
height: 80,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[300], borderRadius: BorderRadius.circular(10)),
|
|
),
|
|
);
|
|
|
|
/// Expandable description widget.
|
|
class ExpandableDescription extends StatefulWidget {
|
|
final String description;
|
|
const ExpandableDescription({Key? key, required this.description})
|
|
: super(key: key);
|
|
|
|
@override
|
|
State<ExpandableDescription> createState() => _ExpandableDescriptionState();
|
|
}
|
|
|
|
class _ExpandableDescriptionState extends State<ExpandableDescription> {
|
|
bool isExpanded = false;
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final isLong = widget.description.length > 100;
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
MyText.bodySmall(
|
|
widget.description,
|
|
maxLines: isExpanded ? null : 2,
|
|
overflow: isExpanded ? TextOverflow.visible : TextOverflow.ellipsis,
|
|
fontWeight: 500,
|
|
),
|
|
if (isLong || !isExpanded)
|
|
InkWell(
|
|
onTap: () => setState(() => isExpanded = !isExpanded),
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(top: 4),
|
|
child: MyText.labelSmall(
|
|
isExpanded ? 'Show less' : 'Show more',
|
|
fontWeight: 600,
|
|
color: Colors.blue,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|