diff --git a/app_petty_cash/android/app/build.gradle b/app_petty_cash/android/app/build.gradle index ed29a90..a97d4f8 100644 --- a/app_petty_cash/android/app/build.gradle +++ b/app_petty_cash/android/app/build.gradle @@ -52,6 +52,7 @@ android { targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } buildTypes { @@ -69,4 +70,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:multidex:1.0.3' } diff --git a/app_petty_cash/android/app/src/main/AndroidManifest.xml b/app_petty_cash/android/app/src/main/AndroidManifest.xml index b54eb58..7144690 100644 --- a/app_petty_cash/android/app/src/main/AndroidManifest.xml +++ b/app_petty_cash/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + (null); + final photoBase64 = useState(""); + final previewLoading = useState(false); + getBase64() async { + // List imageBytes = await photo.value?.readAsBytes(); + if (photo.value != null) { + final bytes = io.File(photo.value!.path).readAsBytesSync(); + String base64Image = base64Encode(bytes); + photoBase64.value = base64Image; + final file = File(photo.value!.path); + print(file.lengthSync() / 1000000); + print(await photo.value!.length()); + + // await getExternalStorageDirectory(); + // print(await photo.value!.saveTo(path)); + print(base64Image); + } + } + + final ImagePicker _picker = ImagePicker(); + pickImage() async { + previewLoading.value = true; + final XFile? pickedFile = await _picker.pickImage( + source: ImageSource.camera, + ); + photo.value = pickedFile; + // final Directory appDocumentsDir = + // await getApplicationDocumentsDirectory(); + // print(appDocumentsDir); + // await pickedFile!.saveTo(appDocumentsDir.path); + await getBase64(); + previewLoading.value = false; + } + + browseImage() async { + previewLoading.value = true; + + final XFile? pickedFile = await _picker.pickImage( + source: ImageSource.gallery, + ); + photo.value = pickedFile; + getBase64(); + previewLoading.value = false; + } + + return Scaffold( + body: SingleChildScrollView( + child: SafeArea( + minimum: const EdgeInsets.all(20), + child: Column( + children: [ + Container( + height: Constant.getActualYPhone(context: context, y: 500), + width: MediaQuery.of(context).size.width, + color: Colors.red, + child: LayoutBuilder( + builder: (context, constraints) { + final String? mime = + lookupMimeType(photo.value?.path ?? ""); + + return Semantics( + label: 'image_picker_example_picked_image', + child: (mime != null + ? (mime.startsWith('image/')) + ? Image.file( + // image: AssetImage(photo.value!.path), + File(photo.value!.path), + frameBuilder: (context, child, frame, + wasSynchronouslyLoaded) { + return (wasSynchronouslyLoaded) + ? Center( + child: Text("Loadinga"), + ) + : Container( + child: child, + ); + }, + errorBuilder: (BuildContext context, + Object error, StackTrace? stackTrace) { + return const Center( + child: Text( + 'This image type is not supported')); + }, + ) + : null + : null)); + }, + ), + ), + // photo.value != null + // ? PhotoView(imageProvider: AssetImage(photo.value!.path)) + // : Container(), + Row( + children: [ + ElevatedButton( + onPressed: () { + pickImage(); + }, + child: Text("Take a picture")), + ElevatedButton( + onPressed: () { + browseImage(); + }, + child: Text("Browse a picture")) + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/app_petty_cash/lib/screen/camera/example.dart b/app_petty_cash/lib/screen/camera/example.dart new file mode 100644 index 0000000..e792072 --- /dev/null +++ b/app_petty_cash/lib/screen/camera/example.dart @@ -0,0 +1,542 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:mime/mime.dart'; +import 'package:video_player/video_player.dart'; + +class CamerExample extends StatefulWidget { + const CamerExample({super.key}); + + @override + State createState() => _CamerExampleState(); +} + +class _CamerExampleState extends State { + List? _mediaFileList; + + void _setImageFileListFromFile(XFile? value) { + _mediaFileList = value == null ? null : [value]; + } + + dynamic _pickImageError; + bool isVideo = false; + + VideoPlayerController? _controller; + VideoPlayerController? _toBeDisposed; + String? _retrieveDataError; + + final ImagePicker _picker = ImagePicker(); + final TextEditingController maxWidthController = TextEditingController(); + final TextEditingController maxHeightController = TextEditingController(); + final TextEditingController qualityController = TextEditingController(); + + Future _playVideo(XFile? file) async { + if (file != null && mounted) { + await _disposeVideoController(); + late VideoPlayerController controller; + if (kIsWeb) { + controller = VideoPlayerController.networkUrl(Uri.parse(file.path)); + } else { + controller = VideoPlayerController.file(File(file.path)); + } + _controller = controller; + // In web, most browsers won't honor a programmatic call to .play + // if the video has a sound track (and is not muted). + // Mute the video so it auto-plays in web! + // This is not needed if the call to .play is the result of user + // interaction (clicking on a "play" button, for example). + const double volume = kIsWeb ? 0.0 : 1.0; + await controller.setVolume(volume); + await controller.initialize(); + await controller.setLooping(true); + await controller.play(); + setState(() {}); + } + } + + Future _onImageButtonPressed( + ImageSource source, { + required BuildContext context, + bool isMultiImage = false, + bool isMedia = false, + }) async { + if (_controller != null) { + await _controller!.setVolume(0.0); + } + if (context.mounted) { + if (isVideo) { + final XFile? file = await _picker.pickVideo( + source: source, maxDuration: const Duration(seconds: 10)); + await _playVideo(file); + } else if (isMultiImage) { + await _displayPickImageDialog(context, + (double? maxWidth, double? maxHeight, int? quality) async { + try { + final List pickedFileList = isMedia + ? await _picker.pickMultipleMedia( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ) + : await _picker.pickMultiImage( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); + setState(() { + _mediaFileList = pickedFileList; + }); + } catch (e) { + setState(() { + _pickImageError = e; + }); + } + }); + } else if (isMedia) { + await _displayPickImageDialog(context, + (double? maxWidth, double? maxHeight, int? quality) async { + try { + final List pickedFileList = []; + final XFile? media = await _picker.pickMedia( + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); + if (media != null) { + pickedFileList.add(media); + setState(() { + _mediaFileList = pickedFileList; + }); + } + } catch (e) { + setState(() { + _pickImageError = e; + }); + } + }); + } else { + await _displayPickImageDialog(context, + (double? maxWidth, double? maxHeight, int? quality) async { + try { + final XFile? pickedFile = await _picker.pickImage( + source: source, + maxWidth: maxWidth, + maxHeight: maxHeight, + imageQuality: quality, + ); + setState(() { + _setImageFileListFromFile(pickedFile); + }); + } catch (e) { + setState(() { + _pickImageError = e; + }); + } + }); + } + } + } + + @override + void deactivate() { + if (_controller != null) { + _controller!.setVolume(0.0); + _controller!.pause(); + } + super.deactivate(); + } + + @override + void dispose() { + _disposeVideoController(); + maxWidthController.dispose(); + maxHeightController.dispose(); + qualityController.dispose(); + super.dispose(); + } + + Future _disposeVideoController() async { + if (_toBeDisposed != null) { + await _toBeDisposed!.dispose(); + } + _toBeDisposed = _controller; + _controller = null; + } + + Widget _previewVideo() { + final Text? retrieveError = _getRetrieveErrorWidget(); + if (retrieveError != null) { + return retrieveError; + } + if (_controller == null) { + return const Text( + 'You have not yet picked a video', + textAlign: TextAlign.center, + ); + } + return Padding( + padding: const EdgeInsets.all(10.0), + child: AspectRatioVideo(_controller), + ); + } + + Widget _previewImages() { + final Text? retrieveError = _getRetrieveErrorWidget(); + if (retrieveError != null) { + return retrieveError; + } + if (_mediaFileList != null) { + return Semantics( + label: 'image_picker_example_picked_images', + child: ListView.builder( + key: UniqueKey(), + itemBuilder: (BuildContext context, int index) { + final String? mime = lookupMimeType(_mediaFileList![index].path); + + // Why network for web? + // See https://pub.dev/packages/image_picker_for_web#limitations-on-the-web-platform + return Semantics( + label: 'image_picker_example_picked_image', + child: kIsWeb + ? Image.network(_mediaFileList![index].path) + : (mime == null || mime.startsWith('image/') + ? Image.file( + File(_mediaFileList![index].path), + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return const Center( + child: + Text('This image type is not supported')); + }, + ) + : _buildInlineVideoPlayer(index)), + ); + }, + itemCount: _mediaFileList!.length, + ), + ); + } else if (_pickImageError != null) { + return Text( + 'Pick image error: $_pickImageError', + textAlign: TextAlign.center, + ); + } else { + return const Text( + 'You have not yet picked an image.', + textAlign: TextAlign.center, + ); + } + } + + Widget _buildInlineVideoPlayer(int index) { + final VideoPlayerController controller = + VideoPlayerController.file(File(_mediaFileList![index].path)); + const double volume = kIsWeb ? 0.0 : 1.0; + controller.setVolume(volume); + controller.initialize(); + controller.setLooping(true); + controller.play(); + return Center(child: AspectRatioVideo(controller)); + } + + Widget _handlePreview() { + if (isVideo) { + return _previewVideo(); + } else { + return _previewImages(); + } + } + + Future retrieveLostData() async { + final LostDataResponse response = await _picker.retrieveLostData(); + if (response.isEmpty) { + return; + } + if (response.file != null) { + if (response.type == RetrieveType.video) { + isVideo = true; + await _playVideo(response.file); + } else { + isVideo = false; + setState(() { + if (response.files == null) { + _setImageFileListFromFile(response.file); + } else { + _mediaFileList = response.files; + } + }); + } + } else { + _retrieveDataError = response.exception!.code; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Camera example"), + ), + body: Center( + child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android + ? FutureBuilder( + future: retrieveLostData(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.none: + case ConnectionState.waiting: + return const Text( + 'You have not yet picked an image.', + textAlign: TextAlign.center, + ); + case ConnectionState.done: + return _handlePreview(); + case ConnectionState.active: + if (snapshot.hasError) { + return Text( + 'Pick image/video error: ${snapshot.error}}', + textAlign: TextAlign.center, + ); + } else { + return const Text( + 'You have not yet picked an image.', + textAlign: TextAlign.center, + ); + } + } + }, + ) + : _handlePreview(), + ), + floatingActionButton: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Semantics( + label: 'image_picker_example_from_gallery', + child: FloatingActionButton( + onPressed: () { + isVideo = false; + _onImageButtonPressed(ImageSource.gallery, context: context); + }, + heroTag: 'image0', + tooltip: 'Pick Image from gallery', + child: const Icon(Icons.photo), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + onPressed: () { + isVideo = false; + _onImageButtonPressed( + ImageSource.gallery, + context: context, + isMultiImage: true, + isMedia: true, + ); + }, + heroTag: 'multipleMedia', + tooltip: 'Pick Multiple Media from gallery', + child: const Icon(Icons.photo_library), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + onPressed: () { + isVideo = false; + _onImageButtonPressed( + ImageSource.gallery, + context: context, + isMedia: true, + ); + }, + heroTag: 'media', + tooltip: 'Pick Single Media from gallery', + child: const Icon(Icons.photo_library), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + onPressed: () { + isVideo = false; + _onImageButtonPressed( + ImageSource.gallery, + context: context, + isMultiImage: true, + ); + }, + heroTag: 'image1', + tooltip: 'Pick Multiple Image from gallery', + child: const Icon(Icons.photo_library), + ), + ), + if (_picker.supportsImageSource(ImageSource.camera)) + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + onPressed: () { + isVideo = false; + _onImageButtonPressed(ImageSource.camera, context: context); + }, + heroTag: 'image2', + tooltip: 'Take a Photo', + child: const Icon(Icons.camera_alt), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + backgroundColor: Colors.red, + onPressed: () { + isVideo = true; + _onImageButtonPressed(ImageSource.gallery, context: context); + }, + heroTag: 'video0', + tooltip: 'Pick Video from gallery', + child: const Icon(Icons.video_library), + ), + ), + if (_picker.supportsImageSource(ImageSource.camera)) + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: FloatingActionButton( + backgroundColor: Colors.red, + onPressed: () { + isVideo = true; + _onImageButtonPressed(ImageSource.camera, context: context); + }, + heroTag: 'video1', + tooltip: 'Take a Video', + child: const Icon(Icons.videocam), + ), + ), + ], + ), + ); + } + + Text? _getRetrieveErrorWidget() { + if (_retrieveDataError != null) { + final Text result = Text(_retrieveDataError!); + _retrieveDataError = null; + return result; + } + return null; + } + + Future _displayPickImageDialog( + BuildContext context, OnPickImageCallback onPick) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Add optional parameters'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: maxWidthController, + keyboardType: + const TextInputType.numberWithOptions(decimal: true), + decoration: const InputDecoration( + hintText: 'Enter maxWidth if desired'), + ), + TextField( + controller: maxHeightController, + keyboardType: + const TextInputType.numberWithOptions(decimal: true), + decoration: const InputDecoration( + hintText: 'Enter maxHeight if desired'), + ), + TextField( + controller: qualityController, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + hintText: 'Enter quality if desired'), + ), + ], + ), + actions: [ + TextButton( + child: const Text('CANCEL'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: const Text('PICK'), + onPressed: () { + final double? width = maxWidthController.text.isNotEmpty + ? double.parse(maxWidthController.text) + : null; + final double? height = maxHeightController.text.isNotEmpty + ? double.parse(maxHeightController.text) + : null; + final int? quality = qualityController.text.isNotEmpty + ? int.parse(qualityController.text) + : null; + onPick(width, height, quality); + Navigator.of(context).pop(); + }), + ], + ); + }); + } +} + +typedef OnPickImageCallback = void Function( + double? maxWidth, double? maxHeight, int? quality); + +class AspectRatioVideo extends StatefulWidget { + const AspectRatioVideo(this.controller, {super.key}); + + final VideoPlayerController? controller; + + @override + AspectRatioVideoState createState() => AspectRatioVideoState(); +} + +class AspectRatioVideoState extends State { + VideoPlayerController? get controller => widget.controller; + bool initialized = false; + + void _onVideoControllerUpdate() { + if (!mounted) { + return; + } + if (initialized != controller!.value.isInitialized) { + initialized = controller!.value.isInitialized; + setState(() {}); + } + } + + @override + void initState() { + super.initState(); + controller!.addListener(_onVideoControllerUpdate); + } + + @override + void dispose() { + controller!.removeListener(_onVideoControllerUpdate); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (initialized) { + return Center( + child: AspectRatio( + aspectRatio: controller!.value.aspectRatio, + child: VideoPlayer(controller!), + ), + ); + } else { + return Container(); + } + } +} diff --git a/app_petty_cash/lib/screen/report/report_screen.dart b/app_petty_cash/lib/screen/report/report_screen.dart index 75318aa..cf8b5c5 100644 --- a/app_petty_cash/lib/screen/report/report_screen.dart +++ b/app_petty_cash/lib/screen/report/report_screen.dart @@ -254,149 +254,140 @@ class ReportScreen extends HookConsumerWidget { ), ), ), - bottomNavigationBar: Padding( - padding: EdgeInsets.only( - // right: Constant.getActualXPhone(context: context, x: 27), - // left: Constant.getActualXPhone(context: context, x: 27), - // bottom: Constant.getActualYPhone(context: context, y: 32), - top: Constant.getActualYPhone(context: context, y: 10), - ), - child: BottomAppBar( - child: Container( - height: 150, - child: Padding( - padding: EdgeInsets.only( + bottomNavigationBar: BottomAppBar( + height: 150, + child: Container( + child: Padding( + padding: EdgeInsets.only( // right: Constant.getActualXPhone(context: context, x: 27), // left: Constant.getActualXPhone(context: context, x: 27), // bottom: Constant.getActualYPhone(context: context, y: 32), - top: Constant.getActualYPhone(context: context, y: 24), - ), - child: Column( - children: [ - // Excel - Container( - width: Constant.getActualXPhone(context: context, x: 336), - height: Constant.getActualYPhone(context: context, y: 42), - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: MaterialStateColor.resolveWith( - (states) => Colors.white), - // side: MaterialStateBorderSide.resolveWith( - // (states) => BorderSide(color: Colors.green), - // ), + // top: Constant.getActualYPhone(context: context, y: 24), + ), + child: Column( + children: [ + // Excel + Container( + width: Constant.getActualXPhone(context: context, x: 336), + height: Constant.getActualYPhone(context: context, y: 42), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateColor.resolveWith( + (states) => Colors.white), + // side: MaterialStateBorderSide.resolveWith( + // (states) => BorderSide(color: Colors.green), + // ), - // backgroundColor: MaterialStateColor.resolveWith( - // (st) => Constant.pcBtnBackgroundColor), - shape: - MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide( - color: Colors.green, - ), + // backgroundColor: MaterialStateColor.resolveWith( + // (st) => Constant.pcBtnBackgroundColor), + shape: + MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Colors.green, ), ), - shadowColor: - MaterialStateProperty.all(Color(0xffff48423d)), - elevation: MaterialStateProperty.all(4.0), ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: Constant.getActualXPhone( - context: context, x: 16), - height: Constant.getActualYPhone( - context: context, y: 16), - // decoration: BoxDecoration(color: Colors.grey), - child: Image.asset( - "images/logo_excel.png", - fit: BoxFit.fill, - // scale: 1, - ), + shadowColor: + MaterialStateProperty.all(Color(0xffff48423d)), + elevation: MaterialStateProperty.all(4.0), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: Constant.getActualXPhone( + context: context, x: 16), + height: Constant.getActualYPhone( + context: context, y: 16), + // decoration: BoxDecoration(color: Colors.grey), + child: Image.asset( + "images/logo_excel.png", + fit: BoxFit.fill, + // scale: 1, ), - SizedBox( - height: Constant.getActualXPhone( - context: context, x: 8), + ), + SizedBox( + height: Constant.getActualXPhone( + context: context, x: 8), + ), + Text( + 'Download Report (xls) ', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Colors.green, ), - Text( - 'Download Report (xls) ', - style: Constant.body1(context: context).copyWith( + ), + ], + ), + onPressed: () {}, + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // PDF + Container( + width: Constant.getActualXPhone(context: context, x: 336), + height: Constant.getActualYPhone(context: context, y: 42), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateColor.resolveWith( + (st) => Constant.pcBtnBackgroundColor), + shape: + MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Constant.pcBtnBackgroundColor, + ), + ), + ), + shadowColor: + MaterialStateProperty.all(Color(0xffff48423d)), + elevation: MaterialStateProperty.all(4.0), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: Constant.getActualXPhone( + context: context, x: 16), + height: Constant.getActualYPhone( + context: context, y: 16), + // decoration: BoxDecoration(color: Colors.grey), + child: Image.asset( + "images/logo_pdf.png", + fit: BoxFit.fill, + // scale: 1, + ), + ), + SizedBox( + height: Constant.getActualXPhone( + context: context, x: 8), + ), + Text( + 'Download Report (PDF)', + style: Constant.body1(context: context).copyWith( fontWeight: FontWeight.w600, - color: Colors.green, - ), - ), - ], - ), - onPressed: () {}, - ), - ), - - SizedBox( - height: Constant.getActualYPhone(context: context, y: 20), - ), - - // PDF - Container( - width: Constant.getActualXPhone(context: context, x: 336), - height: Constant.getActualYPhone(context: context, y: 42), - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: MaterialStateColor.resolveWith( - (st) => Constant.pcBtnBackgroundColor), - shape: - MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide( - color: Constant.pcBtnBackgroundColor, - ), - ), + color: Constant.white), ), - shadowColor: - MaterialStateProperty.all(Color(0xffff48423d)), - elevation: MaterialStateProperty.all(4.0), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: Constant.getActualXPhone( - context: context, x: 16), - height: Constant.getActualYPhone( - context: context, y: 16), - // decoration: BoxDecoration(color: Colors.grey), - child: Image.asset( - "images/logo_pdf.png", - fit: BoxFit.fill, - // scale: 1, - ), - ), - SizedBox( - height: Constant.getActualXPhone( - context: context, x: 8), - ), - Text( - 'Download Report (PDF)', - style: Constant.body1(context: context).copyWith( - fontWeight: FontWeight.w600, - color: Constant.white), - ), - ], - ), - onPressed: () async { - String url = - "https://pub.dev/packages?q=url+launcher"; - if (!await launchUrl(Uri.parse(url))) { - // throw Exception('Could not launch $url'); - SanckbarWidget(context, 'Could not launch $url', - snackbarType.error); - } - }, + ], ), + onPressed: () async { + String url = "https://pub.dev/packages?q=url+launcher"; + if (!await launchUrl(Uri.parse(url))) { + // throw Exception('Could not launch $url'); + SanckbarWidget(context, 'Could not launch $url', + snackbarType.error); + } + }, ), - ], - ), + ), + ], ), ), ), diff --git a/app_petty_cash/lib/widget/custom_drawer.dart b/app_petty_cash/lib/widget/custom_drawer.dart index 2c352b6..bfbfc94 100644 --- a/app_petty_cash/lib/widget/custom_drawer.dart +++ b/app_petty_cash/lib/widget/custom_drawer.dart @@ -102,7 +102,28 @@ class CustomDrawer extends HookConsumerWidget { // Handle navigation to Home screen Navigator.pop(context); ref.read(currentPageProvider.state).update((state) => 0); - Navigator.pushNamed(context, homeRoute); + // Navigator.pushNamed(context, homeRoute); + Navigator.pushNamed(context, cameraExampleRoute); + }, + ), + ListTile( + title: Text( + 'Coba Camera', + style: TextStyle( + color: (currentMenu == 10) + ? Constant.textWhite + : Constant.textBlack, + ), + ), + tileColor: (currentMenu == 10) + ? Constant.pcBtnBackgroundColor + : Colors.transparent, + onTap: () { + // Handle navigation to Home screen + Navigator.pop(context); + ref.read(currentPageProvider.state).update((state) => 10); + // Navigator.pushNamed(context, homeRoute); + Navigator.pushNamed(context, cobaCameraRoute); }, ), ListTile( diff --git a/app_petty_cash/linux/flutter/generated_plugin_registrant.cc b/app_petty_cash/linux/flutter/generated_plugin_registrant.cc index f6f23bf..7299b5c 100644 --- a/app_petty_cash/linux/flutter/generated_plugin_registrant.cc +++ b/app_petty_cash/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/app_petty_cash/linux/flutter/generated_plugins.cmake b/app_petty_cash/linux/flutter/generated_plugins.cmake index f16b4c3..786ff5c 100644 --- a/app_petty_cash/linux/flutter/generated_plugins.cmake +++ b/app_petty_cash/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux url_launcher_linux ) diff --git a/app_petty_cash/macos/Flutter/GeneratedPluginRegistrant.swift b/app_petty_cash/macos/Flutter/GeneratedPluginRegistrant.swift index 997e35d..a7158a1 100644 --- a/app_petty_cash/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/app_petty_cash/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,16 @@ import FlutterMacOS import Foundation +import file_selector_macos +import path_provider_foundation import shared_preferences_foundation import url_launcher_macos +import video_player_avfoundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) } diff --git a/app_petty_cash/pubspec.lock b/app_petty_cash/pubspec.lock index 4813d03..ec6781f 100644 --- a/app_petty_cash/pubspec.lock +++ b/app_petty_cash/pubspec.lock @@ -65,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + url: "https://pub.dev" + source: hosted + version: "0.3.3+8" crypto: dependency: transitive description: @@ -73,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" cupertino_icons: dependency: "direct main" description: @@ -145,6 +161,38 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" + url: "https://pub.dev" + source: hosted + version: "0.9.2+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" flutter: dependency: "direct main" description: flutter @@ -208,6 +256,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: transitive + description: + name: http + sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 + url: "https://pub.dev" + source: hosted + version: "1.1.2" http_parser: dependency: transitive description: @@ -216,6 +280,70 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd" + url: "https://pub.dev" + source: hosted + version: "1.0.7" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1" + url: "https://pub.dev" + source: hosted + version: "0.8.9+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3 + url: "https://pub.dev" + source: hosted + version: "3.0.2" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3 + url: "https://pub.dev" + source: hosted + version: "0.8.9+1" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b + url: "https://pub.dev" + source: hosted + version: "2.9.3" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" intl: dependency: "direct main" description: @@ -256,6 +384,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + mime: + dependency: "direct main" + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" open_file: dependency: "direct main" description: @@ -272,6 +408,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -336,6 +496,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.3" + photo_view: + dependency: "direct main" + description: + name: photo_view + sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb" + url: "https://pub.dev" + source: hosted + version: "0.14.0" platform: dependency: transitive description: @@ -565,6 +733,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + video_player: + dependency: "direct main" + description: + name: video_player + sha256: fbf28ce8bcfe709ad91b5789166c832cb7a684d14f571a81891858fefb5bb1c2 + url: "https://pub.dev" + source: hosted + version: "2.8.2" + video_player_android: + dependency: transitive + description: + name: video_player_android + sha256: "7f8f25d7ad56819a82b2948357f3c3af071f6a678db33833b26ec36bbc221316" + url: "https://pub.dev" + source: hosted + version: "2.4.11" + video_player_avfoundation: + dependency: transitive + description: + name: video_player_avfoundation + sha256: "309e3962795e761be010869bae65c0b0e45b5230c5cee1bec72197ca7db040ed" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + video_player_platform_interface: + dependency: transitive + description: + name: video_player_platform_interface + sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + video_player_web: + dependency: transitive + description: + name: video_player_web + sha256: "34beb3a07d4331a24f7e7b2f75b8e2b103289038e07e65529699a671b6a6e2cb" + url: "https://pub.dev" + source: hosted + version: "2.1.3" web: dependency: transitive description: @@ -590,5 +798,5 @@ packages: source: hosted version: "1.0.4" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.2.0 <4.0.0" + flutter: ">=3.16.0" diff --git a/app_petty_cash/pubspec.yaml b/app_petty_cash/pubspec.yaml index 93edb0c..c8047c0 100644 --- a/app_petty_cash/pubspec.yaml +++ b/app_petty_cash/pubspec.yaml @@ -50,6 +50,11 @@ dependencies: flutter_multi_formatter: ^2.12.4 top_snackbar_flutter: ^3.1.0 url_launcher: ^6.1.13 + image_picker: ^1.0.7 + video_player: ^2.7.2 + photo_view: ^0.14.0 + mime: ^1.0.4 + path_provider: ^2.1.2 dev_dependencies: flutter_test: diff --git a/app_petty_cash/windows/flutter/generated_plugin_registrant.cc b/app_petty_cash/windows/flutter/generated_plugin_registrant.cc index a0d0bbe..4e586f9 100644 --- a/app_petty_cash/windows/flutter/generated_plugin_registrant.cc +++ b/app_petty_cash/windows/flutter/generated_plugin_registrant.cc @@ -6,10 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/app_petty_cash/windows/flutter/generated_plugins.cmake b/app_petty_cash/windows/flutter/generated_plugins.cmake index c20a586..1119879 100644 --- a/app_petty_cash/windows/flutter/generated_plugins.cmake +++ b/app_petty_cash/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows permission_handler_windows url_launcher_windows )