- 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
116 lines
3.5 KiB
Dart
116 lines
3.5 KiB
Dart
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: ', '');
|
|
});
|
|
}
|
|
}
|
|
}
|