feat(app): implement Product Scan review flow, dynamic batch expiry picker, custom PDFs, PO relationships, and aligned card layouts
This commit is contained in:
1 parent
9ff4a4a922
commit
577be04308
69 files changed
+5645
-1657
No files matched your search
@@ -0,0 +1,374 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../config/app_config.dart';
|
||||
import '../auth/auth_provider.dart';
|
||||
import 'scan_mode_provider.dart';
|
||||
|
||||
class CameraDrawer extends ConsumerStatefulWidget {
|
||||
const CameraDrawer({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<CameraDrawer> createState() => _CameraDrawerState();
|
||||
}
|
||||
|
||||
class _CameraDrawerState extends ConsumerState<CameraDrawer> {
|
||||
String _storeName = 'Store Name';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadStoreName();
|
||||
}
|
||||
|
||||
Future<void> _loadStoreName() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_storeName = prefs.getString('nama_toko') ?? 'Store Name';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final activeMode = ref.watch(scanModeProvider);
|
||||
|
||||
return Drawer(
|
||||
backgroundColor: Colors.white,
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
// Close Button & Profile Row
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Close Button
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.close, color: Colors.grey),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Profile Row
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.grey.shade200, width: 1),
|
||||
),
|
||||
child: ClipOval(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Image.asset(
|
||||
'assets/logo.png',
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Prima Fresh Mart',
|
||||
style: AppConfig.h3.copyWith(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
_storeName,
|
||||
style: AppConfig.bodySmall.copyWith(
|
||||
color: Colors.grey.shade600,
|
||||
fontSize: 13,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(height: 1, thickness: 1),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Mode Toggle Section (between DO and Product Scan)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Mode',
|
||||
style: AppConfig.bodySmall.copyWith(
|
||||
color: Colors.grey.shade500,
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
ref.read(scanModeProvider.notifier).state = 'DO';
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: activeMode == 'DO' ? AppConfig.primaryColor : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: activeMode == 'DO'
|
||||
? [
|
||||
BoxShadow(
|
||||
color: AppConfig.primaryColor.withOpacity(0.2),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
)
|
||||
]
|
||||
: [],
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
activeMode == 'DO' ? Icons.description : Icons.description_outlined,
|
||||
size: 16,
|
||||
color: activeMode == 'DO' ? Colors.white : Colors.grey.shade500,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'DO Scan',
|
||||
style: AppConfig.bodyMedium.copyWith(
|
||||
fontWeight: activeMode == 'DO' ? FontWeight.bold : FontWeight.normal,
|
||||
color: activeMode == 'DO' ? Colors.white : Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
ref.read(scanModeProvider.notifier).state = 'Product';
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: activeMode == 'Product' ? AppConfig.primaryColor : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: activeMode == 'Product'
|
||||
? [
|
||||
BoxShadow(
|
||||
color: AppConfig.primaryColor.withOpacity(0.2),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
)
|
||||
]
|
||||
: [],
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
activeMode == 'Product' ? Icons.inventory_2 : Icons.inventory_2_outlined,
|
||||
size: 16,
|
||||
color: activeMode == 'Product' ? Colors.white : Colors.grey.shade500,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'Product Scan',
|
||||
style: AppConfig.bodyMedium.copyWith(
|
||||
fontWeight: activeMode == 'Product' ? FontWeight.bold : FontWeight.normal,
|
||||
color: activeMode == 'Product' ? Colors.white : Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Menu Items List with Grouping Sections
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
children: [
|
||||
_buildSectionHeader('DASHBOARD'),
|
||||
_buildDrawerItem(
|
||||
icon: Icons.home_outlined,
|
||||
title: 'Home',
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
_buildDrawerItem(
|
||||
icon: Icons.history_outlined,
|
||||
title: 'History',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
context.push('/documents');
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildSectionHeader('USER PROFILE'),
|
||||
_buildDrawerItem(
|
||||
icon: Icons.person_outline,
|
||||
title: 'Profile',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_showNotImplemented('Profile');
|
||||
},
|
||||
),
|
||||
_buildDrawerItem(
|
||||
icon: Icons.notifications_none_outlined,
|
||||
title: 'Notifications',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_showNotImplemented('Notifications');
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildSectionHeader('SUPPORT & SETTINGS'),
|
||||
_buildDrawerItem(
|
||||
icon: Icons.settings_outlined,
|
||||
title: 'Settings',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_showNotImplemented('Settings');
|
||||
},
|
||||
),
|
||||
_buildDrawerItem(
|
||||
icon: Icons.help_outline,
|
||||
title: 'Help',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_showHelpDialog();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Logout at the bottom
|
||||
const Divider(height: 1),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: _buildDrawerItem(
|
||||
icon: Icons.logout_outlined,
|
||||
title: 'Logout',
|
||||
textColor: AppConfig.errorColor,
|
||||
iconColor: AppConfig.errorColor,
|
||||
onTap: () {
|
||||
ref.read(authProvider.notifier).logout();
|
||||
context.go('/login');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSectionHeader(String title) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0, top: 8.0, bottom: 8.0),
|
||||
child: Text(
|
||||
title,
|
||||
style: AppConfig.bodySmall.copyWith(
|
||||
color: Colors.grey.shade400,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 11,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDrawerItem({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required VoidCallback onTap,
|
||||
Color? textColor,
|
||||
Color? iconColor,
|
||||
}) {
|
||||
return ListTile(
|
||||
leading: Icon(icon, color: iconColor ?? Colors.black87),
|
||||
title: Text(
|
||||
title,
|
||||
style: AppConfig.bodyLarge.copyWith(
|
||||
color: textColor ?? Colors.black87,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
|
||||
void _showNotImplemented(String featureName) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('$featureName feature coming soon!'),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showHelpDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Tentang Prima Mart'),
|
||||
content: const SingleChildScrollView(
|
||||
child: Text(
|
||||
'www.primafreshmart.com merupakan sarana belanja online dari toko Prima Mart yang sudah melayani konsumen selama 10 tahun dan memiliki hampir 1200 gerai di Pulau Jawa, Bali dan Sumatera. Inovasi terbaru dari PT. Primafood International sebagai bagian dari PT. Charoen Pokphand Indonesia, Tbk.\n\nPT. Primafood International\nJl. Ancol Barat VIII no.1, Ancol, Pademangan, Jakarta Utara, DKI Jakarta.',
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Tutup'),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,9 @@ import 'package:geolocator/geolocator.dart';
|
||||
import '../../core/location/location_service.dart';
|
||||
import '../../core/utils/exif_helper.dart';
|
||||
import '../../config/app_config.dart';
|
||||
import '../auth/auth_provider.dart';
|
||||
import 'image_preview_screen.dart';
|
||||
import 'scan_mode_provider.dart';
|
||||
import 'camera_drawer.dart';
|
||||
|
||||
class CameraScreen extends ConsumerStatefulWidget {
|
||||
const CameraScreen({super.key});
|
||||
@@ -52,13 +53,8 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
});
|
||||
}
|
||||
},
|
||||
onError: (error) {
|
||||
debugPrint('Location stream error: $error');
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Background location fetch failed: $e');
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<void> _takePicture() async {
|
||||
@@ -78,6 +74,7 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
_isCapturing = true;
|
||||
});
|
||||
|
||||
// Use pre-fetched location if available, otherwise fetch quick position
|
||||
Position? position = _currentPosition;
|
||||
if (position == null) {
|
||||
try {
|
||||
@@ -92,12 +89,7 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
navigateToPreview(image.path, latitude: position?.latitude, longitude: position?.longitude);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Error picking image from camera: $e');
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Gagal membuka kamera: $e')),
|
||||
);
|
||||
}
|
||||
debugPrint('Error taking picture: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,23 +158,17 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final activeMode = ref.watch(scanModeProvider);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: AppConfig.backgroundColor,
|
||||
appBar: AppBar(
|
||||
title: const Text('Pemindai Dokumen OCR'),
|
||||
actions: [
|
||||
Builder(
|
||||
builder: (context) => IconButton(
|
||||
icon: const Icon(Icons.menu),
|
||||
onPressed: () => Scaffold.of(context).openDrawer(),
|
||||
),
|
||||
),
|
||||
],
|
||||
title: Text(activeMode == 'DO' ? 'Pemindai Dokumen OCR' : 'Pemindai Produk PFM'),
|
||||
),
|
||||
drawer: _buildDrawer(),
|
||||
drawer: const CameraDrawer(),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
padding: AppConfig.screenPadding,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
@@ -191,7 +177,7 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadiusXL),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
@@ -201,50 +187,84 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
padding: AppConfig.paddingXL,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
color: AppConfig.primaryColor.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
child: activeMode == 'DO'
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
color: AppConfig.primaryColor.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.document_scanner,
|
||||
size: 48,
|
||||
color: AppConfig.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppConfig.spaceXL),
|
||||
Text(
|
||||
'Pemindai DO',
|
||||
style: AppConfig.h3,
|
||||
),
|
||||
const SizedBox(height: AppConfig.spaceMedium),
|
||||
Text(
|
||||
'Ambil foto lembar Delivery Order (DO) Prima Fresh Mart untuk mengekstrak data PO, SO, DO, dan item barang secara otomatis.',
|
||||
style: AppConfig.bodyMedium.copyWith(color: AppConfig.textSecondary),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: AppConfig.spaceXL),
|
||||
_buildGuidelineRow(Icons.lightbulb_outline, 'Pastikan pencahayaan cukup dan terang.'),
|
||||
const SizedBox(height: AppConfig.spaceSmall),
|
||||
_buildGuidelineRow(Icons.crop_free, 'Posisikan seluruh halaman dokumen di dalam foto.'),
|
||||
const SizedBox(height: AppConfig.spaceSmall),
|
||||
_buildGuidelineRow(Icons.camera_enhance_outlined, 'Pegang HP dengan stabil agar tidak buram.'),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
color: AppConfig.primaryColor.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.inventory_2_outlined,
|
||||
size: 48,
|
||||
color: AppConfig.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppConfig.spaceXL),
|
||||
Text(
|
||||
'Pemindai Produk',
|
||||
style: AppConfig.h3,
|
||||
),
|
||||
const SizedBox(height: AppConfig.spaceMedium),
|
||||
Text(
|
||||
'Ambil foto kemasan produk Prima Fresh Mart untuk mengidentifikasi SKU, nama item, dan mendeteksi tanggal kadaluwarsa secara otomatis.',
|
||||
style: AppConfig.bodyMedium.copyWith(color: AppConfig.textSecondary),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: AppConfig.spaceXL),
|
||||
_buildGuidelineRow(Icons.lightbulb_outline, 'Pastikan kode SKU atau teks kadaluwarsa terlihat jelas.'),
|
||||
const SizedBox(height: AppConfig.spaceSmall),
|
||||
_buildGuidelineRow(Icons.center_focus_strong, 'Posisikan produk di tengah kamera.'),
|
||||
const SizedBox(height: AppConfig.spaceSmall),
|
||||
_buildGuidelineRow(Icons.flash_on, 'Gunakan pencahayaan yang cukup agar tidak buram.'),
|
||||
],
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.document_scanner,
|
||||
size: 48,
|
||||
color: AppConfig.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Pindai Dokumen DO',
|
||||
style: AppConfig.h2,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'Ambil foto lembar Delivery Order (DO) Prima Fresh Mart untuk mengekstrak data PO, SO, DO, dan item barang secara otomatis.',
|
||||
style: AppConfig.bodyMedium.copyWith(color: AppConfig.textSecondary),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
// Quick Guidelines
|
||||
_buildGuidelineRow(Icons.lightbulb_outline, 'Pastikan pencahayaan cukup dan terang.'),
|
||||
const SizedBox(height: 8),
|
||||
_buildGuidelineRow(Icons.crop_free, 'Posisikan seluruh halaman dokumen di dalam foto.'),
|
||||
const SizedBox(height: 8),
|
||||
_buildGuidelineRow(Icons.camera_enhance_outlined, 'Pegang HP dengan stabil agar tidak buram.'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const SizedBox(height: AppConfig.spaceXL),
|
||||
|
||||
// Action Buttons
|
||||
ElevatedButton.icon(
|
||||
@@ -256,7 +276,7 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
textStyle: AppConfig.bodyLarge.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: AppConfig.spaceMedium),
|
||||
OutlinedButton.icon(
|
||||
onPressed: _isCapturing ? null : _pickFromGallery,
|
||||
icon: const Icon(Icons.photo_library),
|
||||
@@ -266,12 +286,12 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
side: const BorderSide(color: AppConfig.primaryColor),
|
||||
foregroundColor: AppConfig.primaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderRadius: BorderRadius.circular(AppConfig.borderRadiusMedium),
|
||||
),
|
||||
textStyle: AppConfig.bodyLarge.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: AppConfig.spaceMedium),
|
||||
TextButton.icon(
|
||||
onPressed: _isCapturing ? null : () => context.push('/documents'),
|
||||
icon: const Icon(Icons.history_edu),
|
||||
@@ -291,7 +311,7 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
return Row(
|
||||
children: [
|
||||
Icon(icon, size: 18, color: AppConfig.secondaryColor),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(width: AppConfig.spaceSmall),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
@@ -301,76 +321,4 @@ class CameraScreenState extends ConsumerState<CameraScreen> {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDrawer() {
|
||||
return Drawer(
|
||||
backgroundColor: AppConfig.backgroundColor,
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
DrawerHeader(
|
||||
decoration: const BoxDecoration(
|
||||
color: AppConfig.primaryColor,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.store,
|
||||
size: 48,
|
||||
color: Colors.white,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'Aplikasi Pemindai OCR',
|
||||
style: AppConfig.h2.copyWith(color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info),
|
||||
title: Text('Tentang Kami', style: AppConfig.bodyLarge),
|
||||
onTap: () {
|
||||
Navigator.pop(context); // Close drawer
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Tentang Prima Mart'),
|
||||
content: SingleChildScrollView(
|
||||
child: Text(
|
||||
'www.primafreshmart.com merupakan sarana belanja online dari toko Prima Mart yang sudah melayani konsumen selama 10 tahun dan memiliki hampir 1200 gerai di Pulau Jawa, Bali dan Sumatera. Inovasi terbaru dari PT. Primafood International sebagai bagian dari PT. Charoen Pokphand Indonesia, Tbk.\n\nPT. Primafood International\nJl. Ancol Barat VIII no.1, Ancol, Pademangan, Jakarta Utara, DKI Jakarta.',
|
||||
style: AppConfig.bodyMedium,
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Tutup'),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: Text('Versi Aplikasi', style: AppConfig.bodyLarge),
|
||||
subtitle: Text('v${AppConfig.appVersion}', style: AppConfig.bodySmall),
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.logout, color: AppConfig.errorColor),
|
||||
title: Text('Keluar', style: AppConfig.bodyLarge.copyWith(color: AppConfig.errorColor)),
|
||||
onTap: () {
|
||||
ref.read(authProvider.notifier).logout();
|
||||
context.go('/login');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final scanModeProvider = StateProvider<String>((ref) => 'DO');
|
||||
Reference in new issue
Block a user