v1.2.0: foto produk di kasir (grid + keranjang) + fix MIME jpg->jpeg

This commit is contained in:
onie
2026-10-18 00:28:18 +07:00
parent 60abcc1f5c
commit c6230abd5c
3 changed files with 35 additions and 28 deletions

View File

@@ -8,6 +8,7 @@ import '../models/product.dart';
import '../models/sale.dart'; import '../models/sale.dart';
import '../state/app_state.dart'; import '../state/app_state.dart';
import '../services/printer_service.dart'; import '../services/printer_service.dart';
import 'produk_screen.dart' show productImageUrl;
import '../utils/colors.dart'; import '../utils/colors.dart';
import '../utils/format.dart'; import '../utils/format.dart';
import '../utils/rupiah_input.dart'; import '../utils/rupiah_input.dart';
@@ -1138,19 +1139,7 @@ class _CartSheetContent extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row( child: Row(
children: [ children: [
CircleAvatar( _KasirAvatar(product: line.product, radius: 18),
radius: 18,
backgroundColor: kAccent.withValues(alpha: 0.15),
child: Text(
line.product.name.isNotEmpty
? line.product.name[0].toUpperCase()
: '?',
style: TextStyle(
color: kAccent,
fontWeight: FontWeight.w700,
fontSize: 13),
),
),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded( Expanded(
child: Column( child: Column(
@@ -1490,19 +1479,7 @@ class _ProductCard extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
CircleAvatar( _KasirAvatar(product: product, radius: 18),
radius: 18,
backgroundColor: kAccent.withValues(alpha: 0.15),
child: Text(
product.name.isNotEmpty
? product.name[0].toUpperCase()
: '?',
style: TextStyle(
color: kAccent,
fontWeight: FontWeight.w700,
),
),
),
const Spacer(), const Spacer(),
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -1579,6 +1556,34 @@ class _ProductCard extends StatelessWidget {
} }
} }
/// Avatar produk di kasir: foto jika ada, fallback huruf pertama nama.
class _KasirAvatar extends StatelessWidget {
final Product product;
final double radius;
const _KasirAvatar({required this.product, this.radius = 18});
@override
Widget build(BuildContext context) {
final url = productImageUrl(product.imagePath);
return CircleAvatar(
radius: radius,
backgroundColor: kAccent.withValues(alpha: 0.15),
backgroundImage: url != null ? NetworkImage(url) : null,
child: url == null
? Text(
product.name.isNotEmpty
? product.name[0].toUpperCase()
: '?',
style: TextStyle(
color: kAccent,
fontWeight: FontWeight.w700,
fontSize: radius * 0.75),
)
: null,
);
}
}
class _QtyButton extends StatelessWidget { class _QtyButton extends StatelessWidget {
final IconData icon; final IconData icon;
final VoidCallback onTap; final VoidCallback onTap;

View File

@@ -40,12 +40,14 @@ Future<String?> pickAndUploadProductImage(BuildContext context,
final raw = picked.name.substring(dot + 1).toLowerCase(); final raw = picked.name.substring(dot + 1).toLowerCase();
if (['jpg', 'jpeg', 'png', 'webp'].contains(raw)) ext = raw; if (['jpg', 'jpeg', 'png', 'webp'].contains(raw)) ext = raw;
} }
// MIME resmi: jpg -> image/jpeg (bukan image/jpg, ditolak server 415)
final mime = ext == 'jpg' ? 'image/jpeg' : 'image/$ext';
final path = final path =
'prod-${DateTime.now().millisecondsSinceEpoch}.$ext'; 'prod-${DateTime.now().millisecondsSinceEpoch}.$ext';
await Supabase.instance.client.storage await Supabase.instance.client.storage
.from(kProductImageBucket) .from(kProductImageBucket)
.uploadBinary(path, bytes, .uploadBinary(path, bytes,
fileOptions: FileOptions(contentType: 'image/$ext', upsert: true)); fileOptions: FileOptions(contentType: mime, upsert: true));
return path; return path;
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.1.0+4 version: 1.2.0+5
environment: environment:
sdk: ^3.9.2 sdk: ^3.9.2