feat: create product
This commit is contained in:
parent
935b6b9a5b
commit
bb9aef55cf
@ -1,91 +1,189 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:enaklo_pos/presentation/setting/bloc/upload_file/upload_file_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
|
||||
import '../assets/assets.gen.dart';
|
||||
import '../constants/colors.dart';
|
||||
import '../constants/variables.dart';
|
||||
import 'buttons.dart';
|
||||
import 'spaces.dart';
|
||||
|
||||
class ImagePickerWidget extends StatefulWidget {
|
||||
final String label;
|
||||
final void Function(XFile? file) onChanged;
|
||||
final void Function(String? uploadedUrl)? onUploaded;
|
||||
final bool showLabel;
|
||||
final String? initialImageUrl;
|
||||
final bool autoUpload;
|
||||
|
||||
const ImagePickerWidget({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.onChanged,
|
||||
this.onUploaded,
|
||||
this.showLabel = true,
|
||||
this.initialImageUrl,
|
||||
this.autoUpload = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ImagePickerWidget> createState() => _ImagePickerWidgetState();
|
||||
}
|
||||
|
||||
class _ImagePickerWidgetState extends State<ImagePickerWidget> {
|
||||
class _ImagePickerWidgetState extends State<ImagePickerWidget>
|
||||
with TickerProviderStateMixin {
|
||||
String? imagePath;
|
||||
String? uploadedImageUrl;
|
||||
bool hasInitialImage = false;
|
||||
bool isHovering = false;
|
||||
bool isUploading = false;
|
||||
late AnimationController _scaleController;
|
||||
late AnimationController _fadeController;
|
||||
late AnimationController _uploadController;
|
||||
late Animation<double> _scaleAnimation;
|
||||
late Animation<double> _fadeAnimation;
|
||||
late Animation<double> _uploadAnimation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
hasInitialImage = widget.initialImageUrl != null;
|
||||
|
||||
_scaleController = AnimationController(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
vsync: this,
|
||||
);
|
||||
_fadeController = AnimationController(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
vsync: this,
|
||||
);
|
||||
_uploadController = AnimationController(
|
||||
duration: const Duration(milliseconds: 1000),
|
||||
vsync: this,
|
||||
);
|
||||
|
||||
_scaleAnimation = Tween<double>(
|
||||
begin: 1.0,
|
||||
end: 0.95,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _scaleController,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
|
||||
_fadeAnimation = Tween<double>(
|
||||
begin: 0.0,
|
||||
end: 1.0,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _fadeController,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
|
||||
_uploadAnimation = Tween<double>(
|
||||
begin: 0.0,
|
||||
end: 1.0,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _uploadController,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
|
||||
_fadeController.forward();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scaleController.dispose();
|
||||
_fadeController.dispose();
|
||||
_uploadController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _pickImage() async {
|
||||
_scaleController.forward().then((_) {
|
||||
_scaleController.reverse();
|
||||
});
|
||||
|
||||
final pickedFile = await ImagePicker().pickImage(
|
||||
source: ImageSource.gallery,
|
||||
);
|
||||
|
||||
setState(() {
|
||||
if (pickedFile != null) {
|
||||
if (pickedFile != null) {
|
||||
setState(() {
|
||||
imagePath = pickedFile.path;
|
||||
hasInitialImage = false; // Clear initial image when new image is picked
|
||||
widget.onChanged(pickedFile);
|
||||
} else {
|
||||
debugPrint('No image selected.');
|
||||
widget.onChanged(null);
|
||||
hasInitialImage = false;
|
||||
uploadedImageUrl = null;
|
||||
});
|
||||
|
||||
widget.onChanged(pickedFile);
|
||||
|
||||
// Auto upload if enabled
|
||||
if (widget.autoUpload) {
|
||||
_uploadImage(pickedFile.path);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
debugPrint('No image selected.');
|
||||
widget.onChanged(null);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.showLabel) ...[
|
||||
Text(
|
||||
widget.label,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
void _uploadImage(String filePath) {
|
||||
setState(() {
|
||||
isUploading = true;
|
||||
});
|
||||
_uploadController.forward();
|
||||
|
||||
context.read<UploadFileBloc>().add(
|
||||
UploadFileEvent.upload(filePath),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImageContainer() {
|
||||
return Container(
|
||||
width: 100.0,
|
||||
height: 100.0,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
const SpaceHeight(12.0),
|
||||
],
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(color: AppColors.primary),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 80.0,
|
||||
height: 80.0,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
child: imagePath != null
|
||||
? Image.file(
|
||||
File(imagePath!),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: imagePath != null
|
||||
? Image.file(
|
||||
File(imagePath!),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: uploadedImageUrl != null
|
||||
? CachedNetworkImage(
|
||||
imageUrl: uploadedImageUrl!.contains('http')
|
||||
? uploadedImageUrl!
|
||||
: '${Variables.baseUrl}/$uploadedImageUrl',
|
||||
placeholder: (context, url) => Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
AppColors.primary.withOpacity(0.1),
|
||||
AppColors.primary.withOpacity(0.05),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) =>
|
||||
_buildPlaceholder(),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: hasInitialImage && widget.initialImageUrl != null
|
||||
@ -93,38 +191,493 @@ class _ImagePickerWidgetState extends State<ImagePickerWidget> {
|
||||
imageUrl: widget.initialImageUrl!.contains('http')
|
||||
? widget.initialImageUrl!
|
||||
: '${Variables.baseUrl}/${widget.initialImageUrl}',
|
||||
placeholder: (context, url) =>
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
color: AppColors.black.withOpacity(0.05),
|
||||
child: Assets.icons.image.svg(),
|
||||
placeholder: (context, url) => Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
AppColors.primary.withOpacity(0.1),
|
||||
AppColors.primary.withOpacity(0.05),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child:
|
||||
CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) =>
|
||||
_buildPlaceholder(),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
color: AppColors.black.withOpacity(0.05),
|
||||
child: Assets.icons.image.svg(),
|
||||
),
|
||||
: _buildPlaceholder(),
|
||||
),
|
||||
// Upload progress overlay
|
||||
if (isUploading)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.6),
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(
|
||||
color: Colors.white,
|
||||
strokeWidth: 2,
|
||||
value: _uploadAnimation.value == 1.0
|
||||
? null
|
||||
: _uploadAnimation.value,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Uploading...',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10.0),
|
||||
child: Button.filled(
|
||||
height: 30.0,
|
||||
width: 140.0,
|
||||
onPressed: _pickImage,
|
||||
label: 'Choose Photo',
|
||||
fontSize: 12.0,
|
||||
borderRadius: 5.0,
|
||||
// Overlay gradient for better button visibility
|
||||
if ((imagePath != null ||
|
||||
uploadedImageUrl != null ||
|
||||
(hasInitialImage && widget.initialImageUrl != null)) &&
|
||||
!isUploading)
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withOpacity(0.3),
|
||||
],
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPlaceholder() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
AppColors.primary.withOpacity(0.1),
|
||||
AppColors.primary.withOpacity(0.05),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.add_photo_alternate_outlined,
|
||||
size: 32,
|
||||
color: AppColors.primary.withOpacity(0.6),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Photo',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: AppColors.primary.withOpacity(0.6),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButton() {
|
||||
bool hasImage = imagePath != null ||
|
||||
uploadedImageUrl != null ||
|
||||
(hasInitialImage && widget.initialImageUrl != null);
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
AppColors.primary,
|
||||
AppColors.primary.withOpacity(0.8),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColors.primary.withOpacity(0.3),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: isUploading ? null : _pickImage,
|
||||
onHover: (hover) {
|
||||
setState(() {
|
||||
isHovering = hover;
|
||||
});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: isHovering
|
||||
? Colors.white.withOpacity(0.1)
|
||||
: Colors.transparent,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
isUploading
|
||||
? Icons.cloud_upload_outlined
|
||||
: hasImage
|
||||
? Icons.edit_outlined
|
||||
: Icons.add_photo_alternate_outlined,
|
||||
color: Colors.white,
|
||||
size: 18,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
isUploading
|
||||
? 'Uploading...'
|
||||
: hasImage
|
||||
? 'Change Photo'
|
||||
: 'Choose Photo',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUploadButton() {
|
||||
if (!widget.autoUpload &&
|
||||
imagePath != null &&
|
||||
uploadedImageUrl == null &&
|
||||
!isUploading) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Colors.green.shade600,
|
||||
Colors.green.shade500,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.green.withOpacity(0.3),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => _uploadImage(imagePath!),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud_upload_outlined,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Upload to Server',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocListener<UploadFileBloc, UploadFileState>(
|
||||
listener: (context, state) {
|
||||
state.when(
|
||||
initial: () {},
|
||||
loading: () {
|
||||
if (!isUploading) {
|
||||
setState(() {
|
||||
isUploading = true;
|
||||
});
|
||||
_uploadController.repeat();
|
||||
}
|
||||
},
|
||||
success: (fileData) {
|
||||
setState(() {
|
||||
isUploading = false;
|
||||
uploadedImageUrl = fileData.fileUrl;
|
||||
});
|
||||
_uploadController.reset();
|
||||
|
||||
if (widget.onUploaded != null) {
|
||||
widget.onUploaded!(fileData.fileUrl);
|
||||
}
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Row(
|
||||
children: [
|
||||
Icon(Icons.check_circle, color: Colors.white),
|
||||
SizedBox(width: 8),
|
||||
Text('Image uploaded successfully!'),
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.green,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (message) {
|
||||
setState(() {
|
||||
isUploading = false;
|
||||
});
|
||||
_uploadController.reset();
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Row(
|
||||
children: [
|
||||
Icon(Icons.error_outline, color: Colors.white),
|
||||
SizedBox(width: 8),
|
||||
Expanded(child: Text('Upload failed: $message')),
|
||||
],
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
duration: Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: FadeTransition(
|
||||
opacity: _fadeAnimation,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.showLabel) ...[
|
||||
Text(
|
||||
widget.label,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
const SpaceHeight(16.0),
|
||||
],
|
||||
ScaleTransition(
|
||||
scale: _scaleAnimation,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
color: Colors.white,
|
||||
border: Border.all(
|
||||
color: isUploading
|
||||
? Colors.orange.withOpacity(0.5)
|
||||
: uploadedImageUrl != null
|
||||
? Colors.green.withOpacity(0.5)
|
||||
: AppColors.primary.withOpacity(0.2),
|
||||
width: 1.5,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildImageContainer(),
|
||||
const SizedBox(height: 20),
|
||||
_buildActionButton(),
|
||||
_buildUploadButton(),
|
||||
if ((imagePath != null ||
|
||||
uploadedImageUrl != null ||
|
||||
(hasInitialImage &&
|
||||
widget.initialImageUrl != null)) &&
|
||||
!isUploading) ...[
|
||||
const SizedBox(height: 12),
|
||||
TextButton.icon(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
imagePath = null;
|
||||
hasInitialImage = false;
|
||||
uploadedImageUrl = null;
|
||||
});
|
||||
widget.onChanged(null);
|
||||
if (widget.onUploaded != null) {
|
||||
widget.onUploaded!(null);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete_outline,
|
||||
size: 16,
|
||||
color: Colors.red.shade400,
|
||||
),
|
||||
label: Text(
|
||||
'Remove Photo',
|
||||
style: TextStyle(
|
||||
color: Colors.red.shade400,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
// Upload status indicator
|
||||
if (uploadedImageUrl != null && !isUploading) ...[
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border:
|
||||
Border.all(color: Colors.green.withOpacity(0.3)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.cloud_done_outlined,
|
||||
size: 14,
|
||||
color: Colors.green.shade600,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
'Uploaded',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.green.shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Cara menggunakan widget ini:
|
||||
///
|
||||
/// ```dart
|
||||
/// // 1. Basic usage tanpa auto upload
|
||||
/// ImagePickerWidget(
|
||||
/// label: 'Product Image',
|
||||
/// onChanged: (file) {
|
||||
/// // Handle selected file
|
||||
/// print('Selected file: ${file?.path}');
|
||||
/// },
|
||||
/// onUploaded: (url) {
|
||||
/// // Handle uploaded URL
|
||||
/// print('Uploaded URL: $url');
|
||||
/// },
|
||||
/// )
|
||||
///
|
||||
/// // 2. Auto upload setelah memilih gambar
|
||||
/// ImagePickerWidget(
|
||||
/// label: 'Profile Picture',
|
||||
/// autoUpload: true,
|
||||
/// onChanged: (file) => setState(() => selectedFile = file),
|
||||
/// onUploaded: (url) => setState(() => profileImageUrl = url),
|
||||
/// )
|
||||
///
|
||||
/// // 3. Dengan initial image
|
||||
/// ImagePickerWidget(
|
||||
/// label: 'Banner Image',
|
||||
/// initialImageUrl: existingImageUrl,
|
||||
/// onChanged: (file) => handleFileChange(file),
|
||||
/// onUploaded: (url) => handleUploadSuccess(url),
|
||||
/// )
|
||||
/// ```
|
||||
///
|
||||
/// Pastikan untuk wrap widget ini dengan BlocProvider:
|
||||
/// ```dart
|
||||
/// BlocProvider(
|
||||
/// create: (context) => UploadFileBloc(
|
||||
/// context.read<FileRemoteDataSource>(),
|
||||
/// ),
|
||||
/// child: ImagePickerWidget(...),
|
||||
/// )
|
||||
/// ```
|
||||
@ -1,27 +1,48 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:enaklo_pos/core/constants/variables.dart';
|
||||
import 'package:enaklo_pos/core/network/dio_client.dart';
|
||||
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/response/category_response_model.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
class CategoryRemoteDatasource {
|
||||
Future<Either<String, CategroyResponseModel>> getCategories() async {
|
||||
final Dio dio = DioClient.instance;
|
||||
|
||||
Future<Either<String, CategoryResponseModel>> getCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
bool isActive = true,
|
||||
}) async {
|
||||
final authData = await AuthLocalDataSource().getAuthData();
|
||||
final Map<String, String> headers = {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
'Accept': 'application/json',
|
||||
};
|
||||
final response = await http.get(
|
||||
Uri.parse('${Variables.baseUrl}/api/api-categories'),
|
||||
headers: headers);
|
||||
log(response.statusCode.toString());
|
||||
log(response.body);
|
||||
if (response.statusCode == 200) {
|
||||
return right(CategroyResponseModel.fromJson(response.body));
|
||||
} else {
|
||||
return left(response.body);
|
||||
|
||||
try {
|
||||
final response = await dio.get(
|
||||
'${Variables.baseUrl}/api/v1/categories',
|
||||
queryParameters: {
|
||||
'page': page,
|
||||
'limit': limit,
|
||||
'is_active': isActive,
|
||||
},
|
||||
options: Options(headers: headers),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return right(CategoryResponseModel.fromMap(response.data));
|
||||
} else {
|
||||
return left(response.data.toString());
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
log('Dio error: ${e.message}');
|
||||
return left(e.response?.data.toString() ?? e.message ?? 'Unknown error');
|
||||
} catch (e) {
|
||||
log('Unexpected error: $e');
|
||||
return left('Unexpected error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
lib/data/datasources/file_remote_datasource.dart
Normal file
53
lib/data/datasources/file_remote_datasource.dart
Normal file
@ -0,0 +1,53 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:enaklo_pos/core/constants/variables.dart';
|
||||
import 'package:enaklo_pos/core/network/dio_client.dart';
|
||||
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/response/file_response_model.dart';
|
||||
|
||||
class FileRemoteDataSource {
|
||||
final Dio dio = DioClient.instance;
|
||||
|
||||
Future<Either<String, FileResponseModel>> uploadFile({
|
||||
required String filePath,
|
||||
required String fileType,
|
||||
required String description,
|
||||
}) async {
|
||||
final url = '${Variables.baseUrl}/api/v1/files/upload';
|
||||
|
||||
try {
|
||||
final authData = await AuthLocalDataSource().getAuthData();
|
||||
|
||||
// Membuat FormData
|
||||
final formData = FormData.fromMap({
|
||||
'file': await MultipartFile.fromFile(filePath,
|
||||
filename: filePath.split('/').last),
|
||||
'file_type': fileType,
|
||||
'description': description,
|
||||
});
|
||||
|
||||
final response = await dio.post(
|
||||
url,
|
||||
data: formData,
|
||||
options: Options(
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
'Accept': 'application/json',
|
||||
// Content-Type otomatis diatur oleh Dio untuk FormData
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 201 || response.statusCode == 200) {
|
||||
// Misal response.data['url'] adalah URL file yang diupload
|
||||
return Right(FileResponseModel.fromJson(response.data));
|
||||
} else {
|
||||
return Left('Upload gagal: ${response.statusMessage}');
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
return Left(e.response?.data['message'] ?? 'Upload gagal');
|
||||
} catch (e) {
|
||||
return Left('Unexpected error: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,6 @@ import 'package:enaklo_pos/core/network/dio_client.dart';
|
||||
import 'package:enaklo_pos/data/models/request/product_request_model.dart';
|
||||
import 'package:enaklo_pos/data/models/response/add_product_response_model.dart';
|
||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../core/constants/variables.dart';
|
||||
import 'auth_local_datasource.dart';
|
||||
@ -21,6 +20,10 @@ class ProductRemoteDatasource {
|
||||
|
||||
final response = await dio.get(
|
||||
url,
|
||||
queryParameters: {
|
||||
'page': 1,
|
||||
'limit': 30,
|
||||
},
|
||||
options: Options(
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
@ -45,67 +48,64 @@ class ProductRemoteDatasource {
|
||||
|
||||
Future<Either<String, AddProductResponseModel>> addProduct(
|
||||
ProductRequestModel productRequestModel) async {
|
||||
final authData = await AuthLocalDataSource().getAuthData();
|
||||
final Map<String, String> headers = {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
};
|
||||
var request = http.MultipartRequest(
|
||||
'POST', Uri.parse('${Variables.baseUrl}/api/products'));
|
||||
request.fields.addAll(productRequestModel.toMap());
|
||||
request.files.add(await http.MultipartFile.fromPath(
|
||||
'image', productRequestModel.image!.path));
|
||||
request.headers.addAll(headers);
|
||||
try {
|
||||
final authData = await AuthLocalDataSource().getAuthData();
|
||||
final url = '${Variables.baseUrl}/api/v1/products';
|
||||
|
||||
http.StreamedResponse response = await request.send();
|
||||
final response = await dio.post(
|
||||
url,
|
||||
data: productRequestModel.toMap(),
|
||||
options: Options(
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final String body = await response.stream.bytesToString();
|
||||
log(response.stream.toString());
|
||||
log(response.statusCode.toString());
|
||||
if (response.statusCode == 201) {
|
||||
return right(AddProductResponseModel.fromJson(body));
|
||||
} else {
|
||||
return left(body);
|
||||
if (response.statusCode == 200) {
|
||||
return Right(AddProductResponseModel.fromMap(response.data));
|
||||
} else {
|
||||
return const Left('Failed to create products');
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
log("Dio error: ${e.message}");
|
||||
return Left(e.response?.data['message'] ?? 'Gagal menambah produk');
|
||||
} catch (e) {
|
||||
log("Unexpected error: $e");
|
||||
return const Left('Unexpected error occurred');
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<String, AddProductResponseModel>> updateProduct(
|
||||
ProductRequestModel productRequestModel) async {
|
||||
final authData = await AuthLocalDataSource().getAuthData();
|
||||
final Map<String, String> headers = {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
};
|
||||
try {
|
||||
final authData = await AuthLocalDataSource().getAuthData();
|
||||
final url =
|
||||
'${Variables.baseUrl}/api/v1/products/${productRequestModel.id}';
|
||||
|
||||
log("Update Product Request Data: ${productRequestModel.toMap()}");
|
||||
log("Update Product ID: ${productRequestModel.id}");
|
||||
log("Update Product Name: ${productRequestModel.name}");
|
||||
log("Update Product Price: ${productRequestModel.price}");
|
||||
log("Update Product Stock: ${productRequestModel.stock}");
|
||||
log("Update Product Category ID: ${productRequestModel.categoryId}");
|
||||
log("Update Product Is Best Seller: ${productRequestModel.isBestSeller}");
|
||||
log("Update Product Printer Type: ${productRequestModel.printerType}");
|
||||
log("Update Product Has Image: ${productRequestModel.image != null}");
|
||||
final response = await dio.put(
|
||||
url,
|
||||
data: productRequestModel.toMap(),
|
||||
options: Options(
|
||||
headers: {
|
||||
'Authorization': 'Bearer ${authData.token}',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
var request = http.MultipartRequest(
|
||||
'POST', Uri.parse('${Variables.baseUrl}/api/products/edit'));
|
||||
request.fields.addAll(productRequestModel.toMap());
|
||||
if (productRequestModel.image != null) {
|
||||
request.files.add(await http.MultipartFile.fromPath(
|
||||
'image', productRequestModel.image!.path));
|
||||
}
|
||||
request.headers.addAll(headers);
|
||||
|
||||
log("Update Product Request Fields: ${request.fields}");
|
||||
log("Update Product Request Files: ${request.files.length}");
|
||||
|
||||
http.StreamedResponse response = await request.send();
|
||||
|
||||
final String body = await response.stream.bytesToString();
|
||||
log("Update Product Status Code: ${response.statusCode}");
|
||||
log("Update Product Body: $body");
|
||||
if (response.statusCode == 200) {
|
||||
return right(AddProductResponseModel.fromJson(body));
|
||||
} else {
|
||||
return left(body);
|
||||
if (response.statusCode == 200) {
|
||||
return Right(AddProductResponseModel.fromMap(response.data));
|
||||
} else {
|
||||
return const Left('Failed to update products');
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
log("Dio error: ${e.message}");
|
||||
return Left(e.response?.data['message'] ?? 'Gagal update produk');
|
||||
} catch (e) {
|
||||
log("Unexpected error: $e");
|
||||
return const Left('Unexpected error occurred');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,40 +1,49 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class ProductRequestModel {
|
||||
final String? id;
|
||||
final String name;
|
||||
final String? description;
|
||||
final String categoryId;
|
||||
final String? sku;
|
||||
final String? barcode;
|
||||
final int price;
|
||||
final int stock;
|
||||
final int categoryId;
|
||||
final int isBestSeller;
|
||||
final XFile? image;
|
||||
final int cost;
|
||||
final bool isActive;
|
||||
final bool hasVariants;
|
||||
final String imageUrl;
|
||||
final String? printerType;
|
||||
|
||||
ProductRequestModel({
|
||||
this.id,
|
||||
required this.name,
|
||||
required this.price,
|
||||
required this.stock,
|
||||
this.description,
|
||||
required this.categoryId,
|
||||
required this.isBestSeller,
|
||||
this.image,
|
||||
this.sku,
|
||||
this.barcode,
|
||||
required this.price,
|
||||
required this.cost,
|
||||
this.isActive = true,
|
||||
this.hasVariants = false,
|
||||
required this.imageUrl,
|
||||
this.printerType,
|
||||
});
|
||||
|
||||
Map<String, String> toMap() {
|
||||
log("toMap: $isBestSeller");
|
||||
final map = {
|
||||
Map<String, dynamic> toMap() {
|
||||
final map = <String, dynamic>{
|
||||
'name': name,
|
||||
'price': price.toString(),
|
||||
'stock': stock.toString(),
|
||||
'category_id': categoryId.toString(),
|
||||
'is_best_seller': isBestSeller.toString(),
|
||||
'description': description ?? '',
|
||||
'category_id': categoryId,
|
||||
'sku': sku ?? '',
|
||||
'barcode': barcode ?? '',
|
||||
'price': price,
|
||||
'cost': cost,
|
||||
'is_active': isActive,
|
||||
'has_variants': hasVariants,
|
||||
'image_url': imageUrl,
|
||||
'printer_type': printerType ?? '',
|
||||
};
|
||||
|
||||
if (id != null) {
|
||||
map['id'] = id.toString();
|
||||
map['id'] = id;
|
||||
}
|
||||
|
||||
return map;
|
||||
|
||||
@ -4,12 +4,10 @@ import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
|
||||
class AddProductResponseModel {
|
||||
final bool success;
|
||||
final String message;
|
||||
final Product data;
|
||||
|
||||
AddProductResponseModel({
|
||||
required this.success,
|
||||
required this.message,
|
||||
required this.data,
|
||||
});
|
||||
|
||||
@ -21,13 +19,11 @@ class AddProductResponseModel {
|
||||
factory AddProductResponseModel.fromMap(Map<String, dynamic> json) =>
|
||||
AddProductResponseModel(
|
||||
success: json["success"],
|
||||
message: json["message"],
|
||||
data: Product.fromMap(json["data"]),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
"success": success,
|
||||
"message": message,
|
||||
"data": data.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,91 +1,120 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'dart:convert';
|
||||
|
||||
class CategroyResponseModel {
|
||||
final String status;
|
||||
final List<CategoryModel> data;
|
||||
class CategoryResponseModel {
|
||||
final bool success;
|
||||
final CategoryData data;
|
||||
final dynamic errors;
|
||||
|
||||
CategroyResponseModel({
|
||||
required this.status,
|
||||
CategoryResponseModel({
|
||||
required this.success,
|
||||
required this.data,
|
||||
this.errors,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
'status': status,
|
||||
'data': data.map((x) => x.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
factory CategroyResponseModel.fromMap(Map<String, dynamic> map) {
|
||||
return CategroyResponseModel(
|
||||
status: map['status'] as String,
|
||||
data: List<CategoryModel>.from(
|
||||
(map['data']).map<CategoryModel>(
|
||||
(x) => CategoryModel.fromMap(x as Map<String, dynamic>),
|
||||
),
|
||||
),
|
||||
factory CategoryResponseModel.fromMap(Map<String, dynamic> map) {
|
||||
return CategoryResponseModel(
|
||||
success: map['success'] as bool,
|
||||
data: CategoryData.fromMap(map['data'] as Map<String, dynamic>),
|
||||
errors: map['errors'],
|
||||
);
|
||||
}
|
||||
|
||||
factory CategroyResponseModel.fromJson(String str) =>
|
||||
CategroyResponseModel.fromMap(json.decode(str));
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
|
||||
class CategoryModel {
|
||||
int? id;
|
||||
String? name;
|
||||
int? categoryId;
|
||||
int? isSync;
|
||||
String? image;
|
||||
// DateTime createdAt;
|
||||
// DateTime updatedAt;
|
||||
|
||||
CategoryModel({this.id, this.name, this.categoryId, this.isSync, this.image});
|
||||
factory CategoryResponseModel.fromJson(String str) =>
|
||||
CategoryResponseModel.fromMap(json.decode(str));
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
// 'id': id,
|
||||
'name': name,
|
||||
'is_sync': isSync ?? 1,
|
||||
'category_id': id,
|
||||
'image': image
|
||||
return {
|
||||
'success': success,
|
||||
'data': data.toMap(),
|
||||
'errors': errors,
|
||||
};
|
||||
}
|
||||
|
||||
factory CategoryModel.fromMap(Map<String, dynamic> map) {
|
||||
return CategoryModel(
|
||||
id: map['id'] as int?,
|
||||
name: map['name'] as String?,
|
||||
isSync: map['is_sync'] as int?,
|
||||
categoryId: map['id'],
|
||||
image: map['image']);
|
||||
}
|
||||
|
||||
factory CategoryModel.fromJson(String str) =>
|
||||
CategoryModel.fromMap(json.decode(str));
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant CategoryModel other) {
|
||||
if (identical(this, other)) return true;
|
||||
class CategoryData {
|
||||
final List<CategoryModel> categories;
|
||||
final int totalCount;
|
||||
final int page;
|
||||
final int limit;
|
||||
final int totalPages;
|
||||
|
||||
return other.id == id &&
|
||||
other.name == name &&
|
||||
other.categoryId == categoryId &&
|
||||
other.isSync == isSync &&
|
||||
other.image == image;
|
||||
CategoryData({
|
||||
required this.categories,
|
||||
required this.totalCount,
|
||||
required this.page,
|
||||
required this.limit,
|
||||
required this.totalPages,
|
||||
});
|
||||
|
||||
factory CategoryData.fromMap(Map<String, dynamic> map) {
|
||||
return CategoryData(
|
||||
categories: List<CategoryModel>.from(
|
||||
(map['categories'] as List).map((x) => CategoryModel.fromMap(x)),
|
||||
),
|
||||
totalCount: map['total_count'] as int,
|
||||
page: map['page'] as int,
|
||||
limit: map['limit'] as int,
|
||||
totalPages: map['total_pages'] as int,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return id.hashCode ^
|
||||
name.hashCode ^
|
||||
categoryId.hashCode ^
|
||||
isSync.hashCode ^
|
||||
image.hashCode;
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'categories': categories.map((x) => x.toMap()).toList(),
|
||||
'total_count': totalCount,
|
||||
'page': page,
|
||||
'limit': limit,
|
||||
'total_pages': totalPages,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class CategoryModel {
|
||||
String id;
|
||||
final String organizationId;
|
||||
final String name;
|
||||
final String? description;
|
||||
final String businessType;
|
||||
final Map<String, dynamic> metadata;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
|
||||
CategoryModel({
|
||||
required this.id,
|
||||
required this.organizationId,
|
||||
required this.name,
|
||||
this.description,
|
||||
required this.businessType,
|
||||
required this.metadata,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
factory CategoryModel.fromMap(Map<String, dynamic> map) {
|
||||
return CategoryModel(
|
||||
id: map['id'] as String,
|
||||
organizationId: map['organization_id'] as String,
|
||||
name: map['name'] as String,
|
||||
description: map['description'] as String?,
|
||||
businessType: map['business_type'] as String,
|
||||
metadata: Map<String, dynamic>.from(map['metadata'] ?? {}),
|
||||
createdAt: DateTime.parse(map['created_at'] as String),
|
||||
updatedAt: DateTime.parse(map['updated_at'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'organization_id': organizationId,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'business_type': businessType,
|
||||
'metadata': metadata,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
154
lib/data/models/response/file_response_model.dart
Normal file
154
lib/data/models/response/file_response_model.dart
Normal file
@ -0,0 +1,154 @@
|
||||
class FileResponseModel {
|
||||
final FileModel data;
|
||||
final String message;
|
||||
final bool success;
|
||||
|
||||
FileResponseModel({
|
||||
required this.data,
|
||||
required this.message,
|
||||
required this.success,
|
||||
});
|
||||
|
||||
factory FileResponseModel.fromJson(Map<String, dynamic> json) {
|
||||
return FileResponseModel(
|
||||
data: FileModel.fromJson(json['data']),
|
||||
message: json['message'] as String,
|
||||
success: json['success'] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'data': data.toJson(),
|
||||
'message': message,
|
||||
'success': success,
|
||||
};
|
||||
|
||||
factory FileResponseModel.fromMap(Map<String, dynamic> map) =>
|
||||
FileResponseModel.fromJson(map);
|
||||
|
||||
Map<String, dynamic> toMap() => toJson();
|
||||
|
||||
FileResponseModel copyWith({
|
||||
FileModel? data,
|
||||
String? message,
|
||||
bool? success,
|
||||
}) {
|
||||
return FileResponseModel(
|
||||
data: data ?? this.data,
|
||||
message: message ?? this.message,
|
||||
success: success ?? this.success,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'FileResponseModel(data: $data, message: $message, success: $success)';
|
||||
}
|
||||
|
||||
class FileModel {
|
||||
final String id;
|
||||
final String organizationId;
|
||||
final String userId;
|
||||
final String fileName;
|
||||
final String originalName;
|
||||
final String fileUrl;
|
||||
final int fileSize;
|
||||
final String mimeType;
|
||||
final String fileType;
|
||||
final String uploadPath;
|
||||
final bool isPublic;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
|
||||
FileModel({
|
||||
required this.id,
|
||||
required this.organizationId,
|
||||
required this.userId,
|
||||
required this.fileName,
|
||||
required this.originalName,
|
||||
required this.fileUrl,
|
||||
required this.fileSize,
|
||||
required this.mimeType,
|
||||
required this.fileType,
|
||||
required this.uploadPath,
|
||||
required this.isPublic,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
factory FileModel.fromJson(Map<String, dynamic> json) {
|
||||
return FileModel(
|
||||
id: json['id'] as String,
|
||||
organizationId: json['organization_id'] as String,
|
||||
userId: json['user_id'] as String,
|
||||
fileName: json['file_name'] as String,
|
||||
originalName: json['original_name'] as String,
|
||||
fileUrl: json['file_url'] as String,
|
||||
fileSize: json['file_size'] as int,
|
||||
mimeType: json['mime_type'] as String,
|
||||
fileType: json['file_type'] as String,
|
||||
uploadPath: json['upload_path'] as String,
|
||||
isPublic: json['is_public'] as bool,
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'organization_id': organizationId,
|
||||
'user_id': userId,
|
||||
'file_name': fileName,
|
||||
'original_name': originalName,
|
||||
'file_url': fileUrl,
|
||||
'file_size': fileSize,
|
||||
'mime_type': mimeType,
|
||||
'file_type': fileType,
|
||||
'upload_path': uploadPath,
|
||||
'is_public': isPublic,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
'updated_at': updatedAt.toIso8601String(),
|
||||
};
|
||||
|
||||
factory FileModel.fromMap(Map<String, dynamic> map) =>
|
||||
FileModel.fromJson(map);
|
||||
|
||||
Map<String, dynamic> toMap() => toJson();
|
||||
|
||||
FileModel copyWith({
|
||||
String? id,
|
||||
String? organizationId,
|
||||
String? userId,
|
||||
String? fileName,
|
||||
String? originalName,
|
||||
String? fileUrl,
|
||||
int? fileSize,
|
||||
String? mimeType,
|
||||
String? fileType,
|
||||
String? uploadPath,
|
||||
bool? isPublic,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return FileModel(
|
||||
id: id ?? this.id,
|
||||
organizationId: organizationId ?? this.organizationId,
|
||||
userId: userId ?? this.userId,
|
||||
fileName: fileName ?? this.fileName,
|
||||
originalName: originalName ?? this.originalName,
|
||||
fileUrl: fileUrl ?? this.fileUrl,
|
||||
fileSize: fileSize ?? this.fileSize,
|
||||
mimeType: mimeType ?? this.mimeType,
|
||||
fileType: fileType ?? this.fileType,
|
||||
uploadPath: uploadPath ?? this.uploadPath,
|
||||
isPublic: isPublic ?? this.isPublic,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FileModel(id: $id, organizationId: $organizationId, userId: $userId, fileName: $fileName, originalName: $originalName, fileUrl: $fileUrl, fileSize: $fileSize, mimeType: $mimeType, fileType: $fileType, uploadPath: $uploadPath, isPublic: $isPublic, createdAt: $createdAt, updatedAt: $updatedAt)';
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:developer';
|
||||
import 'package:enaklo_pos/core/constants/theme.dart';
|
||||
import 'package:enaklo_pos/data/datasources/customer_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/datasources/file_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/datasources/outlet_remote_data_source.dart';
|
||||
import 'package:enaklo_pos/data/datasources/table_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/datasources/user_remote_datasource.dart';
|
||||
@ -14,6 +15,7 @@ import 'package:enaklo_pos/presentation/home/bloc/user_update_outlet/user_update
|
||||
import 'package:enaklo_pos/presentation/refund/bloc/refund_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/sales/blocs/order_loader/order_loader_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/sales/blocs/payment_form/payment_form_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/setting/bloc/upload_file/upload_file_bloc.dart';
|
||||
import 'package:enaklo_pos/presentation/void/bloc/void_order_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
|
||||
@ -265,6 +267,9 @@ class _MyAppState extends State<MyApp> {
|
||||
BlocProvider(
|
||||
create: (context) => UserUpdateOutletBloc(UserRemoteDatasource()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => UploadFileBloc(FileRemoteDataSource()),
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:enaklo_pos/data/datasources/product_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/request/product_request_model.dart';
|
||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
part 'add_product_event.dart';
|
||||
part 'add_product_state.dart';
|
||||
@ -18,21 +14,12 @@ class AddProductBloc extends Bloc<AddProductEvent, AddProductState> {
|
||||
) : super(const _Initial()) {
|
||||
on<_AddProduct>((event, emit) async {
|
||||
emit(const _Loading());
|
||||
final requestData = ProductRequestModel(
|
||||
name: event.product.name!,
|
||||
price: event.product.price!,
|
||||
stock: 0,
|
||||
categoryId: 0,
|
||||
isBestSeller: 0,
|
||||
image: event.image,
|
||||
);
|
||||
log("requestData: ${requestData.toString()}");
|
||||
final response = await datasource.addProduct(requestData);
|
||||
final response = await datasource.addProduct(event.product);
|
||||
// products.add(newProduct);
|
||||
response.fold(
|
||||
(l) => emit(_Error(l)),
|
||||
(r) {
|
||||
emit(_Success('Add Product Success'));
|
||||
emit(_Success('Produk berhasil ditambahkan'));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -19,19 +19,19 @@ mixin _$AddProductEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function(Product product, XFile image) addProduct,
|
||||
required TResult Function(ProductRequestModel product) addProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function(Product product, XFile image)? addProduct,
|
||||
TResult? Function(ProductRequestModel product)? addProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function(Product product, XFile image)? addProduct,
|
||||
TResult Function(ProductRequestModel product)? addProduct,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@ -119,7 +119,7 @@ class _$StartedImpl implements _Started {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function(Product product, XFile image) addProduct,
|
||||
required TResult Function(ProductRequestModel product) addProduct,
|
||||
}) {
|
||||
return started();
|
||||
}
|
||||
@ -128,7 +128,7 @@ class _$StartedImpl implements _Started {
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function(Product product, XFile image)? addProduct,
|
||||
TResult? Function(ProductRequestModel product)? addProduct,
|
||||
}) {
|
||||
return started?.call();
|
||||
}
|
||||
@ -137,7 +137,7 @@ class _$StartedImpl implements _Started {
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function(Product product, XFile image)? addProduct,
|
||||
TResult Function(ProductRequestModel product)? addProduct,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (started != null) {
|
||||
@ -188,7 +188,7 @@ abstract class _$$AddProductImplCopyWith<$Res> {
|
||||
_$AddProductImpl value, $Res Function(_$AddProductImpl) then) =
|
||||
__$$AddProductImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({Product product, XFile image});
|
||||
$Res call({ProductRequestModel product});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -205,17 +205,12 @@ class __$$AddProductImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? product = null,
|
||||
Object? image = null,
|
||||
}) {
|
||||
return _then(_$AddProductImpl(
|
||||
null == product
|
||||
? _value.product
|
||||
: product // ignore: cast_nullable_to_non_nullable
|
||||
as Product,
|
||||
null == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as XFile,
|
||||
as ProductRequestModel,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -223,16 +218,14 @@ class __$$AddProductImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
|
||||
class _$AddProductImpl implements _AddProduct {
|
||||
const _$AddProductImpl(this.product, this.image);
|
||||
const _$AddProductImpl(this.product);
|
||||
|
||||
@override
|
||||
final Product product;
|
||||
@override
|
||||
final XFile image;
|
||||
final ProductRequestModel product;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AddProductEvent.addProduct(product: $product, image: $image)';
|
||||
return 'AddProductEvent.addProduct(product: $product)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -240,12 +233,11 @@ class _$AddProductImpl implements _AddProduct {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$AddProductImpl &&
|
||||
(identical(other.product, product) || other.product == product) &&
|
||||
(identical(other.image, image) || other.image == image));
|
||||
(identical(other.product, product) || other.product == product));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, product, image);
|
||||
int get hashCode => Object.hash(runtimeType, product);
|
||||
|
||||
/// Create a copy of AddProductEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@ -259,29 +251,29 @@ class _$AddProductImpl implements _AddProduct {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() started,
|
||||
required TResult Function(Product product, XFile image) addProduct,
|
||||
required TResult Function(ProductRequestModel product) addProduct,
|
||||
}) {
|
||||
return addProduct(product, image);
|
||||
return addProduct(product);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? started,
|
||||
TResult? Function(Product product, XFile image)? addProduct,
|
||||
TResult? Function(ProductRequestModel product)? addProduct,
|
||||
}) {
|
||||
return addProduct?.call(product, image);
|
||||
return addProduct?.call(product);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? started,
|
||||
TResult Function(Product product, XFile image)? addProduct,
|
||||
TResult Function(ProductRequestModel product)? addProduct,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (addProduct != null) {
|
||||
return addProduct(product, image);
|
||||
return addProduct(product);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
@ -319,11 +311,10 @@ class _$AddProductImpl implements _AddProduct {
|
||||
}
|
||||
|
||||
abstract class _AddProduct implements AddProductEvent {
|
||||
const factory _AddProduct(final Product product, final XFile image) =
|
||||
const factory _AddProduct(final ProductRequestModel product) =
|
||||
_$AddProductImpl;
|
||||
|
||||
Product get product;
|
||||
XFile get image;
|
||||
ProductRequestModel get product;
|
||||
|
||||
/// Create a copy of AddProductEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@ -3,6 +3,6 @@ part of 'add_product_bloc.dart';
|
||||
@freezed
|
||||
class AddProductEvent with _$AddProductEvent {
|
||||
const factory AddProductEvent.started() = _Started;
|
||||
const factory AddProductEvent.addProduct(Product product, XFile image) =
|
||||
const factory AddProductEvent.addProduct(ProductRequestModel product) =
|
||||
_AddProduct;
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:enaklo_pos/data/datasources/category_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/response/category_response_model.dart';
|
||||
@ -15,11 +14,11 @@ class GetCategoriesBloc extends Bloc<GetCategoriesEvent, GetCategoriesState> {
|
||||
) : super(const _Initial()) {
|
||||
on<_Fetch>((event, emit) async {
|
||||
emit(const _Loading());
|
||||
final result = await datasource.getCategories();
|
||||
final result = await datasource.getCategories(limit: 50);
|
||||
result.fold(
|
||||
(l) => emit(_Error(l)),
|
||||
(r) async {
|
||||
emit(_Success(r.data));
|
||||
emit(_Success(r.data.categories));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:enaklo_pos/data/datasources/product_local_datasource.dart';
|
||||
import 'package:enaklo_pos/data/datasources/product_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/request/product_request_model.dart';
|
||||
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
part 'update_product_event.dart';
|
||||
part 'update_product_state.dart';
|
||||
@ -21,61 +18,11 @@ class UpdateProductBloc extends Bloc<UpdateProductEvent, UpdateProductState> {
|
||||
emit(const _Loading());
|
||||
|
||||
try {
|
||||
// Validate required fields
|
||||
if (event.product.name == null || event.product.name!.isEmpty) {
|
||||
emit(_Error('Product name is required'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.product.price == null || event.product.price == 0) {
|
||||
emit(_Error('Product price is required'));
|
||||
return;
|
||||
}
|
||||
|
||||
// if (event.product.stock == null) {
|
||||
// emit(_Error('Product stock is required'));
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (event.product.categoryId == null) {
|
||||
emit(_Error('Product category is required'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse price safely
|
||||
final price = event.product.price!;
|
||||
if (price == 0) {
|
||||
emit(_Error('Invalid price format'));
|
||||
return;
|
||||
}
|
||||
|
||||
final requestData = ProductRequestModel(
|
||||
id: event.product.id,
|
||||
name: event.product.name!,
|
||||
price: price,
|
||||
stock: 0,
|
||||
categoryId: 0,
|
||||
isBestSeller: 0, // Default to 0 if null
|
||||
image: event.image,
|
||||
printerType: 'kitchen', // Default to kitchen if null
|
||||
);
|
||||
|
||||
log("Update requestData: ${requestData.toString()}");
|
||||
log("Request map: ${requestData.toMap()}");
|
||||
|
||||
final response = await datasource.updateProduct(requestData);
|
||||
final response = await datasource.updateProduct(event.product);
|
||||
response.fold(
|
||||
(l) => emit(_Error(l)),
|
||||
(r) async {
|
||||
// Update local database after successful API update
|
||||
try {
|
||||
await ProductLocalDatasource.instance
|
||||
.updateProduct(event.product);
|
||||
log("Local product updated successfully");
|
||||
} catch (e) {
|
||||
log("Error updating local product: $e");
|
||||
}
|
||||
emit(_Success('Update Product Success'));
|
||||
emit(_Success('Product berhasil diupdate'));
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
|
||||
@ -16,21 +16,20 @@ final _privateConstructorUsedError = UnsupportedError(
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UpdateProductEvent {
|
||||
Product get product => throw _privateConstructorUsedError;
|
||||
XFile? get image => throw _privateConstructorUsedError;
|
||||
ProductRequestModel get product => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(Product product, XFile? image) updateProduct,
|
||||
required TResult Function(ProductRequestModel product) updateProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(Product product, XFile? image)? updateProduct,
|
||||
TResult? Function(ProductRequestModel product)? updateProduct,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(Product product, XFile? image)? updateProduct,
|
||||
TResult Function(ProductRequestModel product)? updateProduct,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@ -64,7 +63,7 @@ abstract class $UpdateProductEventCopyWith<$Res> {
|
||||
UpdateProductEvent value, $Res Function(UpdateProductEvent) then) =
|
||||
_$UpdateProductEventCopyWithImpl<$Res, UpdateProductEvent>;
|
||||
@useResult
|
||||
$Res call({Product product, XFile? image});
|
||||
$Res call({ProductRequestModel product});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -83,17 +82,12 @@ class _$UpdateProductEventCopyWithImpl<$Res, $Val extends UpdateProductEvent>
|
||||
@override
|
||||
$Res call({
|
||||
Object? product = null,
|
||||
Object? image = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
product: null == product
|
||||
? _value.product
|
||||
: product // ignore: cast_nullable_to_non_nullable
|
||||
as Product,
|
||||
image: freezed == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as XFile?,
|
||||
as ProductRequestModel,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@ -106,7 +100,7 @@ abstract class _$$UpdateProductImplCopyWith<$Res>
|
||||
__$$UpdateProductImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({Product product, XFile? image});
|
||||
$Res call({ProductRequestModel product});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -123,17 +117,12 @@ class __$$UpdateProductImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? product = null,
|
||||
Object? image = freezed,
|
||||
}) {
|
||||
return _then(_$UpdateProductImpl(
|
||||
null == product
|
||||
? _value.product
|
||||
: product // ignore: cast_nullable_to_non_nullable
|
||||
as Product,
|
||||
freezed == image
|
||||
? _value.image
|
||||
: image // ignore: cast_nullable_to_non_nullable
|
||||
as XFile?,
|
||||
as ProductRequestModel,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -141,16 +130,14 @@ class __$$UpdateProductImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
|
||||
class _$UpdateProductImpl implements _UpdateProduct {
|
||||
const _$UpdateProductImpl(this.product, this.image);
|
||||
const _$UpdateProductImpl(this.product);
|
||||
|
||||
@override
|
||||
final Product product;
|
||||
@override
|
||||
final XFile? image;
|
||||
final ProductRequestModel product;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdateProductEvent.updateProduct(product: $product, image: $image)';
|
||||
return 'UpdateProductEvent.updateProduct(product: $product)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -158,12 +145,11 @@ class _$UpdateProductImpl implements _UpdateProduct {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UpdateProductImpl &&
|
||||
(identical(other.product, product) || other.product == product) &&
|
||||
(identical(other.image, image) || other.image == image));
|
||||
(identical(other.product, product) || other.product == product));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, product, image);
|
||||
int get hashCode => Object.hash(runtimeType, product);
|
||||
|
||||
/// Create a copy of UpdateProductEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@ -176,27 +162,27 @@ class _$UpdateProductImpl implements _UpdateProduct {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(Product product, XFile? image) updateProduct,
|
||||
required TResult Function(ProductRequestModel product) updateProduct,
|
||||
}) {
|
||||
return updateProduct(product, image);
|
||||
return updateProduct(product);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(Product product, XFile? image)? updateProduct,
|
||||
TResult? Function(ProductRequestModel product)? updateProduct,
|
||||
}) {
|
||||
return updateProduct?.call(product, image);
|
||||
return updateProduct?.call(product);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(Product product, XFile? image)? updateProduct,
|
||||
TResult Function(ProductRequestModel product)? updateProduct,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updateProduct != null) {
|
||||
return updateProduct(product, image);
|
||||
return updateProduct(product);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
@ -231,13 +217,11 @@ class _$UpdateProductImpl implements _UpdateProduct {
|
||||
}
|
||||
|
||||
abstract class _UpdateProduct implements UpdateProductEvent {
|
||||
const factory _UpdateProduct(final Product product, final XFile? image) =
|
||||
const factory _UpdateProduct(final ProductRequestModel product) =
|
||||
_$UpdateProductImpl;
|
||||
|
||||
@override
|
||||
Product get product;
|
||||
@override
|
||||
XFile? get image;
|
||||
ProductRequestModel get product;
|
||||
|
||||
/// Create a copy of UpdateProductEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@ -2,5 +2,6 @@ part of 'update_product_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class UpdateProductEvent with _$UpdateProductEvent {
|
||||
const factory UpdateProductEvent.updateProduct(Product product, XFile? image) = _UpdateProduct;
|
||||
}
|
||||
const factory UpdateProductEvent.updateProduct(ProductRequestModel product) =
|
||||
_UpdateProduct;
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:enaklo_pos/data/datasources/file_remote_datasource.dart';
|
||||
import 'package:enaklo_pos/data/models/response/file_response_model.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'upload_file_event.dart';
|
||||
part 'upload_file_state.dart';
|
||||
part 'upload_file_bloc.freezed.dart';
|
||||
|
||||
class UploadFileBloc extends Bloc<UploadFileEvent, UploadFileState> {
|
||||
final FileRemoteDataSource _fileRemoteDataSource;
|
||||
UploadFileBloc(this._fileRemoteDataSource)
|
||||
: super(UploadFileState.initial()) {
|
||||
on<_Upload>((event, emit) async {
|
||||
emit(_Loading());
|
||||
final result = await _fileRemoteDataSource.uploadFile(
|
||||
filePath: event.filePath,
|
||||
fileType: 'image',
|
||||
description: 'Product Image',
|
||||
);
|
||||
|
||||
result.fold((l) {
|
||||
emit(_Error(l));
|
||||
}, (r) {
|
||||
emit(_Success(r.data));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,845 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'upload_file_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UploadFileEvent {
|
||||
String get filePath => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(String filePath) upload,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(String filePath)? upload,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(String filePath)? upload,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Upload value) upload,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Upload value)? upload,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Upload value)? upload,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of UploadFileEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$UploadFileEventCopyWith<UploadFileEvent> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UploadFileEventCopyWith<$Res> {
|
||||
factory $UploadFileEventCopyWith(
|
||||
UploadFileEvent value, $Res Function(UploadFileEvent) then) =
|
||||
_$UploadFileEventCopyWithImpl<$Res, UploadFileEvent>;
|
||||
@useResult
|
||||
$Res call({String filePath});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UploadFileEventCopyWithImpl<$Res, $Val extends UploadFileEvent>
|
||||
implements $UploadFileEventCopyWith<$Res> {
|
||||
_$UploadFileEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of UploadFileEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? filePath = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
filePath: null == filePath
|
||||
? _value.filePath
|
||||
: filePath // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$UploadImplCopyWith<$Res>
|
||||
implements $UploadFileEventCopyWith<$Res> {
|
||||
factory _$$UploadImplCopyWith(
|
||||
_$UploadImpl value, $Res Function(_$UploadImpl) then) =
|
||||
__$$UploadImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String filePath});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UploadImplCopyWithImpl<$Res>
|
||||
extends _$UploadFileEventCopyWithImpl<$Res, _$UploadImpl>
|
||||
implements _$$UploadImplCopyWith<$Res> {
|
||||
__$$UploadImplCopyWithImpl(
|
||||
_$UploadImpl _value, $Res Function(_$UploadImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UploadFileEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? filePath = null,
|
||||
}) {
|
||||
return _then(_$UploadImpl(
|
||||
null == filePath
|
||||
? _value.filePath
|
||||
: filePath // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$UploadImpl implements _Upload {
|
||||
const _$UploadImpl(this.filePath);
|
||||
|
||||
@override
|
||||
final String filePath;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UploadFileEvent.upload(filePath: $filePath)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UploadImpl &&
|
||||
(identical(other.filePath, filePath) ||
|
||||
other.filePath == filePath));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, filePath);
|
||||
|
||||
/// Create a copy of UploadFileEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UploadImplCopyWith<_$UploadImpl> get copyWith =>
|
||||
__$$UploadImplCopyWithImpl<_$UploadImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(String filePath) upload,
|
||||
}) {
|
||||
return upload(filePath);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(String filePath)? upload,
|
||||
}) {
|
||||
return upload?.call(filePath);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(String filePath)? upload,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (upload != null) {
|
||||
return upload(filePath);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Upload value) upload,
|
||||
}) {
|
||||
return upload(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Upload value)? upload,
|
||||
}) {
|
||||
return upload?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Upload value)? upload,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (upload != null) {
|
||||
return upload(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Upload implements UploadFileEvent {
|
||||
const factory _Upload(final String filePath) = _$UploadImpl;
|
||||
|
||||
@override
|
||||
String get filePath;
|
||||
|
||||
/// Create a copy of UploadFileEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$UploadImplCopyWith<_$UploadImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$UploadFileState {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(FileModel file) success,
|
||||
required TResult Function(String message) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(FileModel file)? success,
|
||||
TResult? Function(String message)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(FileModel file)? success,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Success value) success,
|
||||
required TResult Function(_Error value) error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Success value)? success,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Success value)? success,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $UploadFileStateCopyWith<$Res> {
|
||||
factory $UploadFileStateCopyWith(
|
||||
UploadFileState value, $Res Function(UploadFileState) then) =
|
||||
_$UploadFileStateCopyWithImpl<$Res, UploadFileState>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$UploadFileStateCopyWithImpl<$Res, $Val extends UploadFileState>
|
||||
implements $UploadFileStateCopyWith<$Res> {
|
||||
_$UploadFileStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$InitialImplCopyWith<$Res> {
|
||||
factory _$$InitialImplCopyWith(
|
||||
_$InitialImpl value, $Res Function(_$InitialImpl) then) =
|
||||
__$$InitialImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$InitialImplCopyWithImpl<$Res>
|
||||
extends _$UploadFileStateCopyWithImpl<$Res, _$InitialImpl>
|
||||
implements _$$InitialImplCopyWith<$Res> {
|
||||
__$$InitialImplCopyWithImpl(
|
||||
_$InitialImpl _value, $Res Function(_$InitialImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$InitialImpl implements _Initial {
|
||||
const _$InitialImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UploadFileState.initial()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$InitialImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(FileModel file) success,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return initial();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(FileModel file)? success,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return initial?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(FileModel file)? success,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Success value) success,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return initial(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Success value)? success,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return initial?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Success value)? success,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
return initial(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Initial implements UploadFileState {
|
||||
const factory _Initial() = _$InitialImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LoadingImplCopyWith<$Res> {
|
||||
factory _$$LoadingImplCopyWith(
|
||||
_$LoadingImpl value, $Res Function(_$LoadingImpl) then) =
|
||||
__$$LoadingImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LoadingImplCopyWithImpl<$Res>
|
||||
extends _$UploadFileStateCopyWithImpl<$Res, _$LoadingImpl>
|
||||
implements _$$LoadingImplCopyWith<$Res> {
|
||||
__$$LoadingImplCopyWithImpl(
|
||||
_$LoadingImpl _value, $Res Function(_$LoadingImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LoadingImpl implements _Loading {
|
||||
const _$LoadingImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UploadFileState.loading()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$LoadingImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(FileModel file) success,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return loading();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(FileModel file)? success,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return loading?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(FileModel file)? success,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Success value) success,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return loading(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Success value)? success,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return loading?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Success value)? success,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (loading != null) {
|
||||
return loading(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Loading implements UploadFileState {
|
||||
const factory _Loading() = _$LoadingImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SuccessImplCopyWith<$Res> {
|
||||
factory _$$SuccessImplCopyWith(
|
||||
_$SuccessImpl value, $Res Function(_$SuccessImpl) then) =
|
||||
__$$SuccessImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({FileModel file});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SuccessImplCopyWithImpl<$Res>
|
||||
extends _$UploadFileStateCopyWithImpl<$Res, _$SuccessImpl>
|
||||
implements _$$SuccessImplCopyWith<$Res> {
|
||||
__$$SuccessImplCopyWithImpl(
|
||||
_$SuccessImpl _value, $Res Function(_$SuccessImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? file = null,
|
||||
}) {
|
||||
return _then(_$SuccessImpl(
|
||||
null == file
|
||||
? _value.file
|
||||
: file // ignore: cast_nullable_to_non_nullable
|
||||
as FileModel,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SuccessImpl implements _Success {
|
||||
const _$SuccessImpl(this.file);
|
||||
|
||||
@override
|
||||
final FileModel file;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UploadFileState.success(file: $file)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SuccessImpl &&
|
||||
(identical(other.file, file) || other.file == file));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, file);
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SuccessImplCopyWith<_$SuccessImpl> get copyWith =>
|
||||
__$$SuccessImplCopyWithImpl<_$SuccessImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(FileModel file) success,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return success(file);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(FileModel file)? success,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return success?.call(file);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(FileModel file)? success,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (success != null) {
|
||||
return success(file);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Success value) success,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return success(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Success value)? success,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return success?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Success value)? success,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (success != null) {
|
||||
return success(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Success implements UploadFileState {
|
||||
const factory _Success(final FileModel file) = _$SuccessImpl;
|
||||
|
||||
FileModel get file;
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SuccessImplCopyWith<_$SuccessImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ErrorImplCopyWith<$Res> {
|
||||
factory _$$ErrorImplCopyWith(
|
||||
_$ErrorImpl value, $Res Function(_$ErrorImpl) then) =
|
||||
__$$ErrorImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String message});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ErrorImplCopyWithImpl<$Res>
|
||||
extends _$UploadFileStateCopyWithImpl<$Res, _$ErrorImpl>
|
||||
implements _$$ErrorImplCopyWith<$Res> {
|
||||
__$$ErrorImplCopyWithImpl(
|
||||
_$ErrorImpl _value, $Res Function(_$ErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? message = null,
|
||||
}) {
|
||||
return _then(_$ErrorImpl(
|
||||
null == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ErrorImpl implements _Error {
|
||||
const _$ErrorImpl(this.message);
|
||||
|
||||
@override
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UploadFileState.error(message: $message)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ErrorImpl &&
|
||||
(identical(other.message, message) || other.message == message));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, message);
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
|
||||
__$$ErrorImplCopyWithImpl<_$ErrorImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function() loading,
|
||||
required TResult Function(FileModel file) success,
|
||||
required TResult Function(String message) error,
|
||||
}) {
|
||||
return error(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? initial,
|
||||
TResult? Function()? loading,
|
||||
TResult? Function(FileModel file)? success,
|
||||
TResult? Function(String message)? error,
|
||||
}) {
|
||||
return error?.call(message);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function()? loading,
|
||||
TResult Function(FileModel file)? success,
|
||||
TResult Function(String message)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(message);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Initial value) initial,
|
||||
required TResult Function(_Loading value) loading,
|
||||
required TResult Function(_Success value) success,
|
||||
required TResult Function(_Error value) error,
|
||||
}) {
|
||||
return error(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Initial value)? initial,
|
||||
TResult? Function(_Loading value)? loading,
|
||||
TResult? Function(_Success value)? success,
|
||||
TResult? Function(_Error value)? error,
|
||||
}) {
|
||||
return error?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Initial value)? initial,
|
||||
TResult Function(_Loading value)? loading,
|
||||
TResult Function(_Success value)? success,
|
||||
TResult Function(_Error value)? error,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (error != null) {
|
||||
return error(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Error implements UploadFileState {
|
||||
const factory _Error(final String message) = _$ErrorImpl;
|
||||
|
||||
String get message;
|
||||
|
||||
/// Create a copy of UploadFileState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ErrorImplCopyWith<_$ErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
part of 'upload_file_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class UploadFileEvent with _$UploadFileEvent {
|
||||
const factory UploadFileEvent.upload(String filePath) = _Upload;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
part of 'upload_file_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class UploadFileState with _$UploadFileState {
|
||||
const factory UploadFileState.initial() = _Initial;
|
||||
const factory UploadFileState.loading() = _Loading;
|
||||
const factory UploadFileState.success(FileModel file) = _Success;
|
||||
const factory UploadFileState.error(String message) = _Error;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -58,18 +58,18 @@ class _SyncDataPageState extends State<SyncDataPage> {
|
||||
);
|
||||
},
|
||||
loaded: (productResponseModel) async {
|
||||
await ProductLocalDatasource.instance
|
||||
.deleteAllProducts();
|
||||
await ProductLocalDatasource.instance
|
||||
.insertProducts(
|
||||
productResponseModel.data!.products!,
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Sync Product Success2'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
// await ProductLocalDatasource.instance
|
||||
// .deleteAllProducts();
|
||||
// await ProductLocalDatasource.instance
|
||||
// .insertProducts(
|
||||
// productResponseModel.data!.products!,
|
||||
// );
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// const SnackBar(
|
||||
// content: Text('Sync Product Success2'),
|
||||
// backgroundColor: Colors.green,
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -127,12 +127,12 @@ class _SyncDataPageState extends State<SyncDataPage> {
|
||||
);
|
||||
},
|
||||
loaded: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Sync Order Success'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
// ScaffoldMessenger.of(context).showSnackBar(
|
||||
// const SnackBar(
|
||||
// content: Text('Sync Order Success'),
|
||||
// backgroundColor: Colors.green,
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@ -366,6 +366,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
dropdown_search:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dropdown_search
|
||||
sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.6"
|
||||
esc_pos_utils_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@ -62,6 +62,7 @@ dependencies:
|
||||
dio: ^5.8.0+1
|
||||
awesome_dio_interceptor: ^1.3.0
|
||||
another_flushbar: ^1.12.30
|
||||
dropdown_search: ^5.0.6
|
||||
# imin_printer: ^0.6.10
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user