first commit

This commit is contained in:
2026-04-29 12:53:22 +07:00
commit e6a30eddd3
394 changed files with 16408 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
import 'package:flutter/material.dart';
import 'package:frontend_eccp_mobile/app/core/constants/constants.dart';
import 'package:frontend_eccp_mobile/app/core/widgets/app_empty.dart';
import 'package:frontend_eccp_mobile/app/core/widgets/layout/app_screen.dart';
import 'package:frontend_eccp_mobile/modules/berkas/data/models/berkas_model.dart';
import 'package:frontend_eccp_mobile/modules/berkas/presentation/widgets/Berkas_card.dart';
import 'package:frontend_eccp_mobile/modules/berkas/presentation/widgets/Berkas_section_header.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
class BerkasPage extends StatefulWidget {
const BerkasPage({super.key});
@override
State<BerkasPage> createState() => _BerkasPageState();
}
class _BerkasPageState extends State<BerkasPage> {
final RefreshController _refreshController = RefreshController();
Future<void> _onRefresh() async {
await Future<void>.delayed(const Duration(seconds: 1));
_refreshController.refreshCompleted();
}
@override
void dispose() {
_refreshController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AppScreen(
title: 'Berkas',
backgroundColor: AppColors.neutral50,
scrollableBody: false,
useShadowAppBar: false,
isSliver: true,
refreshController: _refreshController,
enablePullDown: true,
onRefresh: _onRefresh,
refreshHeader: const ClassicHeader(),
body: const SizedBox.shrink(),
slivers: [
if (todayBerkas.isNotEmpty)
_buildSection(
title: 'Terbaru',
items: todayBerkas,
),
if (earlierBerkas.isNotEmpty)
_buildSection(
title: 'Lebih Lama',
items: earlierBerkas,
),
if (todayBerkas.isEmpty && earlierBerkas.isEmpty)
SliverToBoxAdapter(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.7,
child: Center(
child: empty(),
),
),
),
const SliverToBoxAdapter(child: AppSpacing.h24),
],
);
}
SliverMainAxisGroup _buildSection({
required String title,
required List<BerkasModel> items,
}) {
return SliverMainAxisGroup(
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: BerkasSectionHeaderDelegate(title: title),
),
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: AppSizes.s16,
),
sliver: SliverToBoxAdapter(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 900),
child: Column(
children: List.generate(items.length, (index) {
final item = items[index];
return Padding(
padding: AppPadding.t8,
child: BerkasCard(item: item),
);
}),
),
),
),
),
),
const SliverToBoxAdapter(child: AppSpacing.h16),
],
);
}
}
final todayBerkas = <BerkasModel>[
BerkasModel(
title: 'Rosaldo',
description: '2908388',
),
BerkasModel(
title: 'Rosaldo',
description: '2908388',
),
BerkasModel(
title: 'Rosaldo',
description: '2908388',
),
BerkasModel(
title: 'Rosaldo',
description: '2908388',
),
BerkasModel(
title: 'Rosaldo',
description: '2908388',
),
BerkasModel(
title: 'Rosaldo',
description: '2908388',
),
];
final earlierBerkas = <BerkasModel>[
BerkasModel(
title: 'Rosaldo 2',
description: '2908389',
),
BerkasModel(
title: 'Rosaldo 3',
description: '2928389',
),
BerkasModel(
title: 'Rosaldo 4',
description: '2900389',
),
BerkasModel(
title: 'Rosaldo 5',
description: '3908389',
),
BerkasModel(
title: 'Rosaldo 2',
description: '2908389',
),
BerkasModel(
title: 'Rosaldo 3',
description: '2928389',
),
BerkasModel(
title: 'Rosaldo 4',
description: '2900389',
),
BerkasModel(
title: 'Rosaldo 5',
description: '3908389',
),
BerkasModel(
title: 'Rosaldo 2',
description: '2908389',
),
BerkasModel(
title: 'Rosaldo 3',
description: '2928389',
),
BerkasModel(
title: 'Rosaldo 4',
description: '2900389',
),
BerkasModel(
title: 'Rosaldo 5',
description: '3908389',
),
];

View File

@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:frontend_eccp_mobile/app/core/constants/constants.dart';
import 'package:frontend_eccp_mobile/modules/berkas/data/models/berkas_model.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
class BerkasCard extends StatelessWidget {
const BerkasCard({
required this.item,
super.key,
});
final BerkasModel item;
@override
Widget build(BuildContext context) {
return Container(
padding: AppPadding.v16.add(AppPadding.h16),
decoration: BoxDecoration(
color: AppColors.neutralWhite,
borderRadius: AppRadius.r8,
boxShadow: AppShadows.sm,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const ShadAvatar(
'https://sample.com/avatar-1.png',
placeholder: Text('RS'),
),
AppSpacing.w12,
Expanded(child: _buildContent()),
],
),
);
}
Widget _buildContent() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title,
style: AppTextStyles.small.copyWith(
fontWeight: FontWeight.w700,
color: AppColors.neutral900,
),
),
AppSpacing.h2,
Text(
item.description,
style: AppTextStyles.xs.copyWith(
color: AppColors.neutral700,
),
),
],
);
}
}

View File

@@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:frontend_eccp_mobile/app/core/constants/constants.dart';
class BerkasSectionHeaderDelegate extends SliverPersistentHeaderDelegate {
BerkasSectionHeaderDelegate({
required this.title,
});
final String title;
@override
double get minExtent => 48;
@override
double get maxExtent => 48;
@override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
final isTablet = MediaQuery.of(context).size.width > 600;
return Container(
color: AppColors.neutral50,
alignment: Alignment.center,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 900),
child: Padding(
padding: isTablet ? EdgeInsets.zero : AppPadding.h16,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: AppTextStyles.label.copyWith(
fontWeight: FontWeight.w600,
color: AppColors.neutral700,
),
),
Text(
'Lihat Semua',
style: AppTextStyles.small.copyWith(
fontWeight: FontWeight.w600,
color: AppColors.primary900,
),
),
],
),
),
),
);
}
@override
bool shouldRebuild(
covariant SliverPersistentHeaderDelegate oldDelegate,
) {
return false;
}
}