diff --git a/android/app/build.gradle b/android/app/build.gradle index d581526..ff9c9cf 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ android { // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. // minSdk = flutter.minSdkVersion - minSdk 23 + minSdk 24 targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f631d1f..3ba4756 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,11 @@ + + + + + diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2c865eb..c01fcfd 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -49,5 +49,7 @@ NSCameraUsageDescription This app needs camera access to scan QR codes + NSMicrophoneUsageDescription + Some message to describe why you need this permission diff --git a/lib/screen/home/rekam_screen.dart b/lib/screen/home/rekam_screen.dart index b08f7e7..5b84b3b 100644 --- a/lib/screen/home/rekam_screen.dart +++ b/lib/screen/home/rekam_screen.dart @@ -1,11 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:fluttervoice2text/provider/voice_to_text_provider.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:flutter_sound/flutter_sound.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'dart:io'; import '../../app/constant.dart'; +import '../../provider/voice_to_text_provider.dart'; class RekamScreen extends HookConsumerWidget { const RekamScreen({super.key}); @@ -21,6 +25,29 @@ class RekamScreen extends HookConsumerWidget { final judulTombol = useState("MULAI REKAM"); final qrCodeStr = useState(""); final isSelesaiRekam = useState(false); + final audioPath = useState(""); + final recorder = useState(FlutterSoundRecorder()); + final player = useState(FlutterSoundPlayer()); + + Future requestPermissions() async { + await Permission.microphone.request(); + await Permission.storage.request(); + } + + useEffect(() { + Future initRecorder() async { + await requestPermissions(); + await recorder.value.openRecorder(); + await player.value.openPlayer(); + } + + initRecorder(); + + return () { + recorder.value.closeRecorder(); + player.value.closePlayer(); + }; + }, []); void handleBarcode(BarcodeCapture barcodes) { if (barcodes.barcodes.isNotEmpty) { @@ -33,164 +60,150 @@ class RekamScreen extends HookConsumerWidget { } } - Widget buildBarcode(Barcode? value) { - final qrCode = value?.displayValue ?? ""; + Future jalankanRekaman() async { + try { + final dir = await getApplicationDocumentsDirectory(); + final filePath = '${dir.path}/myFile.aac'; + audioPath.value = filePath; - if (qrCode.isEmpty) { - return const Text( - 'Scan untuk mendapatkan QR Code', - overflow: TextOverflow.fade, - style: TextStyle(color: Colors.white), + await recorder.value.startRecorder( + toFile: filePath, ); - } - return Text( - "Info: $qrCode", - overflow: TextOverflow.fade, - style: const TextStyle(color: Colors.white), - ); + judulTombol.value = "SELESAI"; + isSelesaiRekam.value = true; + } catch (e) { + print("Error start record ${e.toString()}"); + } } - useEffect(() { - handleBarcode; - return () {}; - }, []); + Future berhentiRekaman() async { + try { + await recorder.value.stopRecorder(); + isSelesaiRekam.value = false; + isRekam.value = false; - return GestureDetector( - onTap: () { - FocusManager.instance.primaryFocus!.unfocus(); - }, - child: Scaffold( - resizeToAvoidBottomInset: true, - backgroundColor: Constant.bgGrey, - bottomNavigationBar: BottomAppBar( - color: Colors.blueGrey.shade100, - height: Constant.getActualYPhone( - context: context, - y: 100, - ), - shape: const CircularNotchedRectangle(), - child: Row( - children: [ - ElevatedButton.icon( - onPressed: () { - ref.read(barcodeX.notifier).state = Barcode(); - isRekam.value = false; - judulTombol.value = "MULAI REKAM"; - qrCodeStr.value = ""; - isSelesaiRekam.value = false; - Navigator.of(context).pop(); - }, - icon: Icon( - Icons.arrow_back, - size: 17, - color: Constant.textWhite, - ), - label: Text( - 'Kembali', - style: Constant.cardText(context: context).copyWith( - color: Constant.textWhite, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.green.shade400, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 8, - shadowColor: Constant.bgButton.withOpacity(0.24), - ), - ), - const Spacer(), - // button - ElevatedButton( - onPressed: (qrCodeStr.value.isEmpty || isSelesaiRekam.value) - ? null - : () { - judulTombol.value = "SELESAI"; - isSelesaiRekam.value = true; - }, - style: ElevatedButton.styleFrom( - backgroundColor: (qrCodeStr.value.isEmpty || isSelesaiRekam.value) - ? Constant.bgGrey - : Constant.bgButton, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 8, - shadowColor: Constant.bgButton.withOpacity(0.24), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.mic, - size: Constant.getActualXPhone( - context: context, - x: 20, - ), - color: Constant.textWhite, - ), - SizedBox( - width: Constant.getActualXPhone( - context: context, - x: 10, - ), - ), - Text( - judulTombol.value, - style: Constant.titleButton500(context: context).copyWith( - color: Constant.textWhite, - ), - ), - ], - ), - ), - ], - ), - ), - appBar: AppBar( - title: Text( - 'Rekam Audio', - style: Constant.titlePosisiHP(context: context), - ), - automaticallyImplyLeading: false, - ), - body: Padding( - padding: EdgeInsets.symmetric( - horizontal: Constant.getActualXPhone(context: context, x: 20), - ), - child: Column( - children: [ - // scanner - if (isRekam.value == false) ...[ - SizedBox( - width: double.infinity, - height: Constant.getActualYPhone( - context: context, - y: 450, - ), - child: MobileScanner( - onDetect: handleBarcode, - ), - ), - SizedBox( - height: Constant.getActualYPhone( - context: context, - y: 15, - ), - ), - ], + // panggil fungsi untuk kirim ke BE + } catch (e) { + print("Error stop record ${e.toString()}"); + } + } - // text - Container( - alignment: Alignment.center, - padding: const EdgeInsets.symmetric(vertical: 10), - color: Constant.inputanGrey, - child: buildBarcode(ref.watch(barcodeX)), + Future playRecording() async { + try { + if (audioPath.value.isNotEmpty && File(audioPath.value).existsSync()) { + await player.value.startPlayer(fromURI: audioPath.value); + } else { + print("Error: Path rekaman kosong atau tidak ditemukan."); + } + } catch (e) { + print("Error saat memutar rekaman: ${e.toString()}"); + } + } + + return Scaffold( + backgroundColor: Constant.bgGrey, + bottomNavigationBar: BottomAppBar( + color: Colors.blueGrey.shade100, + height: Constant.getActualYPhone(context: context, y: 100), + shape: const CircularNotchedRectangle(), + child: Row( + children: [ + ElevatedButton.icon( + onPressed: () { + ref.read(barcodeX.notifier).state = Barcode(); + isRekam.value = false; + judulTombol.value = "MULAI REKAM"; + qrCodeStr.value = ""; + isSelesaiRekam.value = false; + Navigator.of(context).pop(); + }, + icon: Icon(Icons.arrow_back, size: 17, color: Constant.textWhite), + label: Text( + 'Kembali', + style: Constant.cardText(context: context) + .copyWith(color: Constant.textWhite), ), - ], - ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.green.shade400, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + elevation: 8, + ), + ), + const Spacer(), + ElevatedButton( + onPressed: qrCodeStr.value.isEmpty + ? null + : () async { + if (!isSelesaiRekam.value) { + await jalankanRekaman(); + } else { + await berhentiRekaman(); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: qrCodeStr.value.isNotEmpty + ? Constant.bgButton + : Constant.bgGrey, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + elevation: 8, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.mic, size: 20, color: Constant.textWhite), + SizedBox(width: 10), + Text( + judulTombol.value, + style: Constant.titleButton500(context: context) + .copyWith(color: Constant.textWhite), + ), + ], + ), + ), + ], + ), + ), + appBar: AppBar( + title: Text( + 'Rekam Audio', + style: Constant.titlePosisiHP(context: context), + ), + automaticallyImplyLeading: false, + ), + body: Padding( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Column( + children: [ + if (!isRekam.value) + SizedBox( + width: double.infinity, + height: Constant.getActualYPhone( + context: context, + y: 450, + ), + child: MobileScanner(onDetect: handleBarcode), + ), + SizedBox( + height: Constant.getActualYPhone( + context: context, + y: 20, + ), + ), + Container( + alignment: Alignment.center, + padding: EdgeInsets.symmetric(vertical: 10), + color: Constant.inputanGrey, + child: Text("Info: ${qrCodeStr.value}", + style: TextStyle(color: Colors.white)), + ), + SizedBox(height: 40), + ElevatedButton(onPressed: playRecording, child: Text('Play')), + ], ), ), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 145c9eb..e71a16d 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,14 +6,6 @@ #include "generated_plugin_registrant.h" -#include -#include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); - audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); - g_autoptr(FlPluginRegistrar) record_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); - record_linux_plugin_register_with_registrar(record_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index ecad9e4..2e1de87 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,8 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - audioplayers_linux - record_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index b6a1bab..3d6169d 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,16 +5,12 @@ import FlutterMacOS import Foundation -import audioplayers_darwin import mobile_scanner import path_provider_foundation -import record_darwin import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index b76436d..0c20d8e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,62 +9,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" - audioplayers: - dependency: "direct main" - description: - name: audioplayers - sha256: b3d02a23918b980073d4a76c4e5659eaf5127251ca91a6a804869ba88ef1c8bf - url: "https://pub.dev" - source: hosted - version: "6.2.0" - audioplayers_android: - dependency: transitive - description: - name: audioplayers_android - sha256: "56830454da1a943f33c686cdbfca52a8d24f4c6fd6ce88c6b3501020dbaaf48b" - url: "https://pub.dev" - source: hosted - version: "5.0.3" - audioplayers_darwin: - dependency: transitive - description: - name: audioplayers_darwin - sha256: "34e1fb3a88ba02566615c6ca7173aa93b39cf61a38a05a729b60ba14c4899169" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - audioplayers_linux: - dependency: transitive - description: - name: audioplayers_linux - sha256: ce8383c1ff0db1ba93b5b0b8ef5b260ec2d0ce2598ad37dc8b946b773dd2c5fa - url: "https://pub.dev" - source: hosted - version: "4.1.0" - audioplayers_platform_interface: - dependency: transitive - description: - name: audioplayers_platform_interface - sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - audioplayers_web: - dependency: transitive - description: - name: audioplayers_web - sha256: "3609bdf0e05e66a3d9750ee40b1e37f2a622c4edb796cc600b53a90a30a2ace4" - url: "https://pub.dev" - source: hosted - version: "5.0.1" - audioplayers_windows: - dependency: transitive - description: - name: audioplayers_windows - sha256: "52b57c706a20fc85daa911be67381b3a5c9d03f8e27cb9fdb226de5bddf293b1" - url: "https://pub.dev" - source: hosted - version: "4.1.0" boolean_selector: dependency: transitive description: @@ -145,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.7" + etau: + dependency: transitive + description: + name: etau + sha256: "5859ee8438770e2887426dccf05bb55f2c78f20fe6db84043675155c2ebb9a7e" + url: "https://pub.dev" + source: hosted + version: "0.0.14-alpha.5" fake_async: dependency: transitive description: @@ -206,6 +158,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.1" + flutter_sound: + dependency: "direct main" + description: + name: flutter_sound + sha256: a4662bd1bb15a51569b908deb58a3e9ecc14c7080783487202d015644712f1ef + url: "https://pub.dev" + source: hosted + version: "9.23.1" + flutter_sound_platform_interface: + dependency: transitive + description: + name: flutter_sound_platform_interface + sha256: "0ebd302180ddc91c993d4bb061f08d71a047ebb0f04b05befd2ee8de59ea947d" + url: "https://pub.dev" + source: hosted + version: "9.23.1" + flutter_sound_web: + dependency: transitive + description: + name: flutter_sound_web + sha256: "0891d977674be94d8c3f4759c6cd11e7f29a1ed29dc287b874a1393666ac831f" + url: "https://pub.dev" + source: hosted + version: "9.23.1" flutter_test: dependency: "direct dev" description: flutter @@ -224,14 +200,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.1" - http: - dependency: transitive - description: - name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f - url: "https://pub.dev" - source: hosted - version: "1.3.0" http_parser: dependency: transitive description: @@ -296,6 +264,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + logger: + dependency: transitive + description: + name: logger + sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 + url: "https://pub.dev" + source: hosted + version: "2.5.0" matcher: dependency: transitive description: @@ -328,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.6" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -456,62 +440,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - record: - dependency: "direct main" - description: - name: record - sha256: "2e3d56d196abcd69f1046339b75e5f3855b2406fc087e5991f6703f188aa03a6" - url: "https://pub.dev" - source: hosted - version: "5.2.1" - record_android: + provider: dependency: transitive description: - name: record_android - sha256: "36e009c3b83e034321a44a7683d95dd055162a231f95600f7da579dcc79701f9" + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "1.3.1" - record_darwin: + version: "6.1.2" + recase: dependency: transitive description: - name: record_darwin - sha256: e487eccb19d82a9a39cd0126945cfc47b9986e0df211734e2788c95e3f63c82c + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 url: "https://pub.dev" source: hosted - version: "1.2.2" - record_linux: - dependency: transitive - description: - name: record_linux - sha256: "74d41a9ebb1eb498a38e9a813dd524e8f0b4fdd627270bda9756f437b110a3e3" - url: "https://pub.dev" - source: hosted - version: "0.7.2" - record_platform_interface: - dependency: transitive - description: - name: record_platform_interface - sha256: "8a575828733d4c3cb5983c914696f40db8667eab3538d4c41c50cbb79e722ef4" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - record_web: - dependency: transitive - description: - name: record_web - sha256: ef6f5c7760f22d6785ee8d97a2133ff14cb839c65e525ad831eb7f891d83f592 - url: "https://pub.dev" - source: hosted - version: "1.1.5" - record_windows: - dependency: transitive - description: - name: record_windows - sha256: "26bfebc8899f4fa5b6b044089887dc42115820cd6a907bdf40c16e909e87de0a" - url: "https://pub.dev" - source: hosted - version: "1.0.5" + version: "4.1.0" riverpod: dependency: transitive description: @@ -637,6 +581,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0+3" + tau_web: + dependency: transitive + description: + name: tau_web + sha256: "81c8a0dc264f87db84678e5957dd1e4ccc015047fdea0f2cdd86d91c3c8a838e" + url: "https://pub.dev" + source: hosted + version: "0.0.14-alpha.5" term_glyph: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7c58398..91baee5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,10 +46,9 @@ dependencies: path_provider: ^2.1.5 permission_handler: ^11.3.0 dropdown_button2: ^2.3.9 - audioplayers: ^6.2.0 toastification: ^2.3.0 - record: ^5.2.1 mobile_scanner: ^6.0.6 + flutter_sound: ^9.23.1 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index f82b553..48de52b 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,15 +6,9 @@ #include "generated_plugin_registrant.h" -#include #include -#include void RegisterPlugins(flutter::PluginRegistry* registry) { - AudioplayersWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); - RecordWindowsPluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 286eaae..0e69e40 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,9 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST - audioplayers_windows permission_handler_windows - record_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST