Files
app-grosir/lib/screens/pengaturan_screen.dart
2026-07-23 22:12:32 +07:00

263 lines
8.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../state/app_state.dart';
import '../utils/colors.dart';
import 'kelola_kasir_screen.dart';
import 'printer_screen.dart';
class PengaturanScreen extends StatefulWidget {
const PengaturanScreen({super.key});
@override
State<PengaturanScreen> createState() => _PengaturanScreenState();
}
class _PengaturanScreenState extends State<PengaturanScreen> {
final TextEditingController _storeNameCtrl = TextEditingController();
final TextEditingController _currencyCtrl = TextEditingController(text: 'IDR');
final TextEditingController _whatsappCtrl = TextEditingController();
final TextEditingController _notesCtrl = TextEditingController();
bool _resellerEnabled = true;
bool _loading = true;
@override
void initState() {
super.initState();
_loadSettings();
}
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_storeNameCtrl.text = prefs.getString('store_name') ?? 'Toko Grosir';
_currencyCtrl.text = prefs.getString('currency') ?? 'IDR';
_whatsappCtrl.text = prefs.getString('store_whatsapp') ?? '';
_notesCtrl.text = prefs.getString('store_notes') ?? '';
_resellerEnabled = prefs.getBool('reseller_enabled') ?? true;
_loading = false;
});
}
Future<void> _saveSettings() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('store_name', _storeNameCtrl.text.trim());
await prefs.setString('currency', _currencyCtrl.text.trim());
await prefs.setString('store_whatsapp', _whatsappCtrl.text.trim());
await prefs.setString('store_notes', _notesCtrl.text.trim());
await prefs.setBool('reseller_enabled', _resellerEnabled);
if (!mounted) return;
final state = context.read<AppState>();
state.setResellerEnabled(_resellerEnabled);
}
@override
Widget build(BuildContext context) {
if (_loading) {
return const Center(child: CircularProgressIndicator(color: kAccent));
}
return RefreshIndicator(
onRefresh: () async {
context.read<AppState>().recordManualRefresh();
await context.read<AppState>().refresh();
},
color: kAccent,
child: ListView(
padding: const EdgeInsets.all(12),
children: [
_SettingsListTile(
icon: Icons.store_outlined,
title: 'Pengaturan Toko',
subtitle: _whatsappCtrl.text.isEmpty
? '${_storeNameCtrl.text} • ${_currencyCtrl.text}'
: '${_storeNameCtrl.text} • ${_currencyCtrl.text} • ${_whatsappCtrl.text}',
onTap: () => _showStoreSettingsDialog(context),
),
const SizedBox(height: 8),
_SettingsListTile(
icon: Icons.people_outline,
title: 'Akun Kasir',
subtitle: 'Tambah, edit, atau hapus akun kasir',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const KelolaKasirScreen(),
),
);
},
),
const SizedBox(height: 8),
_SettingsListTile(
icon: Icons.print_outlined,
title: 'Printer Bluetooth',
subtitle: 'Scan, connect, dan cetak struk',
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const PrinterScreen(),
),
);
},
),
],
),
);
}
Future<void> _showStoreSettingsDialog(BuildContext context) async {
final storeNameCtrl = TextEditingController(text: _storeNameCtrl.text);
final currencyCtrl = TextEditingController(text: _currencyCtrl.text);
final whatsappCtrl = TextEditingController(text: _whatsappCtrl.text);
final notesCtrl = TextEditingController(text: _notesCtrl.text);
bool resellerEnabled = _resellerEnabled;
final messenger = ScaffoldMessenger.of(context);
final result = await showDialog<bool>(
context: context,
builder: (ctx) => StatefulBuilder(
builder: (ctx, setModalState) => AlertDialog(
title: const Text('Pengaturan Toko'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: storeNameCtrl,
decoration: const InputDecoration(
labelText: 'Nama Toko',
prefixIcon: Icon(Icons.badge_outlined),
),
),
const SizedBox(height: 10),
TextField(
controller: currencyCtrl,
decoration: const InputDecoration(
labelText: 'Mata Uang',
prefixIcon: Icon(Icons.money_outlined),
),
),
const SizedBox(height: 10),
TextField(
controller: whatsappCtrl,
keyboardType: TextInputType.phone,
decoration: const InputDecoration(
labelText: 'No. WhatsApp',
prefixIcon: Icon(Icons.phone_outlined),
helperText: 'Contoh: 081234567890',
),
),
const SizedBox(height: 10),
TextField(
controller: notesCtrl,
maxLines: 3,
decoration: const InputDecoration(
labelText: 'Catatan Tambahan',
prefixIcon: Icon(Icons.notes_outlined),
helperText: 'Opsional, akan dicetak di struk',
),
),
const SizedBox(height: 10),
SwitchListTile(
contentPadding: EdgeInsets.zero,
title: const Text('Mode Reseller Aktif',
style: TextStyle(fontSize: 14)),
subtitle: const Text(
'Jika aktif, kasir bisa toggle harga reseller per transaksi',
style: TextStyle(fontSize: 12, color: kMuted)),
value: resellerEnabled,
onChanged: (v) => setModalState(() => resellerEnabled = v),
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx, false),
child: const Text('Batal'),
),
FilledButton.icon(
onPressed: () async {
_storeNameCtrl.text = storeNameCtrl.text.trim();
_currencyCtrl.text = currencyCtrl.text.trim();
_whatsappCtrl.text = whatsappCtrl.text.trim();
_notesCtrl.text = notesCtrl.text.trim();
_resellerEnabled = resellerEnabled;
await _saveSettings();
if (ctx.mounted) {
Navigator.pop(ctx, true);
}
},
icon: const Icon(Icons.save_outlined, size: 18),
label: const Text('Simpan'),
),
],
),
),
);
if (result == true && mounted) {
messenger.showSnackBar(
const SnackBar(
content: Text('Pengaturan tersimpan'),
backgroundColor: kSuccess,
),
);
}
}
@override
void dispose() {
_storeNameCtrl.dispose();
_currencyCtrl.dispose();
_whatsappCtrl.dispose();
_notesCtrl.dispose();
super.dispose();
}
}
class _SettingsListTile extends StatelessWidget {
final IconData icon;
final String title;
final String subtitle;
final VoidCallback onTap;
const _SettingsListTile({
required this.icon,
required this.title,
required this.subtitle,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: kAccent.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: kAccent, size: 20),
),
title: Text(
title,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w700),
),
subtitle: Text(
subtitle,
style: const TextStyle(fontSize: 12, color: kMuted),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
trailing: Icon(Icons.chevron_right_rounded, color: kMuted, size: 20),
onTap: onTap,
),
);
}
}