Files
apskel-owner-flutter/lib/presentation/pages/profit_sharing/widgets/profit_sharing_allocation.dart
T
efrilm 2e4c77888e
Build & Deploy iOS to TestFlight / build-and-deploy (push) Canceled after 0s
feat: profit sharing
2026-08-21 22:31:54 +07:00

196 lines
5.3 KiB
Dart

import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../components/spacer/spacer.dart';
/// Warna tetap untuk tiap pos bagi hasil supaya konsisten di semua bagian.
class ProfitSharingColor {
static const Color purchase = Color(0xFF2196F3);
static const Color owner = Color(0xFF4CAF50);
static const Color team = Color(0xFFFF9800);
}
class ProfitSharingAllocation extends StatelessWidget {
final ProfitSharingBudget budget;
const ProfitSharingAllocation({super.key, required this.budget});
@override
Widget build(BuildContext context) {
final total = budget.total;
final percentages = budget.percentages;
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: AppColor.textLight.withOpacity(0.08),
spreadRadius: 1,
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.lang.profit_sharing_allocation,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w700,
color: AppColor.textPrimary,
),
),
const SpaceHeight(16),
ProfitSharingBar(
purchase: percentages.purchase,
owner: percentages.owner,
team: percentages.team,
),
const SpaceHeight(20),
_row(
context: context,
color: ProfitSharingColor.purchase,
label: context.lang.share_purchase,
percentage: percentages.purchase,
amount: total.limitPurchase,
),
const Divider(height: 24, color: AppColor.borderLight),
_row(
context: context,
color: ProfitSharingColor.owner,
label: context.lang.share_owner,
percentage: percentages.owner,
amount: total.limitOwner,
),
const Divider(height: 24, color: AppColor.borderLight),
_row(
context: context,
color: ProfitSharingColor.team,
label: context.lang.share_team,
percentage: percentages.team,
amount: total.limitTeam,
),
],
),
);
}
Widget _row({
required BuildContext context,
required Color color,
required String label,
required double percentage,
required int amount,
}) {
return Row(
children: [
Container(
width: 10,
height: 10,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
const SpaceWidth(10),
Text(
label,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
const SpaceWidth(8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: color.withOpacity(0.12),
borderRadius: BorderRadius.circular(6),
),
child: Text(
'${percentage.toStringAsFixed(percentage % 1 == 0 ? 0 : 1)}%',
style: AppStyle.xs.copyWith(
color: color,
fontWeight: FontWeight.w700,
),
),
),
const Spacer(),
Flexible(
child: Text(
amount.currencyFormatRp,
textAlign: TextAlign.right,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w700,
),
overflow: TextOverflow.ellipsis,
),
),
],
);
}
}
/// Bar proporsi belanja / owner / tim.
class ProfitSharingBar extends StatelessWidget {
final double purchase;
final double owner;
final double team;
final double height;
const ProfitSharingBar({
super.key,
required this.purchase,
required this.owner,
required this.team,
this.height = 12,
});
@override
Widget build(BuildContext context) {
final total = purchase + owner + team;
if (total <= 0) {
return Container(
height: height,
decoration: BoxDecoration(
color: AppColor.borderLight,
borderRadius: BorderRadius.circular(height),
),
);
}
return ClipRRect(
borderRadius: BorderRadius.circular(height),
child: SizedBox(
height: height,
child: Row(
children: [
_segment(purchase, ProfitSharingColor.purchase),
_segment(owner, ProfitSharingColor.owner),
_segment(team, ProfitSharingColor.team),
].whereType<Widget>().toList(),
),
),
);
}
/// Segmen dilewati saat porsinya 0 supaya Expanded tidak dipakai dengan flex 0.
Widget? _segment(double value, Color color) {
final flex = (value * 100).round();
if (flex <= 0) return null;
return Expanded(
flex: flex,
child: Container(color: color),
);
}
}