import 'package:fikoyt_akcali_v1/apps/finans/core/models/finans.model.dart'; import 'package:fikoyt_akcali_v1/apps/finans/core/services/barkod_servisi.dart'; import 'package:fikoyt_akcali_v1/apps/finans/core/services/finans.servis.dart'; import 'package:fikoyt_akcali_v1/apps/finans/core/tema/akcali_tema.dart'; import 'package:fikoyt_ui/fikoyt_ui.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; class BarkodOkuyucuSayfasi extends StatefulWidget { const BarkodOkuyucuSayfasi({super.key}); @override State createState() => _BarkodOkuyucuSayfasiState(); } class _BarkodOkuyucuSayfasiState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final _barkodController = TextEditingController(); final _barkodFocus = FocusNode(); BarkodServisi? _barkodServisi; FinansServis? _finansServis; final RxBool _taraniyor = false.obs; final Rx _bulunanUrun = Rx(null); final RxBool _urunBulundu = false.obs; final _sonBarkod = ''.obs; // Market Modu final RxList<_MarketKalemi> _marketListesi = <_MarketKalemi>[].obs; final RxDouble _tahminiToplam = 0.0.obs; final RxDouble _gercekToplam = 0.0.obs; final _aktifListeAdi = 'Alisveris'.obs; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); _servisleriBaslat(); } void _servisleriBaslat() { try { _barkodServisi = Get.find(); } catch (_) { _barkodServisi = Get.put(BarkodServisi()); } _finansServis = FikoYTCoreService.servisler.getServis(); } @override void dispose() { _tabController.dispose(); _barkodController.dispose(); _barkodFocus.dispose(); super.dispose(); } Future _barkodTara() async { final barkod = _barkodController.text.trim(); if (barkod.isEmpty) { Get.snackbar('Uyari', 'Barkod numarasi girin veya kamera ile tarayin', backgroundColor: AkcaliTema.uyari.withAlpha(30), colorText: AkcaliTema.uyari); return; } _taraniyor.value = true; _sonBarkod.value = barkod; try { final urun = await _barkodServisi?.barkodIleUrunBul(barkod); _bulunanUrun.value = urun; _urunBulundu.value = urun != null; if (urun == null) { _yeniUrunDialoguGoster(barkod); } } catch (e) { _urunBulundu.value = false; _bulunanUrun.value = null; } finally { _taraniyor.value = false; } } Future _kameraIleTara({bool marketModu = false}) async { final sonuc = await Navigator.of(context).push( MaterialPageRoute( builder: (_) => _KameraTarayici(), ), ); if (sonuc != null && sonuc.isNotEmpty && mounted) { _barkodController.text = sonuc; if (marketModu) { _barkodTaraMarket(); } else { _barkodTara(); } } } Future _barkodTaraMarket() async { final barkod = _barkodController.text.trim(); if (barkod.isEmpty) { Get.snackbar('Uyari', 'Barkod numarasi girin veya kamera ile tarayin', backgroundColor: AkcaliTema.uyari.withAlpha(30), colorText: AkcaliTema.uyari); return; } _taraniyor.value = true; try { final urun = await _barkodServisi?.barkodIleUrunBul(barkod); if (urun != null) { final mevcut = _marketListesi.indexWhere( (k) => k.urun?.barkod == barkod || k.urun?.id == urun.id); if (mevcut >= 0) { _marketListesi[mevcut].adet++; _marketListesi.refresh(); } else { _marketListesi.add(_MarketKalemi(urun: urun, adet: 1)); } _toplamHesapla(); } else { _yeniUrunDialoguGoster(barkod, marketModu: true); } _barkodController.clear(); } catch (_) { } finally { _taraniyor.value = false; } } void _toplamHesapla() { double tahmini = 0, gercek = 0; for (final k in _marketListesi) { tahmini += (k.urun?.sonFiyat ?? 0) * k.adet; if (k.satinAlindi) gercek += k.gercekFiyat * k.adet; } _tahminiToplam.value = tahmini; _gercekToplam.value = gercek; } void _yeniUrunDialoguGoster(String barkod, {bool marketModu = false}) { final isimCtrl = TextEditingController(); final markaCtrl = TextEditingController(); final fiyatCtrl = TextEditingController(); final kdvOrani = RxInt(10); final emoji = RxString(''); final isDark = Theme.of(context).brightness == Brightness.dark; showDialog( context: context, builder: (_) => AlertDialog( backgroundColor: isDark ? AkcaliTema.koyuKart : Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), title: Row(children: [ Icon(Icons.add_circle_outline_rounded, color: AkcaliTema.birincil, size: 28), const SizedBox(width: 8), Text('Yeni Urun', style: AkcaliTema.altBaslikStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin)), ]), content: SingleChildScrollView( child: Column(mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: AkcaliTema.birincil.withAlpha(20), borderRadius: BorderRadius.circular(12), ), child: Row(children: [ Icon(Icons.qr_code_2_rounded, color: AkcaliTema.birincil, size: 18), const SizedBox(width: 8), Expanded( child: Text(barkod, style: AkcaliTema.govdeStil.copyWith( color: AkcaliTema.birincil, fontWeight: FontWeight.w600)), ), ]), ), const SizedBox(height: 16), _dialogInput(isimCtrl, 'Urun Adi', Icons.shopping_bag_rounded, isDark), const SizedBox(height: 12), _dialogInput( markaCtrl, 'Marka', Icons.business_rounded, isDark), const SizedBox(height: 12), _dialogInput(fiyatCtrl, 'Fiyat (TL)', Icons.attach_money_rounded, isDark, klavye: TextInputType.numberWithOptions(decimal: true)), const SizedBox(height: 12), Obx(() => Row(children: [ Text('KDV: ', style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), for (final oran in [1, 10, 20]) Padding( padding: const EdgeInsets.only(right: 6), child: ChoiceChip( label: Text('%$oran'), selected: kdvOrani.value == oran, selectedColor: AkcaliTema.birincil.withAlpha(40), labelStyle: TextStyle( color: kdvOrani.value == oran ? AkcaliTema.birincil : (isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil), fontWeight: FontWeight.w600, fontSize: 12, ), onSelected: (_) => kdvOrani.value = oran, ), ), ])), const SizedBox(height: 12), _dialogInput( TextEditingController(text: emoji.value), 'Emoji (opsiyonel)', Icons.emoji_emotions_rounded, isDark, onChanged: (v) => emoji.value = v), ]), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text('Iptal', style: TextStyle( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ), ElevatedButton( onPressed: () async { if (isimCtrl.text.trim().isEmpty) return; final urun = await _barkodServisi?.barkodTanimla( barkod, isimCtrl.text.trim(), fiyat: double.tryParse(fiyatCtrl.text), marka: markaCtrl.text.trim().isEmpty ? null : markaCtrl.text.trim(), kdvOrani: kdvOrani.value, ); if (mounted) Navigator.of(context).pop(); if (urun != null) { _bulunanUrun.value = urun; _urunBulundu.value = true; if (marketModu) { _marketListesi.add(_MarketKalemi(urun: urun, adet: 1)); _toplamHesapla(); _barkodController.clear(); } } }, style: ElevatedButton.styleFrom( backgroundColor: AkcaliTema.birincil, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), ), child: const Text('Kaydet'), ), ], ) ); } Widget _dialogInput(TextEditingController ctrl, String hint, IconData icon, bool isDark, {TextInputType? klavye, ValueChanged? onChanged}) { return TextField( controller: ctrl, keyboardType: klavye, onChanged: onChanged, style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin), decoration: InputDecoration( hintText: hint, hintStyle: TextStyle( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil), prefixIcon: Icon(icon, color: AkcaliTema.birincil, size: 20), filled: true, fillColor: isDark ? AkcaliTema.koyuKartVurgulu : AkcaliTema.acikArkaplan, border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide.none), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), ), ); } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: isDark ? AkcaliTema.koyuArkaplan : AkcaliTema.acikArkaplan, body: Column(children: [ _baslik(isDark), _tabBar(isDark), Expanded( child: TabBarView( controller: _tabController, children: [ _taraModuSayfasi(isDark), _marketModuSayfasi(isDark), ], ), ), ]), ); } Widget _baslik(bool isDark) { return Container( padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 8, left: 16, right: 16, bottom: 8, ), decoration: BoxDecoration( gradient: AkcaliTema.birincilGradyan, borderRadius: const BorderRadius.vertical(bottom: Radius.circular(24)), boxShadow: AkcaliTema.neonGolge(AkcaliTema.birincil, yogunluk: 0.2), ), child: Row(children: [ IconButton( icon: const Icon(Icons.arrow_back_rounded, color: Colors.white), onPressed: () => Navigator.pop(context), ), const SizedBox(width: 4), Icon(Icons.qr_code_scanner_rounded, color: Colors.white, size: 28), const SizedBox(width: 10), Expanded( child: Text('Barkod Okuyucu', style: AkcaliTema.altBaslikStil.copyWith(color: Colors.white)), ), ]), ); } Widget _tabBar(bool isDark) { return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.birincil, opaklik: isDark ? 0.06 : 0.08, ), child: TabBar( controller: _tabController, indicator: BoxDecoration( borderRadius: BorderRadius.circular(16), color: AkcaliTema.birincil, boxShadow: AkcaliTema.neonGolge(AkcaliTema.birincil, yogunluk: 0.3), ), indicatorSize: TabBarIndicatorSize.tab, dividerHeight: 0, labelColor: Colors.white, unselectedLabelColor: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil, labelStyle: AkcaliTema.govdeStil.copyWith(fontWeight: FontWeight.w600), tabs: const [ Tab( icon: Icon(Icons.qr_code_2_rounded, size: 20), text: 'Barkod Tara', ), Tab( icon: Icon(Icons.shopping_cart_rounded, size: 20), text: 'Market Modu', ), ], ), ); } // ============================================================ // MODE 1: BARKOD TARA // ============================================================ Widget _taraModuSayfasi(bool isDark) { return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column(children: [ _tarayiciKart(isDark, onTara: _barkodTara), const SizedBox(height: 16), Obx(() { if (_taraniyor.value) { return _yuklemeKarti(isDark); } if (_urunBulundu.value && _bulunanUrun.value != null) { return _urunSonucKarti(isDark, _bulunanUrun.value!); } if (_sonBarkod.value.isNotEmpty && !_urunBulundu.value) { return _bulunamadiKarti(isDark); } return _bosIpucu(isDark); }), const SizedBox(height: 24), ]), ); } Widget _tarayiciKart(bool isDark, {required VoidCallback onTara, bool marketModu = false}) { return Container( padding: const EdgeInsets.all(20), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.birincil, opaklik: isDark ? 0.06 : 0.05, ), child: Column(children: [ AnimatedContainer( duration: AkcaliTema.normalAnim, padding: const EdgeInsets.symmetric(horizontal: 4), child: TextField( controller: _barkodController, focusNode: _barkodFocus, textAlign: TextAlign.center, style: AkcaliTema.tutarOrta.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin, letterSpacing: 3, fontFamily: 'monospace', ), keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.digitsOnly], onSubmitted: (_) => onTara(), decoration: InputDecoration( hintText: 'Barkod numarasi girin...', hintStyle: TextStyle( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil, fontSize: 16, letterSpacing: 1, ), prefixIcon: Icon(Icons.qr_code_2_rounded, color: AkcaliTema.birincil, size: 24), suffixIcon: IconButton( icon: Icon(Icons.content_paste_rounded, color: AkcaliTema.birincilAcik), onPressed: () async { final data = await Clipboard.getData(Clipboard.kTextPlain); if (data?.text != null) { _barkodController.text = data!.text!; } }, ), filled: true, fillColor: isDark ? AkcaliTema.koyuKartVurgulu : Colors.white, border: OutlineInputBorder( borderRadius: BorderRadius.circular(16), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(16), borderSide: BorderSide(color: AkcaliTema.birincil, width: 1.5), ), contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18), ), ), ), const SizedBox(height: 16), Row(children: [ Expanded( child: SizedBox( height: 52, child: FilledButton.icon( onPressed: () => _kameraIleTara(marketModu: marketModu), icon: const Icon(Icons.camera_alt_rounded, size: 22), label: Text('Kamera', style: AkcaliTema.altBaslikStil.copyWith(color: Colors.white, fontSize: 14)), style: FilledButton.styleFrom( backgroundColor: AkcaliTema.ikincil, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16)), ), ), ), ), const SizedBox(width: 10), Expanded( child: SizedBox( height: 52, child: FilledButton.icon( onPressed: onTara, icon: const Icon(Icons.search_rounded, size: 22), label: Text('Tara', style: AkcaliTema.altBaslikStil.copyWith(color: Colors.white, fontSize: 14)), style: FilledButton.styleFrom( backgroundColor: AkcaliTema.birincil, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16)), ), ), ), ), ]), ]), ); } Widget _yuklemeKarti(bool isDark) { return Container( padding: const EdgeInsets.all(32), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.birincil, opaklik: isDark ? 0.06 : 0.05, ), child: Column(children: [ SizedBox( width: 40, height: 40, child: CircularProgressIndicator( strokeWidth: 3, color: AkcaliTema.birincil, ), ), const SizedBox(height: 12), Text('Urun araniyor...', style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ]), ); } Widget _urunSonucKarti(bool isDark, Urun urun) { final degisim = urun.fiyatDegisimYuzdesi; final degisimRenk = degisim > 0 ? AkcaliTema.gider : (degisim < 0 ? AkcaliTema.gelir : AkcaliTema.bilgi); return Container( padding: const EdgeInsets.all(20), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.birincil, opaklik: isDark ? 0.06 : 0.05, ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ Container( width: 48, height: 48, decoration: BoxDecoration( color: urun.rengi.withAlpha(30), borderRadius: BorderRadius.circular(14), ), alignment: Alignment.center, child: Text( urun.simge ?? '', style: const TextStyle(fontSize: 24), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(urun.ismi ?? 'Urun', style: AkcaliTema.altBaslikStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin)), if (urun.marka != null) Text(urun.marka!, style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ]), ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: degisimRenk.withAlpha(25), borderRadius: BorderRadius.circular(10), ), child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon( degisim > 0 ? Icons.trending_up_rounded : (degisim < 0 ? Icons.trending_down_rounded : Icons.trending_flat_rounded), color: degisimRenk, size: 16, ), const SizedBox(width: 4), Text('${degisim.toStringAsFixed(1)}%', style: AkcaliTema.etiketStil .copyWith(color: degisimRenk, fontWeight: FontWeight.w700)), ]), ), ]), const SizedBox(height: 16), Row(children: [ _fiyatBadge(isDark, 'Son Fiyat', urun.sonFiyat, AkcaliTema.birincil), const SizedBox(width: 8), _fiyatBadge(isDark, 'En Dusuk', urun.enDusukFiyat, AkcaliTema.gelir), const SizedBox(width: 8), _fiyatBadge( isDark, 'En Yuksek', urun.enYuksekFiyat, AkcaliTema.gider), ]), const SizedBox(height: 12), Row(children: [ Expanded( child: Text( '${urun.toplamGirisSayisi} kayit | KDV %${urun.kdvOrani}', style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ), ]), const SizedBox(height: 16), Row(children: [ Expanded( child: OutlinedButton.icon( onPressed: () async { try { final listeler = _barkodServisi?.aktifListeler; if (listeler != null && listeler.isNotEmpty) { await _barkodServisi?.alisverisKalemiEkle( listeler.first.id, urun: urun, adet: 1, ); Get.snackbar('Basarili', '${urun.ismi} listeye eklendi', backgroundColor: AkcaliTema.gelir.withAlpha(30), colorText: AkcaliTema.gelir); } else { Get.snackbar('Uyari', 'Aktif alisveris listesi bulunamadi', backgroundColor: AkcaliTema.uyari.withAlpha(30), colorText: AkcaliTema.uyari); } } catch (_) {} }, icon: Icon(Icons.list_alt_rounded, color: AkcaliTema.birincil, size: 18), label: Text('Listeye Ekle', style: TextStyle(color: AkcaliTema.birincil, fontSize: 13)), style: OutlinedButton.styleFrom( side: BorderSide(color: AkcaliTema.birincil.withAlpha(80)), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), ), ), ), const SizedBox(width: 10), Expanded( child: FilledButton.icon( onPressed: () { // TODO: Harcama ekleme sayfasina yonlendir Get.snackbar('Bilgi', 'Harcama ekle - yakinda', backgroundColor: AkcaliTema.bilgi.withAlpha(30), colorText: AkcaliTema.bilgi); }, icon: const Icon(Icons.receipt_long_rounded, size: 18), label: const Text('Harcama Ekle', style: TextStyle(fontSize: 13)), style: FilledButton.styleFrom( backgroundColor: AkcaliTema.gider, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), ), ), ), ]), ]), ); } Widget _fiyatBadge(bool isDark, String etiket, double fiyat, Color renk) { return Expanded( child: Container( padding: const EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration( color: renk.withAlpha(15), borderRadius: BorderRadius.circular(12), ), child: Column(children: [ Text(etiket, style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil, fontSize: 10)), const SizedBox(height: 2), Text(AkcaliTema.tutarFormat(fiyat), style: AkcaliTema.tutarKucuk.copyWith(color: renk)), ]), ), ); } Widget _bulunamadiKarti(bool isDark) { return Container( padding: const EdgeInsets.all(24), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.uyari, opaklik: isDark ? 0.06 : 0.05, ), child: Column(children: [ Icon(Icons.search_off_rounded, color: AkcaliTema.uyari, size: 48), const SizedBox(height: 12), Text('Urun bulunamadi', style: AkcaliTema.altBaslikStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin)), const SizedBox(height: 4), Text('Yeni urun olarak tanimlamak ister misiniz?', style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), const SizedBox(height: 16), FilledButton.icon( onPressed: () => _yeniUrunDialoguGoster(_sonBarkod.value), icon: const Icon(Icons.add_rounded, size: 20), label: const Text('Yeni Urun Tanimla'), style: FilledButton.styleFrom( backgroundColor: AkcaliTema.birincil, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14)), ), ), ]), ); } Widget _bosIpucu(bool isDark) { return Container( padding: const EdgeInsets.all(32), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.birincil, opaklik: isDark ? 0.04 : 0.03, ), child: Column(children: [ Icon(Icons.qr_code_scanner_rounded, color: (isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil) .withAlpha(80), size: 64), const SizedBox(height: 12), Text('Barkod numarasi girerek urun arayabilirsiniz', textAlign: TextAlign.center, style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ]), ); } // ============================================================ // MODE 2: MARKET MODU // ============================================================ Widget _marketModuSayfasi(bool isDark) { return Column(children: [ _marketBaslik(isDark), Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: _tarayiciKart(isDark, onTara: _barkodTaraMarket, marketModu: true), ), Expanded( child: Obx(() { if (_marketListesi.isEmpty) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.shopping_cart_outlined, color: (isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil) .withAlpha(80), size: 64), const SizedBox(height: 12), Text('Urun tarayarak listeye ekleyin', style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ]), ); } return ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: _marketListesi.length, separatorBuilder: (_, __) => const SizedBox(height: 8), itemBuilder: (_, i) => _marketKalemKarti(isDark, i), ); }), ), _marketOzet(isDark), ]); } Widget _marketBaslik(bool isDark) { return Obx(() => Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: AkcaliTema.camKart( renk: isDark ? Colors.white : AkcaliTema.ikincil, opaklik: isDark ? 0.06 : 0.05, ), child: Row(children: [ Icon(Icons.storefront_rounded, color: AkcaliTema.ikincil, size: 22), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(_aktifListeAdi.value, style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin, fontWeight: FontWeight.w600)), Text( '${_marketListesi.length} urun | Tahmini: ${AkcaliTema.tutarFormat(_tahminiToplam.value)}', style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ]), ), ]), )); } Widget _marketKalemKarti(bool isDark, int index) { return Obx(() { final kalem = _marketListesi[index]; final urun = kalem.urun; return AnimatedContainer( duration: AkcaliTema.hizliAnim, padding: const EdgeInsets.all(14), decoration: AkcaliTema.camKart( renk: isDark ? (kalem.satinAlindi ? AkcaliTema.gelir : Colors.white) : (kalem.satinAlindi ? AkcaliTema.gelir : AkcaliTema.birincil), opaklik: kalem.satinAlindi ? 0.08 : (isDark ? 0.06 : 0.05), ), child: Column(children: [ Row(children: [ GestureDetector( onTap: () { kalem.satinAlindi = !kalem.satinAlindi; _marketListesi.refresh(); _toplamHesapla(); }, child: AnimatedContainer( duration: AkcaliTema.hizliAnim, width: 28, height: 28, decoration: BoxDecoration( color: kalem.satinAlindi ? AkcaliTema.gelir : Colors.transparent, borderRadius: BorderRadius.circular(8), border: Border.all( color: kalem.satinAlindi ? AkcaliTema.gelir : (isDark ? AkcaliTema.koyuSinir : AkcaliTema.acikSinir), width: 2, ), ), child: kalem.satinAlindi ? const Icon(Icons.check_rounded, color: Colors.white, size: 18) : null, ), ), const SizedBox(width: 12), if (urun?.simge != null && urun!.simge!.isNotEmpty) Padding( padding: const EdgeInsets.only(right: 8), child: Text(urun.simge!, style: const TextStyle(fontSize: 20)), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(urun?.ismi ?? 'Urun', style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin, fontWeight: FontWeight.w600, decoration: kalem.satinAlindi ? TextDecoration.lineThrough : null, )), Text( 'Beklenen: ${AkcaliTema.tutarFormat(urun?.sonFiyat ?? 0)}', style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), ]), ), // Adet kontrol Container( decoration: BoxDecoration( color: isDark ? AkcaliTema.koyuKartVurgulu : AkcaliTema.acikArkaplan, borderRadius: BorderRadius.circular(10), ), child: Row(mainAxisSize: MainAxisSize.min, children: [ _adetButon(Icons.remove_rounded, () { if (kalem.adet > 1) { kalem.adet--; _marketListesi.refresh(); _toplamHesapla(); } else { _marketListesi.removeAt(index); _toplamHesapla(); } }, isDark), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Text('${kalem.adet}', style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin, fontWeight: FontWeight.w700)), ), _adetButon(Icons.add_rounded, () { kalem.adet++; _marketListesi.refresh(); _toplamHesapla(); }, isDark), ]), ), ]), if (kalem.satinAlindi) ...[ const SizedBox(height: 10), Row(children: [ const SizedBox(width: 40), Expanded( child: TextField( keyboardType: const TextInputType.numberWithOptions(decimal: true), onChanged: (v) { kalem.gercekFiyat = double.tryParse(v) ?? 0; _toplamHesapla(); }, style: AkcaliTema.govdeStil.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin), decoration: InputDecoration( hintText: 'Gercek fiyat (TL)', hintStyle: TextStyle( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil, fontSize: 13), prefixIcon: Icon(Icons.attach_money_rounded, color: AkcaliTema.gelir, size: 18), filled: true, fillColor: isDark ? AkcaliTema.koyuKartVurgulu : Colors.white, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, ), isDense: true, contentPadding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10), ), ), ), ]), ], ]), ); }); } Widget _adetButon(IconData icon, VoidCallback onTap, bool isDark) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.all(6), child: Icon(icon, size: 18, color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil), ), ); } Widget _marketOzet(bool isDark) { return Obx(() { if (_marketListesi.isEmpty) return const SizedBox.shrink(); final fark = _gercekToplam.value - _tahminiToplam.value; final farkRenk = fark > 0 ? AkcaliTema.gider : AkcaliTema.gelir; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: isDark ? AkcaliTema.koyuKart : Colors.white, borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), boxShadow: [ BoxShadow( color: Colors.black.withAlpha(15), blurRadius: 20, offset: const Offset(0, -5), ), ], ), child: SafeArea( top: false, child: Column(mainAxisSize: MainAxisSize.min, children: [ Row(children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Tahmini', style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), Text(AkcaliTema.tutarFormat(_tahminiToplam.value), style: AkcaliTema.tutarKucuk.copyWith( color: isDark ? AkcaliTema.koyuMetin : AkcaliTema.acikMetin)), ]), ), if (_gercekToplam.value > 0) ...[ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text('Gercek', style: AkcaliTema.etiketStil.copyWith( color: isDark ? AkcaliTema.koyuMetinIkincil : AkcaliTema.acikMetinIkincil)), Text(AkcaliTema.tutarFormat(_gercekToplam.value), style: AkcaliTema.tutarKucuk .copyWith(color: AkcaliTema.birincil)), ]), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text('Fark', style: AkcaliTema.etiketStil .copyWith(color: farkRenk)), Text(AkcaliTema.tutarFormat(fark), style: AkcaliTema.tutarKucuk .copyWith(color: farkRenk)), ]), ), ], ]), const SizedBox(height: 12), SizedBox( width: double.infinity, height: 50, child: FilledButton.icon( onPressed: _alisverisiTamamla, icon: const Icon(Icons.check_circle_rounded, size: 22), label: Text('Alisverisi Tamamla', style: AkcaliTema.altBaslikStil .copyWith(color: Colors.white, fontSize: 16)), style: FilledButton.styleFrom( backgroundColor: AkcaliTema.gelir, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16)), ), ), ), ]), ), ); }); } Future _alisverisiTamamla() async { if (_marketListesi.isEmpty) return; final isar = _finansServis?.isar; if (isar == null) return; try { await isar.writeTxn(() async { final hareket = Hareket(tipi: 'Gider') ..ismi = 'Market Alisverisi' ..miktar = _gercekToplam.value > 0 ? _gercekToplam.value : _tahminiToplam.value ..tarihi = DateTime.now(); final hareketId = await isar.harekets.put(hareket); for (final kalem in _marketListesi) { final hk = HareketKalemi() ..ismi = kalem.urun?.ismi ..birimFiyat = kalem.satinAlindi ? kalem.gercekFiyat : (kalem.urun?.sonFiyat ?? 0) ..adet = kalem.adet.toDouble() ..tarihi = DateTime.now(); hk.hareket.value = hareket; if (kalem.urun != null) hk.urun.value = kalem.urun; final kalemId = await isar.hareketKalemis.put(hk); await hk.hareket.save(); await hk.urun.save(); } }); _marketListesi.clear(); _tahminiToplam.value = 0; _gercekToplam.value = 0; Get.snackbar( 'Basarili', 'Alisveris kaydedildi', backgroundColor: AkcaliTema.gelir.withAlpha(30), colorText: AkcaliTema.gelir, ); } catch (e) { Get.snackbar( 'Hata', 'Kayit sirasinda hata olustu', backgroundColor: AkcaliTema.tehlike.withAlpha(30), colorText: AkcaliTema.tehlike, ); } } } class _MarketKalemi { Urun? urun; int adet; bool satinAlindi; double gercekFiyat; _MarketKalemi({ this.urun, this.adet = 1, this.satinAlindi = false, this.gercekFiyat = 0, }); } class _KameraTarayici extends StatefulWidget { @override State<_KameraTarayici> createState() => _KameraTarayiciState(); } class _KameraTarayiciState extends State<_KameraTarayici> { final MobileScannerController _controller = MobileScannerController( detectionSpeed: DetectionSpeed.normal, facing: CameraFacing.back, ); bool _barkodBulundu = false; @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: Colors.black, body: Stack( children: [ MobileScanner( controller: _controller, onDetect: (capture) { if (_barkodBulundu) return; final barcodes = capture.barcodes; if (barcodes.isNotEmpty && barcodes.first.rawValue != null) { _barkodBulundu = true; HapticFeedback.mediumImpact(); Navigator.pop(context, barcodes.first.rawValue); } }, ), SafeArea( child: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ Row( children: [ GestureDetector( onTap: () => Navigator.pop(context), child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.black.withAlpha(120), borderRadius: BorderRadius.circular(14), ), child: const Icon(Icons.arrow_back_rounded, color: Colors.white, size: 22), ), ), const Spacer(), GestureDetector( onTap: () => _controller.toggleTorch(), child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.black.withAlpha(120), borderRadius: BorderRadius.circular(14), ), child: const Icon(Icons.flash_on_rounded, color: Colors.white, size: 22), ), ), const SizedBox(width: 8), GestureDetector( onTap: () => _controller.switchCamera(), child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.black.withAlpha(120), borderRadius: BorderRadius.circular(14), ), child: const Icon(Icons.cameraswitch_rounded, color: Colors.white, size: 22), ), ), ], ), const Spacer(), Container( width: 260, height: 260, decoration: BoxDecoration( border: Border.all(color: AkcaliTema.birincil, width: 2), borderRadius: BorderRadius.circular(20), ), ), const Spacer(), Container( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12), decoration: BoxDecoration( color: Colors.black.withAlpha(120), borderRadius: BorderRadius.circular(16), ), child: const Text( 'Barkodu cerceve icine hizalayin', style: TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500), ), ), const SizedBox(height: 24), ], ), ), ), ], ), ); } }