Flutter: fitur Tambah Saham (tab Saham + form kode/perusahaan/sektor)
- Tab baru 'Saham' di NavigationBar (daftar master saham dari saat.saham) - FAB konteks: di tab Saham buka form Tambah Saham, di tab lain catat transaksi - EditSahamScreen: form tambah saham baru (kode ticker, perusahaan, sektor) - StockService: method addSaham(), updateSaham(), hapusSaham() ke Odoo
This commit is contained in:
115
flutter/lib/edit_saham_screen.dart
Normal file
115
flutter/lib/edit_saham_screen.dart
Normal file
@@ -0,0 +1,115 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../models/saham_transaksi.dart';
|
||||
import '../services/stock_service.dart';
|
||||
|
||||
class EditSahamScreen extends StatefulWidget {
|
||||
const EditSahamScreen({super.key, required this.service, this.saham});
|
||||
final StockService service;
|
||||
final Saham? saham; // null = tambah baru; ada = edit
|
||||
@override
|
||||
State<EditSahamScreen> createState() => _EditSahamScreenState();
|
||||
}
|
||||
|
||||
class _EditSahamScreenState extends State<EditSahamScreen> {
|
||||
final _kode = TextEditingController();
|
||||
final _perusahaan = TextEditingController();
|
||||
final _sektor = TextEditingController();
|
||||
bool _busy = false;
|
||||
String? _error;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final s = widget.saham;
|
||||
if (s != null) {
|
||||
_kode.text = s.kode;
|
||||
_perusahaan.text = s.perusahaan ?? '';
|
||||
_sektor.text = s.sektor ?? '';
|
||||
} else {
|
||||
_sektor.text = 'Financial';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isEdit = widget.saham != null;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(isEdit ? 'Edit Saham' : 'Tambah Saham')),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: ListView(
|
||||
children: [
|
||||
TextField(
|
||||
controller: _kode,
|
||||
enabled: !isEdit, // kode tidak boleh diubah saat edit
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Kode Saham (Ticker)',
|
||||
hintText: 'misal: BBRI, UNVR, TLKM',
|
||||
prefixIcon: Icon(Icons.business)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _perusahaan,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Nama Perusahaan / Emiten',
|
||||
prefixIcon: Icon(Icons.apartment)),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: _sektor,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Sektor', prefixIcon: Icon(Icons.category)),
|
||||
),
|
||||
if (_error != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(_error!, style: const TextStyle(color: Colors.red)),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.icon(
|
||||
onPressed: _busy ? null : _save,
|
||||
icon: _busy
|
||||
? const SizedBox(width: 18, height: 18,
|
||||
child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Icon(Icons.save),
|
||||
label: const Text('Simpan'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
setState(() {
|
||||
_busy = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
final kode = _kode.text.trim().toUpperCase();
|
||||
if (kode.isEmpty) throw Exception('Kode saham wajib diisi');
|
||||
|
||||
if (widget.saham == null) {
|
||||
await widget.service.addSaham(
|
||||
kode: kode,
|
||||
perusahaan: _perusahaan.text.trim(),
|
||||
sektor: _sektor.text.trim(),
|
||||
);
|
||||
} else {
|
||||
await widget.service.updateSaham(widget.saham!.id,
|
||||
perusahaan: _perusahaan.text.trim(),
|
||||
sektor: _sektor.text.trim(),
|
||||
);
|
||||
}
|
||||
if (!mounted) return;
|
||||
Navigator.pop(context, true);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_error = e.toString().replaceFirst('Exception: ', '');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user