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 '../state/app_state.dart';
import '../services/printer_service.dart';
import 'produk_screen.dart' show productImageUrl;
import '../utils/colors.dart';
import '../utils/format.dart';
import '../utils/rupiah_input.dart';
@@ -1138,19 +1139,7 @@ class _CartSheetContent extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row(
children: [
CircleAvatar(
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),
),
),
_KasirAvatar(product: line.product, radius: 18),
const SizedBox(width: 12),
Expanded(
child: Column(
@@ -1490,19 +1479,7 @@ class _ProductCard extends StatelessWidget {
children: [
Row(
children: [
CircleAvatar(
radius: 18,
backgroundColor: kAccent.withValues(alpha: 0.15),
child: Text(
product.name.isNotEmpty
? product.name[0].toUpperCase()
: '?',
style: TextStyle(
color: kAccent,
fontWeight: FontWeight.w700,
),
),
),
_KasirAvatar(product: product, radius: 18),
const Spacer(),
Container(
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 {
final IconData icon;
final VoidCallback onTap;

View File

@@ -40,12 +40,14 @@ Future<String?> pickAndUploadProductImage(BuildContext context,
final raw = picked.name.substring(dot + 1).toLowerCase();
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 =
'prod-${DateTime.now().millisecondsSinceEpoch}.$ext';
await Supabase.instance.client.storage
.from(kProductImageBucket)
.uploadBinary(path, bytes,
fileOptions: FileOptions(contentType: 'image/$ext', upsert: true));
fileOptions: FileOptions(contentType: mime, upsert: true));
return path;
} catch (e) {
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
# 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.
version: 1.1.0+4
version: 1.2.0+5
environment:
sdk: ^3.9.2