├── lib ├── presentation │ ├── pages │ │ ├── map_page.dart │ │ ├── home_page.dart │ │ ├── gmap_page.dart │ │ └── my_restaurant_page.dart │ └── widgets │ │ └── restaurant_card.dart ├── common │ └── constants.dart ├── bloc │ ├── login │ │ ├── login_event.dart │ │ ├── login_state.dart │ │ └── login_bloc.dart │ ├── register │ │ ├── register_event.dart │ │ ├── register_state.dart │ │ └── register_bloc.dart │ ├── detail_product │ │ ├── detail_product_event.dart │ │ ├── detail_product_state.dart │ │ └── detail_product_bloc.dart │ ├── add_product │ │ ├── add_product_event.dart │ │ ├── add_product_state.dart │ │ └── add_product_bloc.dart │ ├── gmap │ │ ├── gmap_event.dart │ │ ├── gmap_state.dart │ │ └── gmap_bloc.dart │ └── get_all_product │ │ ├── get_all_product_event.dart │ │ ├── get_all_product_state.dart │ │ └── get_all_product_bloc.dart ├── data │ ├── models │ │ ├── gmap_model.dart │ │ ├── requests │ │ │ ├── login_request_model.dart │ │ │ ├── login_request_model.g.dart │ │ │ ├── register_request_model.dart │ │ │ ├── register_request_model.g.dart │ │ │ ├── add_product_request_model.dart │ │ │ └── add_product_request_model.g.dart │ │ ├── responses │ │ │ ├── auth_response_model.dart │ │ │ ├── products_response_model.dart │ │ │ ├── auth_response_model.g.dart │ │ │ ├── products_response_model.g.dart │ │ │ ├── add_product_response_model.dart │ │ │ └── add_product_response_model.g.dart │ │ ├── upload_image_response_model.dart │ │ ├── direction.dart │ │ └── upload_image_response_model.g.dart │ ├── local_datasources │ │ └── auth_local_datasource.dart │ └── remote_datasources │ │ ├── auth_datasource.dart │ │ ├── gmap_datasource.dart │ │ └── restaurant_datasource.dart └── main.dart ├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── RunnerTests │ └── RunnerTests.swift ├── .gitignore └── Podfile ├── coverage ├── ruby.png ├── snow.png ├── amber.png ├── glass.png ├── updown.png ├── emerald.png ├── temp │ ├── ruby.png │ ├── snow.png │ ├── amber.png │ ├── glass.png │ ├── updown.png │ ├── emerald.png │ └── bloc │ │ └── detail_product │ │ └── detail_product_bloc.dart.gcov.html ├── bloc │ ├── detail_product │ │ ├── index-sort-l.html │ │ ├── index.html │ │ └── detail_product_bloc.dart.gcov.html │ └── get_all_product │ │ ├── index-sort-l.html │ │ └── index.html ├── data │ ├── local_datasources │ │ ├── index-sort-l.html │ │ └── index.html │ ├── remote_datasources │ │ ├── index-sort-l.html │ │ └── index.html │ └── models │ │ ├── index-sort-l.html │ │ ├── index.html │ │ ├── requests │ │ ├── index-sort-l.html │ │ └── index.html │ │ └── responses │ │ ├── index-sort-l.html │ │ └── index.html ├── lcov.info └── index-sort-l.html ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── manifest.json └── index.html ├── assets └── markers │ ├── car.png │ ├── pin.png │ ├── locatpin.png │ ├── map-pin.png │ └── mappin.png ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── flutter_restaurant_fic5 │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── test └── bloc │ ├── gmap │ └── gmap_bloc_test.dart │ ├── detail_product │ ├── detail_product_bloc_test.dart │ └── detail_product_bloc_test.mocks.dart │ └── get_all_product │ ├── get_all_product_bloc_test.dart │ └── get_all_product_bloc_test.mocks.dart ├── README.md ├── .gitignore ├── analysis_options.yaml ├── .metadata └── pubspec.yaml /lib/presentation/pages/map_page.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /coverage/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/ruby.png -------------------------------------------------------------------------------- /coverage/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/snow.png -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/web/favicon.png -------------------------------------------------------------------------------- /coverage/amber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/amber.png -------------------------------------------------------------------------------- /coverage/glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/glass.png -------------------------------------------------------------------------------- /coverage/updown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/updown.png -------------------------------------------------------------------------------- /assets/markers/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/assets/markers/car.png -------------------------------------------------------------------------------- /assets/markers/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/assets/markers/pin.png -------------------------------------------------------------------------------- /coverage/emerald.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/emerald.png -------------------------------------------------------------------------------- /coverage/temp/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/temp/ruby.png -------------------------------------------------------------------------------- /coverage/temp/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/temp/snow.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /coverage/temp/amber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/temp/amber.png -------------------------------------------------------------------------------- /coverage/temp/glass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/temp/glass.png -------------------------------------------------------------------------------- /coverage/temp/updown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/temp/updown.png -------------------------------------------------------------------------------- /lib/common/constants.dart: -------------------------------------------------------------------------------- 1 | class Constants { 2 | static const String baseUrl = 'http://103.150.116.14:1337'; 3 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /assets/markers/locatpin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/assets/markers/locatpin.png -------------------------------------------------------------------------------- /assets/markers/map-pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/assets/markers/map-pin.png -------------------------------------------------------------------------------- /assets/markers/mappin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/assets/markers/mappin.png -------------------------------------------------------------------------------- /coverage/temp/emerald.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/coverage/temp/emerald.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /test/bloc/gmap/gmap_bloc_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | testWidgets('gmap bloc ...', (tester) async { 5 | // TODO: Implement test 6 | }); 7 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahrie127/flutter_restaurant_fic5/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/bloc/login/login_event.dart: -------------------------------------------------------------------------------- 1 | part of 'login_bloc.dart'; 2 | 3 | @freezed 4 | class LoginEvent with _$LoginEvent { 5 | const factory LoginEvent.started() = _Started; 6 | const factory LoginEvent.add(LoginRequestModel model) = _Add; 7 | } -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_restaurant_fic5/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.jagoflutter.flutter_restaurant_fic5 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /lib/bloc/register/register_event.dart: -------------------------------------------------------------------------------- 1 | part of 'register_bloc.dart'; 2 | 3 | @freezed 4 | class RegisterEvent with _$RegisterEvent { 5 | const factory RegisterEvent.started() = _Started; 6 | const factory RegisterEvent.add(RegisterRequestModel model) = _Add; 7 | } -------------------------------------------------------------------------------- /lib/bloc/detail_product/detail_product_event.dart: -------------------------------------------------------------------------------- 1 | part of 'detail_product_bloc.dart'; 2 | 3 | @freezed 4 | class DetailProductEvent with _$DetailProductEvent { 5 | const factory DetailProductEvent.started() = _Started; 6 | const factory DetailProductEvent.get(int id) = _Get; 7 | } -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/bloc/add_product/add_product_event.dart: -------------------------------------------------------------------------------- 1 | part of 'add_product_bloc.dart'; 2 | 3 | @freezed 4 | class AddProductEvent with _$AddProductEvent { 5 | const factory AddProductEvent.started() = _Started; 6 | const factory AddProductEvent.add( 7 | AddProductRequestModel model, 8 | XFile image, 9 | ) = _Add; 10 | } 11 | -------------------------------------------------------------------------------- /lib/bloc/gmap/gmap_event.dart: -------------------------------------------------------------------------------- 1 | part of 'gmap_bloc.dart'; 2 | 3 | @freezed 4 | class GmapEvent with _$GmapEvent { 5 | const factory GmapEvent.started() = _Started; 6 | const factory GmapEvent.getCurrentLocation() = _GetCurrentLocation; 7 | const factory GmapEvent.getSelectPosition(double lat, double long) = _GetSelectPosition; 8 | 9 | } -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/bloc/get_all_product/get_all_product_event.dart: -------------------------------------------------------------------------------- 1 | part of 'get_all_product_bloc.dart'; 2 | 3 | @freezed 4 | class GetAllProductEvent with _$GetAllProductEvent { 5 | const factory GetAllProductEvent.started() = _Started; 6 | const factory GetAllProductEvent.get() = _Get; 7 | const factory GetAllProductEvent.getByUserId() = _GetByUserId; 8 | } 9 | -------------------------------------------------------------------------------- /lib/data/models/gmap_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 2 | 3 | class GmapModel { 4 | LatLng? latLng; 5 | String? address; 6 | GmapModel({ 7 | this.latLng, 8 | this.address, 9 | }); 10 | 11 | @override 12 | String toString() => 'GmapModel(latLng: $latLng, address: $address)'; 13 | } 14 | -------------------------------------------------------------------------------- /lib/bloc/gmap/gmap_state.dart: -------------------------------------------------------------------------------- 1 | part of 'gmap_bloc.dart'; 2 | 3 | @freezed 4 | class GmapState with _$GmapState { 5 | const factory GmapState.initial() = _Initial; 6 | const factory GmapState.loading() = _Loading; 7 | const factory GmapState.loaded(GmapModel model) = _Loaded; 8 | const factory GmapState.error(String error) = _Error; 9 | } 10 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /lib/bloc/login/login_state.dart: -------------------------------------------------------------------------------- 1 | part of 'login_bloc.dart'; 2 | 3 | @freezed 4 | class LoginState with _$LoginState { 5 | const factory LoginState.initial() = _Initial; 6 | const factory LoginState.loading() = _Loading; 7 | const factory LoginState.loaded(AuthResponseModel model) = _Loaded; 8 | const factory LoginState.error(String message) = _Error; 9 | } 10 | -------------------------------------------------------------------------------- /lib/bloc/register/register_state.dart: -------------------------------------------------------------------------------- 1 | part of 'register_bloc.dart'; 2 | 3 | @freezed 4 | class RegisterState with _$RegisterState { 5 | const factory RegisterState.initial() = _Initial; 6 | const factory RegisterState.loading() = _Loading; 7 | const factory RegisterState.loaded(AuthResponseModel model) = _Loaded; 8 | const factory RegisterState.error() = _Error; 9 | } 10 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /lib/bloc/add_product/add_product_state.dart: -------------------------------------------------------------------------------- 1 | part of 'add_product_bloc.dart'; 2 | 3 | @freezed 4 | class AddProductState with _$AddProductState { 5 | const factory AddProductState.initial() = _Initial; 6 | const factory AddProductState.loading() = _Loading; 7 | const factory AddProductState.loaded(AddProductResponseModel data) = _Loaded; 8 | const factory AddProductState.error(String string) = _Error; 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/bloc/get_all_product/get_all_product_state.dart: -------------------------------------------------------------------------------- 1 | part of 'get_all_product_bloc.dart'; 2 | 3 | @freezed 4 | class GetAllProductState with _$GetAllProductState { 5 | const factory GetAllProductState.initial() = _Initial; 6 | const factory GetAllProductState.loading() = _Loading; 7 | const factory GetAllProductState.loaded(ProductsResponseModel data) = _Loaded; 8 | const factory GetAllProductState.error() = _Error; 9 | } 10 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/bloc/detail_product/detail_product_state.dart: -------------------------------------------------------------------------------- 1 | part of 'detail_product_bloc.dart'; 2 | 3 | @freezed 4 | class DetailProductState with _$DetailProductState { 5 | const factory DetailProductState.initial() = _Initial; 6 | const factory DetailProductState.loading() = _Loading; 7 | const factory DetailProductState.loaded(AddProductResponseModel model) = _Loaded; 8 | const factory DetailProductState.error(String message) = _Error; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_restaurant_fic5 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /lib/data/models/requests/login_request_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final loginRequestModel = loginRequestModelFromJson(jsonString); 4 | 5 | import 'package:meta/meta.dart'; 6 | import 'package:freezed_annotation/freezed_annotation.dart'; 7 | import 'dart:convert'; 8 | 9 | part 'login_request_model.freezed.dart'; 10 | part 'login_request_model.g.dart'; 11 | 12 | @freezed 13 | class LoginRequestModel with _$LoginRequestModel { 14 | const factory LoginRequestModel({ 15 | required String identifier, 16 | required String password, 17 | }) = _LoginRequestModel; 18 | 19 | factory LoginRequestModel.fromJson(Map json) => 20 | _$LoginRequestModelFromJson(json); 21 | } 22 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.3.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /lib/data/models/requests/login_request_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'login_request_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_LoginRequestModel _$$_LoginRequestModelFromJson(Map json) => 10 | _$_LoginRequestModel( 11 | identifier: json['identifier'] as String, 12 | password: json['password'] as String, 13 | ); 14 | 15 | Map _$$_LoginRequestModelToJson( 16 | _$_LoginRequestModel instance) => 17 | { 18 | 'identifier': instance.identifier, 19 | 'password': instance.password, 20 | }; 21 | -------------------------------------------------------------------------------- /lib/data/models/requests/register_request_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final registerRequestModel = registerRequestModelFromJson(jsonString); 4 | 5 | import 'package:meta/meta.dart'; 6 | import 'package:freezed_annotation/freezed_annotation.dart'; 7 | import 'dart:convert'; 8 | 9 | part 'register_request_model.freezed.dart'; 10 | part 'register_request_model.g.dart'; 11 | 12 | @freezed 13 | class RegisterRequestModel with _$RegisterRequestModel { 14 | const factory RegisterRequestModel({ 15 | required String name, 16 | required String password, 17 | required String email, 18 | required String username, 19 | }) = _RegisterRequestModel; 20 | 21 | factory RegisterRequestModel.fromJson(Map json) => _$RegisterRequestModelFromJson(json); 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/bloc/login/login_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | import 'package:flutter_restaurant_fic5/data/remote_datasources/auth_datasource.dart'; 5 | 6 | import '../../data/models/requests/login_request_model.dart'; 7 | import '../../data/models/responses/auth_response_model.dart'; 8 | 9 | part 'login_bloc.freezed.dart'; 10 | part 'login_event.dart'; 11 | part 'login_state.dart'; 12 | 13 | class LoginBloc extends Bloc { 14 | final AuthDataSource dataSource; 15 | LoginBloc( 16 | this.dataSource, 17 | ) : super(const _Initial()) { 18 | on<_Add>((event, emit) async { 19 | emit(const _Loading()); 20 | final result = await dataSource.login(event.model); 21 | result.fold( 22 | (l) => emit(_Error(l)), 23 | (r) => emit(_Loaded(r)), 24 | ); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/bloc/detail_product/detail_product_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart'; 5 | 6 | import '../../data/models/responses/add_product_response_model.dart'; 7 | 8 | part 'detail_product_bloc.freezed.dart'; 9 | part 'detail_product_event.dart'; 10 | part 'detail_product_state.dart'; 11 | 12 | class DetailProductBloc extends Bloc { 13 | final RestaurantDatasource datasource; 14 | DetailProductBloc( 15 | this.datasource, 16 | ) : super(const _Initial()) { 17 | on<_Get>((event, emit) async { 18 | emit(const _Loading()); 19 | final result = await datasource.getById(event.id); 20 | result.fold( 21 | (l) => emit(_Error(l)), 22 | (r) => emit(_Loaded(r)), 23 | ); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/bloc/register/register_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | import 'package:flutter_restaurant_fic5/data/remote_datasources/auth_datasource.dart'; 5 | 6 | import '../../data/models/requests/register_request_model.dart'; 7 | import '../../data/models/responses/auth_response_model.dart'; 8 | 9 | part 'register_bloc.freezed.dart'; 10 | part 'register_event.dart'; 11 | part 'register_state.dart'; 12 | 13 | class RegisterBloc extends Bloc { 14 | final AuthDataSource dataSource; 15 | RegisterBloc( 16 | this.dataSource, 17 | ) : super(const _Initial()) { 18 | on<_Add>((event, emit) async { 19 | emit(const _Loading()); 20 | final result = await dataSource.register(event.model); 21 | result.fold( 22 | (l) => emit(const _Error()), 23 | (r) => emit(_Loaded(r)), 24 | ); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/data/models/requests/register_request_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'register_request_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_RegisterRequestModel _$$_RegisterRequestModelFromJson( 10 | Map json) => 11 | _$_RegisterRequestModel( 12 | name: json['name'] as String, 13 | password: json['password'] as String, 14 | email: json['email'] as String, 15 | username: json['username'] as String, 16 | ); 17 | 18 | Map _$$_RegisterRequestModelToJson( 19 | _$_RegisterRequestModel instance) => 20 | { 21 | 'name': instance.name, 22 | 'password': instance.password, 23 | 'email': instance.email, 24 | 'username': instance.username, 25 | }; 26 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_restaurant_fic5", 3 | "short_name": "flutter_restaurant_fic5", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /lib/presentation/widgets/restaurant_card.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:flutter_restaurant_fic5/data/models/responses/add_product_response_model.dart'; 4 | import 'package:flutter_restaurant_fic5/presentation/pages/detail_restaurant_page.dart'; 5 | import 'package:go_router/go_router.dart'; 6 | 7 | class RestaurantCard extends StatelessWidget { 8 | const RestaurantCard({ 9 | Key? key, 10 | required this.data, 11 | }) : super(key: key); 12 | final Restaurant data; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return InkWell( 17 | onTap: () => context.push('${DetailRestaurantPage.routeName}/${data.id}'), 18 | child: Card( 19 | child: ListTile( 20 | title: Text(data.attributes.name), 21 | subtitle: Text(data.attributes.description), 22 | leading: CircleAvatar( 23 | radius: 18, 24 | child: Image.network( 25 | data.attributes.photo ?? 'https://picsum.photos/200/300'), 26 | ), 27 | ), 28 | ), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/bloc/gmap/gmap_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | import 'package:flutter_restaurant_fic5/data/remote_datasources/gmap_datasource.dart'; 5 | 6 | import '../../data/models/gmap_model.dart'; 7 | 8 | part 'gmap_bloc.freezed.dart'; 9 | part 'gmap_event.dart'; 10 | part 'gmap_state.dart'; 11 | 12 | class GmapBloc extends Bloc { 13 | final GmapDatasource datasource; 14 | GmapBloc( 15 | this.datasource, 16 | ) : super(const _Initial()) { 17 | on<_GetCurrentLocation>((event, emit) async { 18 | emit(const _Loading()); 19 | final result = await datasource.getCurrentPosition(); 20 | result.fold( 21 | (l) => emit(_Error(l)), 22 | (r) => emit(_Loaded(r)), 23 | ); 24 | }); 25 | 26 | on<_GetSelectPosition>((event, emit) async { 27 | emit(const _Loading()); 28 | final result = await datasource.getPosition( 29 | lat: event.lat, 30 | long: event.lat, 31 | ); 32 | result.fold( 33 | (l) => emit(_Error(l)), 34 | (r) => emit(_Loaded(r)), 35 | ); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/data/models/requests/add_product_request_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final addProductRequestModel = addProductRequestModelFromJson(jsonString); 4 | 5 | import 'package:meta/meta.dart'; 6 | import 'package:freezed_annotation/freezed_annotation.dart'; 7 | import 'dart:convert'; 8 | 9 | part 'add_product_request_model.freezed.dart'; 10 | part 'add_product_request_model.g.dart'; 11 | 12 | @freezed 13 | class AddProductRequestModel with _$AddProductRequestModel { 14 | const factory AddProductRequestModel({ 15 | required Data data, 16 | }) = _AddProductRequestModel; 17 | 18 | factory AddProductRequestModel.fromJson(Map json) => _$AddProductRequestModelFromJson(json); 19 | } 20 | 21 | @freezed 22 | class Data with _$Data { 23 | const factory Data({ 24 | required String name, 25 | required String description, 26 | required String latitude, 27 | required String longitude, 28 | required String photo, 29 | required String address, 30 | required int userId, 31 | }) = _Data; 32 | 33 | factory Data.fromJson(Map json) => _$DataFromJson(json); 34 | } 35 | -------------------------------------------------------------------------------- /lib/data/models/responses/auth_response_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final authResponseModel = authResponseModelFromJson(jsonString); 4 | 5 | import 'package:meta/meta.dart'; 6 | import 'package:freezed_annotation/freezed_annotation.dart'; 7 | import 'dart:convert'; 8 | 9 | part 'auth_response_model.freezed.dart'; 10 | part 'auth_response_model.g.dart'; 11 | 12 | @freezed 13 | class AuthResponseModel with _$AuthResponseModel { 14 | const factory AuthResponseModel({ 15 | required String jwt, 16 | required User user, 17 | }) = _AuthResponseModel; 18 | 19 | factory AuthResponseModel.fromJson(Map json) => _$AuthResponseModelFromJson(json); 20 | } 21 | 22 | @freezed 23 | class User with _$User { 24 | const factory User({ 25 | required int id, 26 | required String username, 27 | required String email, 28 | required String provider, 29 | required bool confirmed, 30 | required bool blocked, 31 | required DateTime createdAt, 32 | required DateTime updatedAt, 33 | }) = _User; 34 | 35 | factory User.fromJson(Map json) => _$UserFromJson(json); 36 | } 37 | -------------------------------------------------------------------------------- /lib/bloc/get_all_product/get_all_product_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:flutter_restaurant_fic5/data/local_datasources/auth_local_datasource.dart'; 3 | import 'package:freezed_annotation/freezed_annotation.dart'; 4 | 5 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart'; 6 | 7 | import '../../data/models/responses/products_response_model.dart'; 8 | 9 | part 'get_all_product_bloc.freezed.dart'; 10 | part 'get_all_product_event.dart'; 11 | part 'get_all_product_state.dart'; 12 | 13 | class GetAllProductBloc extends Bloc { 14 | final RestaurantDatasource datasource; 15 | GetAllProductBloc( 16 | this.datasource, 17 | ) : super(const _Initial()) { 18 | on<_Get>((event, emit) async { 19 | emit(const _Loading()); 20 | final result = await datasource.getAll(); 21 | result.fold( 22 | (l) => emit(const _Error()), 23 | (r) => emit(_Loaded(r)), 24 | ); 25 | }); 26 | 27 | on<_GetByUserId>((event, emit) async { 28 | emit(const _Loading()); 29 | final userId = await AuthLocalDatasource().getUserId(); 30 | final result = await datasource.getByUserId(userId); 31 | result.fold( 32 | (l) => emit(const _Error()), 33 | (r) => emit(_Loaded(r)), 34 | ); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/data/models/responses/products_response_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final productsResponseModel = productsResponseModelFromJson(jsonString); 4 | 5 | import 'package:flutter_restaurant_fic5/data/models/responses/add_product_response_model.dart'; 6 | import 'package:meta/meta.dart'; 7 | import 'package:freezed_annotation/freezed_annotation.dart'; 8 | import 'dart:convert'; 9 | 10 | part 'products_response_model.freezed.dart'; 11 | part 'products_response_model.g.dart'; 12 | 13 | @freezed 14 | class ProductsResponseModel with _$ProductsResponseModel { 15 | const factory ProductsResponseModel({ 16 | required List data, 17 | required Meta meta, 18 | }) = _ProductsResponseModel; 19 | 20 | factory ProductsResponseModel.fromJson(Map json) => 21 | _$ProductsResponseModelFromJson(json); 22 | } 23 | 24 | @freezed 25 | class Meta with _$Meta { 26 | const factory Meta({ 27 | required Pagination pagination, 28 | }) = _Meta; 29 | 30 | factory Meta.fromJson(Map json) => _$MetaFromJson(json); 31 | } 32 | 33 | @freezed 34 | class Pagination with _$Pagination { 35 | const factory Pagination({ 36 | required int page, 37 | required int pageSize, 38 | required int pageCount, 39 | required int total, 40 | }) = _Pagination; 41 | 42 | factory Pagination.fromJson(Map json) => 43 | _$PaginationFromJson(json); 44 | } 45 | -------------------------------------------------------------------------------- /lib/data/local_datasources/auth_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter_restaurant_fic5/data/models/responses/auth_response_model.dart'; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | 6 | class AuthLocalDatasource { 7 | Future saveAuthData(AuthResponseModel model) async { 8 | final SharedPreferences pref = await SharedPreferences.getInstance(); 9 | final res = await pref.setString('auth', jsonEncode(model.toJson())); 10 | return res; 11 | } 12 | 13 | Future removeAuthData() async { 14 | final SharedPreferences pref = await SharedPreferences.getInstance(); 15 | return pref.remove('auth'); 16 | } 17 | 18 | Future getToken() async { 19 | final SharedPreferences pref = await SharedPreferences.getInstance(); 20 | final authJson = pref.getString('auth') ?? ''; 21 | final authData = AuthResponseModel.fromJson(jsonDecode(authJson)); 22 | return authData.jwt; 23 | } 24 | 25 | Future getUserId() async { 26 | final SharedPreferences pref = await SharedPreferences.getInstance(); 27 | final authJson = pref.getString('auth') ?? ''; 28 | final authData = AuthResponseModel.fromJson(jsonDecode(authJson)); 29 | return authData.user.id; 30 | } 31 | 32 | Future isLogin() async { 33 | final SharedPreferences pref = await SharedPreferences.getInstance(); 34 | final authJson = pref.getString('auth') ?? ''; 35 | 36 | return authJson.isNotEmpty; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/data/models/requests/add_product_request_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'add_product_request_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_AddProductRequestModel _$$_AddProductRequestModelFromJson( 10 | Map json) => 11 | _$_AddProductRequestModel( 12 | data: Data.fromJson(json['data'] as Map), 13 | ); 14 | 15 | Map _$$_AddProductRequestModelToJson( 16 | _$_AddProductRequestModel instance) => 17 | { 18 | 'data': instance.data, 19 | }; 20 | 21 | _$_Data _$$_DataFromJson(Map json) => _$_Data( 22 | name: json['name'] as String, 23 | description: json['description'] as String, 24 | latitude: json['latitude'] as String, 25 | longitude: json['longitude'] as String, 26 | photo: json['photo'] as String, 27 | address: json['address'] as String, 28 | userId: json['userId'] as int, 29 | ); 30 | 31 | Map _$$_DataToJson(_$_Data instance) => { 32 | 'name': instance.name, 33 | 'description': instance.description, 34 | 'latitude': instance.latitude, 35 | 'longitude': instance.longitude, 36 | 'photo': instance.photo, 37 | 'address': instance.address, 38 | 'userId': instance.userId, 39 | }; 40 | -------------------------------------------------------------------------------- /lib/bloc/add_product/add_product_bloc.dart: -------------------------------------------------------------------------------- 1 | import 'package:bloc/bloc.dart'; 2 | import 'package:flutter_restaurant_fic5/common/constants.dart'; 3 | import 'package:freezed_annotation/freezed_annotation.dart'; 4 | 5 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart'; 6 | import 'package:image_picker/image_picker.dart'; 7 | 8 | import '../../data/models/requests/add_product_request_model.dart'; 9 | import '../../data/models/responses/add_product_response_model.dart'; 10 | 11 | part 'add_product_bloc.freezed.dart'; 12 | part 'add_product_event.dart'; 13 | part 'add_product_state.dart'; 14 | 15 | class AddProductBloc extends Bloc { 16 | final RestaurantDatasource datasource; 17 | AddProductBloc( 18 | this.datasource, 19 | ) : super(const _Initial()) { 20 | on<_Add>((event, emit) async { 21 | emit(const _Loading()); 22 | final uploadResult = await datasource.uploadImage(event.image); 23 | await Future.sync(() => uploadResult.fold( 24 | (errorUpload) => emit(_Error(errorUpload)), 25 | (successUpload) async { 26 | final result = await datasource.addProduct(AddProductRequestModel( 27 | data: event.model.data.copyWith( 28 | photo: '${Constants.baseUrl}${successUpload.url!}'))); 29 | result.fold( 30 | (l) => emit(_Error(l)), 31 | (r) => emit(_Loaded(r)), 32 | ); 33 | }, 34 | )); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/data/models/responses/auth_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'auth_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_AuthResponseModel _$$_AuthResponseModelFromJson(Map json) => 10 | _$_AuthResponseModel( 11 | jwt: json['jwt'] as String, 12 | user: User.fromJson(json['user'] as Map), 13 | ); 14 | 15 | Map _$$_AuthResponseModelToJson( 16 | _$_AuthResponseModel instance) => 17 | { 18 | 'jwt': instance.jwt, 19 | 'user': instance.user, 20 | }; 21 | 22 | _$_User _$$_UserFromJson(Map json) => _$_User( 23 | id: json['id'] as int, 24 | username: json['username'] as String, 25 | email: json['email'] as String, 26 | provider: json['provider'] as String, 27 | confirmed: json['confirmed'] as bool, 28 | blocked: json['blocked'] as bool, 29 | createdAt: DateTime.parse(json['createdAt'] as String), 30 | updatedAt: DateTime.parse(json['updatedAt'] as String), 31 | ); 32 | 33 | Map _$$_UserToJson(_$_User instance) => { 34 | 'id': instance.id, 35 | 'username': instance.username, 36 | 'email': instance.email, 37 | 'provider': instance.provider, 38 | 'confirmed': instance.confirmed, 39 | 'blocked': instance.blocked, 40 | 'createdAt': instance.createdAt.toIso8601String(), 41 | 'updatedAt': instance.updatedAt.toIso8601String(), 42 | }; 43 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/data/remote_datasources/auth_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter_restaurant_fic5/data/models/requests/login_request_model.dart'; 4 | import 'package:http/http.dart' as http; 5 | import 'package:dartz/dartz.dart'; 6 | 7 | import '../../common/constants.dart'; 8 | import '../models/requests/register_request_model.dart'; 9 | import '../models/responses/auth_response_model.dart'; 10 | 11 | class AuthDataSource { 12 | Future> register( 13 | RegisterRequestModel registerData, 14 | ) async { 15 | final response = await http.post( 16 | Uri.parse("${Constants.baseUrl}/api/auth/local/register"), 17 | headers: { 18 | 'Content-Type': 'application/json; charset=UTF-8', 19 | }, 20 | body: jsonEncode(registerData.toJson()), 21 | ); 22 | 23 | if (response.statusCode == 200) { 24 | return Right( 25 | AuthResponseModel.fromJson(jsonDecode(response.body)), 26 | ); 27 | } else { 28 | return const Left( 29 | 'API ERROR', 30 | ); 31 | } 32 | } 33 | 34 | Future> login( 35 | LoginRequestModel model, 36 | ) async { 37 | final response = await http.post( 38 | Uri.parse("${Constants.baseUrl}/api/auth/local"), 39 | headers: { 40 | 'Content-Type': 'application/json; charset=UTF-8', 41 | }, 42 | body: jsonEncode(model.toJson()), 43 | ); 44 | 45 | if (response.statusCode == 200) { 46 | return Right( 47 | AuthResponseModel.fromJson(jsonDecode(response.body)), 48 | ); 49 | } else { 50 | return const Left( 51 | 'API ERROR', 52 | ); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/data/models/responses/products_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'products_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_ProductsResponseModel _$$_ProductsResponseModelFromJson( 10 | Map json) => 11 | _$_ProductsResponseModel( 12 | data: (json['data'] as List) 13 | .map((e) => Restaurant.fromJson(e as Map)) 14 | .toList(), 15 | meta: Meta.fromJson(json['meta'] as Map), 16 | ); 17 | 18 | Map _$$_ProductsResponseModelToJson( 19 | _$_ProductsResponseModel instance) => 20 | { 21 | 'data': instance.data, 22 | 'meta': instance.meta, 23 | }; 24 | 25 | _$_Meta _$$_MetaFromJson(Map json) => _$_Meta( 26 | pagination: 27 | Pagination.fromJson(json['pagination'] as Map), 28 | ); 29 | 30 | Map _$$_MetaToJson(_$_Meta instance) => { 31 | 'pagination': instance.pagination, 32 | }; 33 | 34 | _$_Pagination _$$_PaginationFromJson(Map json) => 35 | _$_Pagination( 36 | page: json['page'] as int, 37 | pageSize: json['pageSize'] as int, 38 | pageCount: json['pageCount'] as int, 39 | total: json['total'] as int, 40 | ); 41 | 42 | Map _$$_PaginationToJson(_$_Pagination instance) => 43 | { 44 | 'page': instance.page, 45 | 'pageSize': instance.pageSize, 46 | 'pageCount': instance.pageCount, 47 | 'total': instance.total, 48 | }; 49 | -------------------------------------------------------------------------------- /lib/data/models/upload_image_response_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final uploadImageResponseModel = uploadImageResponseModelFromJson(jsonString); 4 | 5 | import 'package:freezed_annotation/freezed_annotation.dart'; 6 | import 'dart:convert'; 7 | 8 | part 'upload_image_response_model.freezed.dart'; 9 | part 'upload_image_response_model.g.dart'; 10 | 11 | @freezed 12 | class UploadImageResponseModel with _$UploadImageResponseModel { 13 | const factory UploadImageResponseModel({ 14 | int? id, 15 | String? name, 16 | dynamic alternativeText, 17 | dynamic caption, 18 | int? width, 19 | int? height, 20 | Formats? formats, 21 | String? hash, 22 | String? ext, 23 | String? mime, 24 | double? size, 25 | String? url, 26 | dynamic previewUrl, 27 | String? provider, 28 | dynamic providerMetadata, 29 | DateTime? createdAt, 30 | DateTime? updatedAt, 31 | }) = _UploadImageResponseModel; 32 | 33 | factory UploadImageResponseModel.fromJson(Map json) => 34 | _$UploadImageResponseModelFromJson(json); 35 | } 36 | 37 | @freezed 38 | class Formats with _$Formats { 39 | const factory Formats({ 40 | Large? thumbnail, 41 | Large? small, 42 | Large? medium, 43 | Large? large, 44 | }) = _Formats; 45 | 46 | factory Formats.fromJson(Map json) => 47 | _$FormatsFromJson(json); 48 | } 49 | 50 | @freezed 51 | class Large with _$Large { 52 | const factory Large({ 53 | String? name, 54 | String? hash, 55 | String? ext, 56 | String? mime, 57 | dynamic path, 58 | int? width, 59 | int? height, 60 | double? size, 61 | String? url, 62 | }) = _Large; 63 | 64 | factory Large.fromJson(Map json) => _$LargeFromJson(json); 65 | } 66 | -------------------------------------------------------------------------------- /lib/data/models/responses/add_product_response_model.dart: -------------------------------------------------------------------------------- 1 | // To parse this JSON data, do 2 | // 3 | // final addProductResponseModel = addProductResponseModelFromJson(jsonString); 4 | 5 | import 'package:meta/meta.dart'; 6 | import 'package:freezed_annotation/freezed_annotation.dart'; 7 | import 'dart:convert'; 8 | 9 | part 'add_product_response_model.freezed.dart'; 10 | part 'add_product_response_model.g.dart'; 11 | 12 | @freezed 13 | class AddProductResponseModel with _$AddProductResponseModel { 14 | const factory AddProductResponseModel({ 15 | required Restaurant data, 16 | required Meta meta, 17 | }) = _AddProductResponseModel; 18 | 19 | factory AddProductResponseModel.fromJson(Map json) => 20 | _$AddProductResponseModelFromJson(json); 21 | } 22 | 23 | @freezed 24 | class Restaurant with _$Restaurant { 25 | const factory Restaurant({ 26 | required int id, 27 | required Attributes attributes, 28 | }) = _Data; 29 | 30 | factory Restaurant.fromJson(Map json) => 31 | _$RestaurantFromJson(json); 32 | } 33 | 34 | @freezed 35 | class Attributes with _$Attributes { 36 | const factory Attributes({ 37 | required String name, 38 | required String description, 39 | required String latitude, 40 | required String longitude, 41 | required String address, 42 | required DateTime createdAt, 43 | required DateTime updatedAt, 44 | required DateTime publishedAt, 45 | String? photo, 46 | String? userId, 47 | }) = _Attributes; 48 | 49 | factory Attributes.fromJson(Map json) => 50 | _$AttributesFromJson(json); 51 | } 52 | 53 | @freezed 54 | class Meta with _$Meta { 55 | const factory Meta() = _Meta; 56 | 57 | factory Meta.fromJson(Map json) => _$MetaFromJson(json); 58 | } 59 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 17 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 18 | - platform: android 19 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 20 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 21 | - platform: ios 22 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 23 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 24 | - platform: linux 25 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 26 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 27 | - platform: macos 28 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 29 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 30 | - platform: web 31 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 32 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 33 | - platform: windows 34 | create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 35 | base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8 36 | 37 | # User provided section 38 | 39 | # List of Local paths (relative to this file) that should be 40 | # ignored by the migrate tool. 41 | # 42 | # Files that are not part of the templates will be ignored by default. 43 | unmanaged_files: 44 | - 'lib/main.dart' 45 | - 'ios/Runner.xcodeproj/project.pbxproj' 46 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Flutter Restaurant Fic5 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flutter_restaurant_fic5 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | UIApplicationSupportsIndirectInputEvents 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | flutter_restaurant_fic5 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 15 | 23 | 27 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /coverage/temp/bloc/detail_product/detail_product_bloc.dart.gcov.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - bloc/detail_product/detail_product_bloc.dart 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 50 | 51 | 52 | 53 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Current view:top level - bloc/detail_product - detail_product_bloc.dart (source / functions)HitTotalCoverage
Test:lcov.infoLines:88100.0 %
Date:2023-07-11 20:31:23Functions:00-
49 |
54 | 55 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | namespace "com.jagoflutter.flutter_restaurant_fic5" 30 | compileSdkVersion flutter.compileSdkVersion 31 | ndkVersion flutter.ndkVersion 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | 38 | kotlinOptions { 39 | jvmTarget = '1.8' 40 | } 41 | 42 | sourceSets { 43 | main.java.srcDirs += 'src/main/kotlin' 44 | } 45 | 46 | defaultConfig { 47 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 48 | applicationId "com.jagoflutter.flutter_restaurant_fic5" 49 | // You can update the following values to match your application needs. 50 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 51 | minSdkVersion 21 52 | targetSdkVersion flutter.targetSdkVersion 53 | versionCode flutterVersionCode.toInteger() 54 | versionName flutterVersionName 55 | } 56 | 57 | buildTypes { 58 | release { 59 | // TODO: Add your own signing config for the release build. 60 | // Signing with the debug keys for now, so `flutter run --release` works. 61 | signingConfig signingConfigs.debug 62 | } 63 | } 64 | } 65 | 66 | flutter { 67 | source '../..' 68 | } 69 | 70 | dependencies { 71 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 72 | } 73 | -------------------------------------------------------------------------------- /lib/data/models/responses/add_product_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'add_product_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_AddProductResponseModel _$$_AddProductResponseModelFromJson( 10 | Map json) => 11 | _$_AddProductResponseModel( 12 | data: Restaurant.fromJson(json['data'] as Map), 13 | meta: Meta.fromJson(json['meta'] as Map), 14 | ); 15 | 16 | Map _$$_AddProductResponseModelToJson( 17 | _$_AddProductResponseModel instance) => 18 | { 19 | 'data': instance.data, 20 | 'meta': instance.meta, 21 | }; 22 | 23 | _$_Data _$$_DataFromJson(Map json) => _$_Data( 24 | id: json['id'] as int, 25 | attributes: 26 | Attributes.fromJson(json['attributes'] as Map), 27 | ); 28 | 29 | Map _$$_DataToJson(_$_Data instance) => { 30 | 'id': instance.id, 31 | 'attributes': instance.attributes, 32 | }; 33 | 34 | _$_Attributes _$$_AttributesFromJson(Map json) => 35 | _$_Attributes( 36 | name: json['name'] as String, 37 | description: json['description'] as String, 38 | latitude: json['latitude'] as String, 39 | longitude: json['longitude'] as String, 40 | address: json['address'] as String, 41 | createdAt: DateTime.parse(json['createdAt'] as String), 42 | updatedAt: DateTime.parse(json['updatedAt'] as String), 43 | publishedAt: DateTime.parse(json['publishedAt'] as String), 44 | photo: json['photo'] as String?, 45 | userId: json['userId'] as String?, 46 | ); 47 | 48 | Map _$$_AttributesToJson(_$_Attributes instance) => 49 | { 50 | 'name': instance.name, 51 | 'description': instance.description, 52 | 'latitude': instance.latitude, 53 | 'longitude': instance.longitude, 54 | 'address': instance.address, 55 | 'createdAt': instance.createdAt.toIso8601String(), 56 | 'updatedAt': instance.updatedAt.toIso8601String(), 57 | 'publishedAt': instance.publishedAt.toIso8601String(), 58 | 'photo': instance.photo, 59 | 'userId': instance.userId, 60 | }; 61 | 62 | _$_Meta _$$_MetaFromJson(Map json) => _$_Meta(); 63 | 64 | Map _$$_MetaToJson(_$_Meta instance) => {}; 65 | -------------------------------------------------------------------------------- /lib/presentation/pages/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_restaurant_fic5/bloc/get_all_product/get_all_product_bloc.dart'; 4 | import 'package:flutter_restaurant_fic5/presentation/pages/my_restaurant_page.dart'; 5 | import 'package:flutter_restaurant_fic5/presentation/widgets/restaurant_card.dart'; 6 | 7 | import 'package:go_router/go_router.dart'; 8 | 9 | 10 | class HomePage extends StatefulWidget { 11 | static const routeName = '/home'; 12 | const HomePage({super.key}); 13 | 14 | @override 15 | State createState() => _HomePageState(); 16 | } 17 | 18 | class _HomePageState extends State { 19 | final controller = ScrollController(); 20 | 21 | @override 22 | void initState() { 23 | context.read().add(const GetAllProductEvent.get()); 24 | super.initState(); 25 | } 26 | 27 | @override 28 | Widget build(BuildContext context) { 29 | return Scaffold( 30 | appBar: AppBar( 31 | automaticallyImplyLeading: false, 32 | title: const Text('List Restaurant'), 33 | actions: [], 34 | ), 35 | body: SafeArea( 36 | child: Padding( 37 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), 38 | child: BlocBuilder( 39 | builder: (context, state) { 40 | return state.when( 41 | initial: () => const Center( 42 | child: CircularProgressIndicator(), 43 | ), 44 | loading: () => 45 | const Center(child: CircularProgressIndicator()), 46 | error: () => const Text('error'), 47 | loaded: (data) { 48 | return ListView.builder( 49 | itemBuilder: (context, index) { 50 | return RestaurantCard(data: data.data[index]); 51 | }, 52 | itemCount: data.data.length, 53 | ); 54 | }, 55 | ); 56 | }, 57 | )), 58 | ), 59 | bottomNavigationBar: BottomNavigationBar( 60 | type: BottomNavigationBarType.fixed, 61 | currentIndex: 0, 62 | onTap: (value) { 63 | if (value == 1) { 64 | context.push(MyRestaurantPage.routeName); 65 | } 66 | }, 67 | items: const [ 68 | BottomNavigationBarItem( 69 | icon: Icon(Icons.restaurant), label: 'All Restaurant'), 70 | BottomNavigationBarItem( 71 | icon: Icon(Icons.person), label: 'My Account'), 72 | ], 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/data/models/direction.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:convert'; 3 | 4 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 5 | import 'package:http/http.dart' as http; 6 | 7 | class Direction { 8 | final LatLngBounds bounds; 9 | 10 | final List polylinePoints; 11 | 12 | const Direction._({ 13 | required this.bounds, 14 | required this.polylinePoints, 15 | }); 16 | 17 | static Future getDirections({ 18 | required String googleMapsApiKey, 19 | required LatLng origin, 20 | required LatLng destination, 21 | }) async { 22 | final query = { 23 | 'key': googleMapsApiKey, 24 | 'origin': '${origin.latitude},${origin.longitude}', 25 | 'destination': '${destination.latitude},${destination.longitude}', 26 | }; 27 | final response = await http.get( 28 | Uri.https("maps.googleapis.com", "/maps/api/directions/json", query), 29 | ); 30 | if (response.statusCode == 200) { 31 | final mapData = jsonDecode(response.body); 32 | if ((mapData['routes'] as List).isEmpty) { 33 | return null; 34 | } else { 35 | return Direction._fromMap(mapData); 36 | } 37 | } else { 38 | return null; 39 | } 40 | } 41 | 42 | factory Direction._fromMap(Map map) { 43 | // Get route information 44 | final data = Map.from(map['routes'][0]); 45 | 46 | // Bounds 47 | final northeast = data['bounds']['northeast']; 48 | final southwest = data['bounds']['southwest']; 49 | final bounds = LatLngBounds( 50 | northeast: LatLng(northeast['lat'], northeast['lng']), 51 | southwest: LatLng(southwest['lat'], southwest['lng']), 52 | ); 53 | 54 | return Direction._( 55 | bounds: bounds, 56 | polylinePoints: _decodePolyline(data['overview_polyline']['points']), 57 | ); 58 | } 59 | 60 | static List _decodePolyline(String encoded) { 61 | List polyLines = []; 62 | int index = 0, len = encoded.length; 63 | int lat = 0, lng = 0; 64 | 65 | while (index < len) { 66 | int b, shift = 0, result = 0; 67 | do { 68 | b = encoded.codeUnitAt(index++) - 63; 69 | result |= (b & 0x1f) << shift; 70 | shift += 5; 71 | } while (b >= 0x20); 72 | int dLat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 73 | lat += dLat; 74 | 75 | shift = 0; 76 | result = 0; 77 | do { 78 | b = encoded.codeUnitAt(index++) - 63; 79 | result |= (b & 0x1f) << shift; 80 | shift += 5; 81 | } while (b >= 0x20); 82 | int dLng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); 83 | lng += dLng; 84 | final p = LatLng((lat / 1E5).toDouble(), (lng / 1E5).toDouble()); 85 | polyLines.add(p); 86 | } 87 | return polyLines; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/bloc/detail_product/detail_product_bloc_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dartz/dartz.dart'; 4 | import 'package:flutter_restaurant_fic5/bloc/detail_product/detail_product_bloc.dart'; 5 | import 'package:flutter_restaurant_fic5/data/models/responses/add_product_response_model.dart'; 6 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart'; 7 | import 'package:flutter_test/flutter_test.dart'; 8 | import 'package:mockito/annotations.dart'; 9 | 10 | import 'package:bloc_test/bloc_test.dart'; 11 | import 'package:mockito/mockito.dart'; 12 | 13 | import 'detail_product_bloc_test.mocks.dart'; 14 | 15 | @GenerateMocks([RestaurantDatasource]) 16 | void main() { 17 | late MockRestaurantDatasource mockDatasource; 18 | late DetailProductBloc detailProductBloc; 19 | 20 | setUp(() { 21 | mockDatasource = MockRestaurantDatasource(); 22 | detailProductBloc = DetailProductBloc(mockDatasource); 23 | }); 24 | 25 | const String jsonString = '''{ 26 | "data": { 27 | "id": 1, 28 | "attributes": { 29 | "name": "Gemati Coffe", 30 | "description": "Coffe & Eatery", 31 | "latitude": "-7.550337836789965", 32 | "longitude": "110.77169609703935", 33 | "address": "Jl. Matoa Raya I", 34 | "createdAt": "2023-06-15T09:42:23.355Z", 35 | "updatedAt": "2023-06-29T13:22:49.183Z", 36 | "publishedAt": "2023-06-15T08:35:25.622Z", 37 | "photo": "https://img.freepik.com/premium-photo/grodno-belarus-march-2019-inside-interior-modern-pub-sport-bar-with-dark-loft-design-style-with-red-chairs_97694-3440.jpg", 38 | "userId": "27" 39 | } 40 | }, 41 | "meta": {} 42 | }'''; 43 | 44 | const int idProduct = 1; 45 | 46 | final modelProduct = AddProductResponseModel.fromJson(jsonDecode(jsonString)); 47 | 48 | blocTest( 49 | 'emits [Loaded] when MyEvent is get.', 50 | build: () { 51 | when(mockDatasource.getById(idProduct)) 52 | .thenAnswer((realInvocation) async { 53 | return Right(modelProduct); 54 | }); 55 | return detailProductBloc; 56 | }, 57 | act: (bloc) => bloc.add(const DetailProductEvent.get(1)), 58 | expect: () => [ 59 | const DetailProductState.loading(), 60 | DetailProductState.loaded(modelProduct), 61 | ], 62 | ); 63 | 64 | blocTest( 65 | 'emits [Error] when MyEvent is get.', 66 | build: () { 67 | when(mockDatasource.getById(idProduct)) 68 | .thenAnswer((realInvocation) async { 69 | return const Left('error'); 70 | }); 71 | return detailProductBloc; 72 | }, 73 | act: (bloc) => bloc.add(const DetailProductEvent.get(1)), 74 | expect: () => [ 75 | const DetailProductState.loading(), 76 | const DetailProductState.error('error'), 77 | ], 78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/presentation/pages/gmap_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter_bloc/flutter_bloc.dart'; 5 | import 'package:flutter_restaurant_fic5/bloc/gmap/gmap_bloc.dart'; 6 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 7 | 8 | class GmapPage extends StatefulWidget { 9 | const GmapPage({ 10 | Key? key, 11 | required this.lat, 12 | required this.long, 13 | }) : super(key: key); 14 | final double lat; 15 | final double long; 16 | 17 | @override 18 | State createState() => _GmapPageState(); 19 | } 20 | 21 | class _GmapPageState extends State { 22 | final TextEditingController addressController = TextEditingController(); 23 | late GoogleMapController _mapController; 24 | final Set _markers = {}; 25 | 26 | void _createInitialMarker() { 27 | final marker = Marker( 28 | markerId: const MarkerId("position"), 29 | position: LatLng(widget.lat, widget.long), 30 | ); 31 | 32 | _markers.add(marker); 33 | } 34 | 35 | void setNewMarker({required double lat, required double long}) async { 36 | _markers.clear(); 37 | final marker = Marker( 38 | markerId: const MarkerId("position"), 39 | position: LatLng(lat, long), 40 | ); 41 | 42 | _markers.add(marker); 43 | 44 | _mapController.animateCamera( 45 | CameraUpdate.newLatLngZoom(LatLng(lat, long), 15), 46 | ); 47 | 48 | context.read().add(GmapEvent.getSelectPosition(lat, long)); 49 | 50 | setState(() {}); 51 | } 52 | 53 | void mapController(GoogleMapController value) { 54 | _mapController = value; 55 | } 56 | 57 | @override 58 | void initState() { 59 | _createInitialMarker(); 60 | super.initState(); 61 | } 62 | 63 | @override 64 | Widget build(BuildContext context) { 65 | return Scaffold( 66 | appBar: AppBar( 67 | title: const Text('Ganti Lokasi'), 68 | automaticallyImplyLeading: false, 69 | actions: [ 70 | IconButton( 71 | onPressed: () => Navigator.pop(context), 72 | icon: const Icon(Icons.check_box), 73 | ), 74 | const SizedBox( 75 | width: 16, 76 | ) 77 | ], 78 | ), 79 | body: Stack( 80 | children: [ 81 | GoogleMap( 82 | initialCameraPosition: CameraPosition( 83 | target: LatLng(widget.lat, widget.long), 84 | ), 85 | markers: _markers, 86 | onMapCreated: (controller) { 87 | mapController(controller); 88 | }, 89 | onTap: (argument) { 90 | setNewMarker( 91 | lat: argument.latitude, 92 | long: argument.longitude, 93 | ); 94 | }, 95 | ), 96 | BlocBuilder( 97 | builder: (context, state) { 98 | return state.maybeWhen( 99 | orElse: () => const Text('No Address'), 100 | loaded: (model) { 101 | return Text(model.address ?? ''); 102 | }, 103 | ); 104 | }, 105 | ), 106 | ], 107 | ), 108 | ); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /lib/presentation/pages/my_restaurant_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_restaurant_fic5/bloc/get_all_product/get_all_product_bloc.dart'; 4 | import 'package:flutter_restaurant_fic5/data/local_datasources/auth_local_datasource.dart'; 5 | import 'package:flutter_restaurant_fic5/presentation/pages/add_restaurant_page.dart'; 6 | import 'package:flutter_restaurant_fic5/presentation/pages/home_page.dart'; 7 | import 'package:flutter_restaurant_fic5/presentation/pages/login_page.dart'; 8 | import 'package:go_router/go_router.dart'; 9 | 10 | import '../widgets/restaurant_card.dart'; 11 | 12 | class MyRestaurantPage extends StatefulWidget { 13 | static const routeName = '/my-restaurant'; 14 | const MyRestaurantPage({super.key}); 15 | 16 | @override 17 | State createState() => _MyRestaurantPageState(); 18 | } 19 | 20 | class _MyRestaurantPageState extends State { 21 | final controller = ScrollController(); 22 | 23 | @override 24 | void initState() { 25 | context 26 | .read() 27 | .add(const GetAllProductEvent.getByUserId()); 28 | super.initState(); 29 | } 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return Scaffold( 34 | appBar: AppBar( 35 | automaticallyImplyLeading: false, 36 | title: const Text('My Restaurant'), 37 | actions: [ 38 | IconButton( 39 | onPressed: () async { 40 | await AuthLocalDatasource().removeAuthData(); 41 | context.go(LoginPage.routeName); 42 | }, 43 | icon: Icon(Icons.logout)), 44 | ], 45 | ), 46 | body: SafeArea( 47 | child: Padding( 48 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), 49 | child: BlocBuilder( 50 | builder: (context, state) { 51 | return state.when( 52 | initial: () => const Center( 53 | child: CircularProgressIndicator(), 54 | ), 55 | loading: () => 56 | const Center(child: CircularProgressIndicator()), 57 | error: () => const Text('error'), 58 | loaded: (data) { 59 | return ListView.builder( 60 | itemBuilder: (context, index) { 61 | return RestaurantCard(data: data.data[index]); 62 | }, 63 | itemCount: data.data.length, 64 | ); 65 | }, 66 | ); 67 | }, 68 | )), 69 | ), 70 | floatingActionButton: FloatingActionButton( 71 | onPressed: () { 72 | context.push(AddRestaurantPage.routeName); 73 | }, 74 | child: Icon(Icons.add), 75 | ), 76 | bottomNavigationBar: BottomNavigationBar( 77 | type: BottomNavigationBarType.fixed, 78 | currentIndex: 1, 79 | onTap: (value) { 80 | if (value == 0) { 81 | context.push(HomePage.routeName); 82 | } 83 | }, 84 | items: const [ 85 | BottomNavigationBarItem( 86 | icon: Icon(Icons.restaurant), label: 'All Restaurant'), 87 | BottomNavigationBarItem( 88 | icon: Icon(Icons.person), label: 'My Account'), 89 | ], 90 | ), 91 | ); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /coverage/bloc/detail_product/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - bloc/detail_product 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - bloc/detail_productHitTotalCoverage
Test:lcov.infoLines:88100.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
detail_product_bloc.dart 68 |
100.0%
69 |
100.0 %8 / 8
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/bloc/detail_product/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - bloc/detail_product 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - bloc/detail_productHitTotalCoverage
Test:lcov.infoLines:88100.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
detail_product_bloc.dart 68 |
100.0%
69 |
100.0 %8 / 8
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/data/local_datasources/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/local_datasources 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/local_datasourcesHitTotalCoverage
Test:lcov.infoLines:0200.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
auth_local_datasource.dart 68 |
0.0%
69 |
0.0 %0 / 20
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/data/local_datasources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/local_datasources 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/local_datasourcesHitTotalCoverage
Test:lcov.infoLines:0200.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
auth_local_datasource.dart 68 |
0.0%
69 |
0.0 %0 / 20
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/data/remote_datasources/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/remote_datasources 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/remote_datasourcesHitTotalCoverage
Test:lcov.infoLines:0510.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
restaurant_datasource.dart 68 |
0.0%
69 |
0.0 %0 / 51
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/data/remote_datasources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/remote_datasources 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/remote_datasourcesHitTotalCoverage
Test:lcov.infoLines:0510.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
restaurant_datasource.dart 68 |
0.0%
69 |
0.0 %0 / 51
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/bloc/get_all_product/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - bloc/get_all_product 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - bloc/get_all_productHitTotalCoverage
Test:lcov.infoLines:91560.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
get_all_product_bloc.dart 68 |
60.0%60.0%
69 |
60.0 %9 / 15
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coverage/bloc/get_all_product/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - bloc/get_all_product 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - bloc/get_all_productHitTotalCoverage
Test:lcov.infoLines:91560.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 |

Filename Sort by nameLine Coverage Sort by line coverage
get_all_product_bloc.dart 68 |
60.0%60.0%
69 |
60.0 %9 / 15
74 |
75 |
76 | 77 | 78 | 79 | 80 |
Generated by: LCOV version 1.16
81 |
82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /lib/data/remote_datasources/gmap_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:dartz/dartz.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/services.dart'; 4 | import 'package:flutter_restaurant_fic5/data/models/gmap_model.dart'; 5 | import 'package:google_maps_flutter/google_maps_flutter.dart'; 6 | import 'package:location/location.dart'; 7 | import 'package:geocoding/geocoding.dart' as geo; 8 | 9 | class GmapDatasource { 10 | Future _getPermission(Location location) async { 11 | late bool serviceEnabled; 12 | late PermissionStatus permissionGranted; 13 | 14 | serviceEnabled = await location.serviceEnabled(); 15 | if (!serviceEnabled) { 16 | serviceEnabled = await location.requestService(); 17 | if (!serviceEnabled) { 18 | return false; 19 | } 20 | } 21 | 22 | permissionGranted = await location.hasPermission(); 23 | if (permissionGranted == PermissionStatus.denied) { 24 | permissionGranted = await location.requestPermission(); 25 | if (permissionGranted != PermissionStatus.granted) { 26 | return false; 27 | } 28 | } 29 | 30 | return true; 31 | } 32 | 33 | Future> getCurrentPosition() async { 34 | try { 35 | final Location location = Location(); 36 | late LocationData locationData; 37 | 38 | final state = await _getPermission(location); 39 | 40 | if (!state) return const Left("Permission not granted"); 41 | 42 | locationData = await location.getLocation(); 43 | final latLng = LatLng( 44 | locationData.latitude!, 45 | locationData.longitude!, 46 | ); 47 | 48 | final info = await geo.placemarkFromCoordinates( 49 | latLng.latitude, 50 | latLng.longitude, 51 | ); 52 | 53 | String? address; 54 | 55 | if (info.isNotEmpty) { 56 | final place = info[0]; 57 | address = 58 | '${place.street}, ${place.subLocality}, ${place.locality}, ${place.postalCode}, ${place.country}'; 59 | } else { 60 | address = "Location not found "; 61 | } 62 | 63 | return Right(GmapModel( 64 | latLng: latLng, 65 | address: address, 66 | )); 67 | } on PlatformException catch (e) { 68 | if (e.code == 'IO_ERROR') { 69 | debugPrint( 70 | 'A network error occurred trying to lookup the supplied coordinates: ${e.message}'); 71 | } else { 72 | debugPrint('Failed to lookup coordinates: ${e.message}'); 73 | } 74 | return Left(e.message!); 75 | } catch (e) { 76 | debugPrint('An unknown error occurred: $e'); 77 | return Left(e.toString()); 78 | } 79 | } 80 | 81 | Future> getPosition( 82 | {required double lat, required double long}) async { 83 | final Location location = Location(); 84 | late LocationData locationData; 85 | final state = await _getPermission(location); 86 | 87 | if (!state) return const Left("Permission not granted"); 88 | locationData = await location.getLocation(); 89 | final latLng = LatLng( 90 | locationData.latitude!, 91 | locationData.longitude!, 92 | ); 93 | 94 | final info = await geo.placemarkFromCoordinates( 95 | lat, 96 | long, 97 | ); 98 | 99 | String? address; 100 | if (info.isNotEmpty) { 101 | final place = info[0]; 102 | address = 103 | '${place.street}, ${place.subLocality}, ${place.locality}, ${place.postalCode}, ${place.country}'; 104 | } else { 105 | address = "Location not found "; 106 | } 107 | 108 | return Right(GmapModel( 109 | latLng: latLng, 110 | address: address, 111 | )); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /coverage/data/models/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/models 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/modelsHitTotalCoverage
Test:lcov.infoLines:0810.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 |

Filename Sort by nameLine Coverage Sort by line coverage
upload_image_response_model.dart 68 |
0.0%
69 |
0.0 %0 / 5
upload_image_response_model.g.dart 76 |
0.0%
77 |
0.0 %0 / 76
82 |
83 |
84 | 85 | 86 | 87 | 88 |
Generated by: LCOV version 1.16
89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /coverage/data/models/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/models 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/modelsHitTotalCoverage
Test:lcov.infoLines:0810.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 |

Filename Sort by nameLine Coverage Sort by line coverage
upload_image_response_model.dart 68 |
0.0%
69 |
0.0 %0 / 5
upload_image_response_model.g.dart 76 |
0.0%
77 |
0.0 %0 / 76
82 |
83 |
84 | 85 | 86 | 87 | 88 |
Generated by: LCOV version 1.16
89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_restaurant_fic5 2 | description: A new Flutter project. 3 | # The following line prevents the package from being accidentally published to 4 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 5 | publish_to: "none" # Remove this line if you wish to publish to pub.dev 6 | 7 | # The following defines the version and build number for your application. 8 | # A version number is three numbers separated by dots, like 1.2.43 9 | # followed by an optional build number separated by a +. 10 | # Both the version and the builder number may be overridden in flutter 11 | # build by specifying --build-name and --build-number, respectively. 12 | # In Android, build-name is used as versionName while build-number used as versionCode. 13 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 14 | # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. 15 | # Read more about iOS versioning at 16 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 17 | # In Windows, build-name is used as the major, minor, and patch parts 18 | # of the product and file versions while build-number is used as the build suffix. 19 | version: 1.0.0+1 20 | 21 | environment: 22 | sdk: ">=3.0.0 <4.0.0" 23 | 24 | # Dependencies specify other packages that your package needs in order to work. 25 | # To automatically upgrade your package dependencies to the latest versions 26 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 27 | # dependencies can be manually updated by changing the version numbers below to 28 | # the latest version available on pub.dev. To see which dependencies have newer 29 | # versions available, run `flutter pub outdated`. 30 | dependencies: 31 | build_runner: ^2.4.5 32 | cupertino_icons: ^1.0.2 33 | dartz: ^0.10.1 34 | flutter: 35 | sdk: flutter 36 | flutter_bloc: ^8.1.3 37 | freezed: ^2.3.5 38 | freezed_annotation: ^2.2.0 39 | geocoding: ^2.1.0 40 | go_router: ^8.0.5 41 | google_maps_flutter: ^2.2.6 42 | http: ^1.0.0 43 | image_picker: ^1.0.0 44 | json_annotation: ^4.8.1 45 | json_serializable: ^6.7.0 46 | location: ^4.4.0 47 | shared_preferences: ^2.1.2 48 | 49 | dev_dependencies: 50 | flutter_lints: ^2.0.0 51 | flutter_test: 52 | sdk: flutter 53 | mockito: ^5.4.2 54 | bloc_test: ^9.1.3 55 | 56 | # For information on the generic Dart part of this file, see the 57 | # following page: https://dart.dev/tools/pub/pubspec 58 | # The following section is specific to Flutter packages. 59 | flutter: 60 | # The following line ensures that the Material Icons font is 61 | # included with your application, so that you can use the icons in 62 | # the material Icons class. 63 | uses-material-design: true 64 | # To add assets to your application, add an assets section, like this: 65 | assets: 66 | - assets/markers/ 67 | # - images/a_dot_ham.jpeg 68 | # An image asset can refer to one or more resolution-specific "variants", see 69 | # https://flutter.dev/assets-and-images/#resolution-aware 70 | # For details regarding adding assets from package dependencies, see 71 | # https://flutter.dev/assets-and-images/#from-packages 72 | # To add custom fonts to your application, add a fonts section here, 73 | # in this "flutter" section. Each entry in this list should have a 74 | # "family" key with the font family name, and a "fonts" key with a 75 | # list giving the asset and other descriptors for the font. For 76 | # example: 77 | # fonts: 78 | # - family: Schyler 79 | # fonts: 80 | # - asset: fonts/Schyler-Regular.ttf 81 | # - asset: fonts/Schyler-Italic.ttf 82 | # style: italic 83 | # - family: Trajan Pro 84 | # fonts: 85 | # - asset: fonts/TrajanPro.ttf 86 | # - asset: fonts/TrajanPro_Bold.ttf 87 | # weight: 700 88 | # 89 | # For details regarding fonts from package dependencies, 90 | # see https://flutter.dev/custom-fonts/#from-packages 91 | -------------------------------------------------------------------------------- /coverage/data/models/requests/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/models/requests 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/models/requestsHitTotalCoverage
Test:lcov.infoLines:0240.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 |

Filename Sort by nameLine Coverage Sort by line coverage
add_product_request_model.dart 68 |
0.0%
69 |
0.0 %0 / 2
add_product_request_model.g.dart 76 |
0.0%
77 |
0.0 %0 / 22
82 |
83 |
84 | 85 | 86 | 87 | 88 |
Generated by: LCOV version 1.16
89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /coverage/data/models/requests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/models/requests 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/models/requestsHitTotalCoverage
Test:lcov.infoLines:0240.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 |

Filename Sort by nameLine Coverage Sort by line coverage
add_product_request_model.dart 68 |
0.0%
69 |
0.0 %0 / 2
add_product_request_model.g.dart 76 |
0.0%
77 |
0.0 %0 / 22
82 |
83 |
84 | 85 | 86 | 87 | 88 |
Generated by: LCOV version 1.16
89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /test/bloc/get_all_product/get_all_product_bloc_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:bloc_test/bloc_test.dart'; 4 | import 'package:dartz/dartz.dart'; 5 | import 'package:flutter_restaurant_fic5/bloc/get_all_product/get_all_product_bloc.dart'; 6 | import 'package:flutter_restaurant_fic5/data/models/responses/products_response_model.dart'; 7 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart'; 8 | import 'package:flutter_test/flutter_test.dart'; 9 | import 'package:mockito/annotations.dart'; 10 | import 'package:mockito/mockito.dart'; 11 | 12 | import 'get_all_product_bloc_test.mocks.dart'; 13 | 14 | @GenerateMocks([RestaurantDatasource]) 15 | void main() { 16 | late GetAllProductBloc getAllProductBloc; 17 | late MockRestaurantDatasource mockRestaurantDatasource; 18 | 19 | setUp(() { 20 | mockRestaurantDatasource = MockRestaurantDatasource(); 21 | getAllProductBloc = GetAllProductBloc(mockRestaurantDatasource); 22 | }); 23 | 24 | final String jsonString = ''' 25 | {"data": [ 26 | { 27 | "id": 6, 28 | "attributes": { 29 | "name": "Gemati Coffe", 30 | "description": "Coffe & Eatery", 31 | "latitude": "-7.550337836789965", 32 | "longitude": "110.77169609703935", 33 | "address": "Jl. Matoa Raya I", 34 | "createdAt": "2023-06-15T09:42:23.355Z", 35 | "updatedAt": "2023-06-29T13:22:49.183Z", 36 | "publishedAt": "2023-06-15T08:35:25.622Z", 37 | "photo": "https://img.freepik.com/premium-photo/grodno-belarus-march-2019-inside-interior-modern-pub-sport-bar-with-dark-loft-design-style-with-red-chairs_97694-3440.jpg", 38 | "userId": "27" 39 | } 40 | }, 41 | { 42 | "id": 26, 43 | "attributes": { 44 | "name": "Alang Puyuh", 45 | "description": "Cafe & Resto", 46 | "latitude": "-3.016910909077944", 47 | "longitude": "120.15385069886861", 48 | "address": "Jl. Andi Kambo", 49 | "createdAt": "2023-06-22T02:31:08.204Z", 50 | "updatedAt": "2023-06-25T08:58:03.274Z", 51 | "publishedAt": "2023-06-15T08:35:25.622Z", 52 | "photo": "https://images.unsplash.com/photo-1533090699061-11bd9fc5a96b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=686&q=80", 53 | "userId": "1" 54 | } 55 | } 56 | ], 57 | "meta": { 58 | "pagination": { 59 | "page": 1, 60 | "pageSize": 25, 61 | "pageCount": 1, 62 | "total": 19 63 | } 64 | } 65 | } 66 | '''; 67 | 68 | final modelResponse = ProductsResponseModel.fromJson(jsonDecode(jsonString)); 69 | 70 | blocTest( 71 | 'test get all product bloc, emit loaded when event get', 72 | build: () { 73 | when(mockRestaurantDatasource.getAll()) 74 | .thenAnswer((realInvocation) async { 75 | return Right(modelResponse); 76 | }); 77 | return getAllProductBloc; 78 | }, 79 | act: (bloc) => bloc.add(const GetAllProductEvent.get()), 80 | expect: () => [ 81 | const GetAllProductState.loading(), 82 | GetAllProductState.loaded(modelResponse), 83 | ], 84 | ); 85 | 86 | blocTest( 87 | 'test get all product bloc, emit error when event get', 88 | build: () { 89 | when(mockRestaurantDatasource.getAll()) 90 | .thenAnswer((realInvocation) async { 91 | return const Left('error'); 92 | }); 93 | return getAllProductBloc; 94 | }, 95 | act: (bloc) => bloc.add(const GetAllProductEvent.get()), 96 | expect: () => [ 97 | const GetAllProductState.loading(), 98 | const GetAllProductState.error(), 99 | ], 100 | ); 101 | } 102 | -------------------------------------------------------------------------------- /lib/data/models/upload_image_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'upload_image_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$_UploadImageResponseModel _$$_UploadImageResponseModelFromJson( 10 | Map json) => 11 | _$_UploadImageResponseModel( 12 | id: json['id'] as int?, 13 | name: json['name'] as String?, 14 | alternativeText: json['alternativeText'], 15 | caption: json['caption'], 16 | width: json['width'] as int?, 17 | height: json['height'] as int?, 18 | formats: json['formats'] == null 19 | ? null 20 | : Formats.fromJson(json['formats'] as Map), 21 | hash: json['hash'] as String?, 22 | ext: json['ext'] as String?, 23 | mime: json['mime'] as String?, 24 | size: (json['size'] as num?)?.toDouble(), 25 | url: json['url'] as String?, 26 | previewUrl: json['previewUrl'], 27 | provider: json['provider'] as String?, 28 | providerMetadata: json['providerMetadata'], 29 | createdAt: json['createdAt'] == null 30 | ? null 31 | : DateTime.parse(json['createdAt'] as String), 32 | updatedAt: json['updatedAt'] == null 33 | ? null 34 | : DateTime.parse(json['updatedAt'] as String), 35 | ); 36 | 37 | Map _$$_UploadImageResponseModelToJson( 38 | _$_UploadImageResponseModel instance) => 39 | { 40 | 'id': instance.id, 41 | 'name': instance.name, 42 | 'alternativeText': instance.alternativeText, 43 | 'caption': instance.caption, 44 | 'width': instance.width, 45 | 'height': instance.height, 46 | 'formats': instance.formats, 47 | 'hash': instance.hash, 48 | 'ext': instance.ext, 49 | 'mime': instance.mime, 50 | 'size': instance.size, 51 | 'url': instance.url, 52 | 'previewUrl': instance.previewUrl, 53 | 'provider': instance.provider, 54 | 'providerMetadata': instance.providerMetadata, 55 | 'createdAt': instance.createdAt?.toIso8601String(), 56 | 'updatedAt': instance.updatedAt?.toIso8601String(), 57 | }; 58 | 59 | _$_Formats _$$_FormatsFromJson(Map json) => _$_Formats( 60 | thumbnail: json['thumbnail'] == null 61 | ? null 62 | : Large.fromJson(json['thumbnail'] as Map), 63 | small: json['small'] == null 64 | ? null 65 | : Large.fromJson(json['small'] as Map), 66 | medium: json['medium'] == null 67 | ? null 68 | : Large.fromJson(json['medium'] as Map), 69 | large: json['large'] == null 70 | ? null 71 | : Large.fromJson(json['large'] as Map), 72 | ); 73 | 74 | Map _$$_FormatsToJson(_$_Formats instance) => 75 | { 76 | 'thumbnail': instance.thumbnail, 77 | 'small': instance.small, 78 | 'medium': instance.medium, 79 | 'large': instance.large, 80 | }; 81 | 82 | _$_Large _$$_LargeFromJson(Map json) => _$_Large( 83 | name: json['name'] as String?, 84 | hash: json['hash'] as String?, 85 | ext: json['ext'] as String?, 86 | mime: json['mime'] as String?, 87 | path: json['path'], 88 | width: json['width'] as int?, 89 | height: json['height'] as int?, 90 | size: (json['size'] as num?)?.toDouble(), 91 | url: json['url'] as String?, 92 | ); 93 | 94 | Map _$$_LargeToJson(_$_Large instance) => { 95 | 'name': instance.name, 96 | 'hash': instance.hash, 97 | 'ext': instance.ext, 98 | 'mime': instance.mime, 99 | 'path': instance.path, 100 | 'width': instance.width, 101 | 'height': instance.height, 102 | 'size': instance.size, 103 | 'url': instance.url, 104 | }; 105 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_restaurant_fic5/bloc/add_product/add_product_bloc.dart'; 4 | import 'package:flutter_restaurant_fic5/bloc/login/login_bloc.dart'; 5 | import 'package:flutter_restaurant_fic5/bloc/register/register_bloc.dart'; 6 | import 'package:flutter_restaurant_fic5/presentation/pages/add_restaurant_page.dart'; 7 | import 'package:go_router/go_router.dart'; 8 | 9 | import 'package:flutter_restaurant_fic5/bloc/gmap/gmap_bloc.dart'; 10 | import 'package:flutter_restaurant_fic5/data/local_datasources/auth_local_datasource.dart'; 11 | import 'package:flutter_restaurant_fic5/data/remote_datasources/gmap_datasource.dart'; 12 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart'; 13 | import 'package:flutter_restaurant_fic5/presentation/pages/detail_restaurant_page.dart'; 14 | import 'package:flutter_restaurant_fic5/presentation/pages/home_page.dart'; 15 | import 'package:flutter_restaurant_fic5/presentation/pages/login_page.dart'; 16 | import 'package:flutter_restaurant_fic5/presentation/pages/my_restaurant_page.dart'; 17 | import 'package:flutter_restaurant_fic5/presentation/pages/register_page.dart'; 18 | 19 | import 'bloc/detail_product/detail_product_bloc.dart'; 20 | import 'bloc/get_all_product/get_all_product_bloc.dart'; 21 | import 'data/remote_datasources/auth_datasource.dart'; 22 | 23 | void main() { 24 | runApp(const MyApp()); 25 | } 26 | 27 | class MyApp extends StatelessWidget { 28 | const MyApp({super.key}); 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return MultiBlocProvider( 33 | providers: [ 34 | BlocProvider( 35 | create: (context) => GetAllProductBloc(RestaurantDatasource()), 36 | ), 37 | BlocProvider( 38 | create: (context) => DetailProductBloc(RestaurantDatasource()), 39 | ), 40 | BlocProvider( 41 | create: (context) => GmapBloc(GmapDatasource()), 42 | ), 43 | BlocProvider( 44 | create: (context) => RegisterBloc(AuthDataSource()), 45 | ), 46 | BlocProvider( 47 | create: (context) => LoginBloc(AuthDataSource()), 48 | ), 49 | BlocProvider( 50 | create: (context) => AddProductBloc(RestaurantDatasource()), 51 | ), 52 | ], 53 | child: MaterialApp.router( 54 | title: 'Flutter Demo', 55 | theme: ThemeData( 56 | colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), 57 | useMaterial3: true, 58 | ), 59 | routerConfig: GoRouter( 60 | initialLocation: HomePage.routeName, 61 | routes: [ 62 | GoRoute( 63 | path: LoginPage.routeName, 64 | builder: (context, state) => const LoginPage(), 65 | ), 66 | GoRoute( 67 | path: RegisterPage.routeName, 68 | builder: (context, state) => const RegisterPage(), 69 | ), 70 | GoRoute( 71 | path: HomePage.routeName, 72 | builder: (context, state) => const HomePage(), 73 | ), 74 | GoRoute( 75 | path: MyRestaurantPage.routeName, 76 | builder: (context, state) { 77 | return const MyRestaurantPage(); 78 | }, 79 | redirect: (context, state) async { 80 | final isLogin = await AuthLocalDatasource().isLogin(); 81 | if (isLogin) { 82 | return null; 83 | } else { 84 | return LoginPage.routeName; 85 | } 86 | }, 87 | ), 88 | GoRoute( 89 | path: '${DetailRestaurantPage.routeName}/:restaurantId', 90 | builder: (context, state) => DetailRestaurantPage( 91 | id: int.parse(state.pathParameters['restaurantId']!)), 92 | ), 93 | GoRoute( 94 | path: MyRestaurantPage.routeName, 95 | builder: (context, state) => const MyRestaurantPage(), 96 | ), 97 | GoRoute( 98 | path: AddRestaurantPage.routeName, 99 | builder: (context, state) => const AddRestaurantPage(), 100 | ), 101 | ], 102 | ), 103 | ), 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /lib/data/remote_datasources/restaurant_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:dartz/dartz.dart'; 4 | import 'package:flutter_restaurant_fic5/common/constants.dart'; 5 | import 'package:flutter_restaurant_fic5/data/local_datasources/auth_local_datasource.dart'; 6 | import 'package:flutter_restaurant_fic5/data/models/requests/add_product_request_model.dart'; 7 | import 'package:flutter_restaurant_fic5/data/models/responses/add_product_response_model.dart'; 8 | import 'package:flutter_restaurant_fic5/data/models/responses/products_response_model.dart'; 9 | 10 | import 'package:http/http.dart' as http; 11 | import 'package:image_picker/image_picker.dart'; 12 | 13 | import '../models/upload_image_response_model.dart'; 14 | 15 | class RestaurantDatasource { 16 | Future> getAll() async { 17 | final response = await http.get( 18 | Uri.parse('${Constants.baseUrl}/api/restaurants'), 19 | headers: { 20 | 'Content-Type': 'application/json; charset=UTF-8', 21 | }, 22 | ); 23 | 24 | if (response.statusCode == 200) { 25 | return Right( 26 | ProductsResponseModel.fromJson( 27 | jsonDecode(response.body), 28 | ), 29 | ); 30 | } else { 31 | return const Left('API ERROR'); 32 | } 33 | } 34 | 35 | Future> getByUserId(int userId) async { 36 | final response = await http.get( 37 | Uri.parse('${Constants.baseUrl}/api/restaurants?filters[userId]=$userId'), 38 | headers: { 39 | 'Content-Type': 'application/json; charset=UTF-8', 40 | }, 41 | ); 42 | 43 | if (response.statusCode == 200) { 44 | return Right( 45 | ProductsResponseModel.fromJson( 46 | jsonDecode(response.body), 47 | ), 48 | ); 49 | } else { 50 | return const Left('API ERROR'); 51 | } 52 | } 53 | 54 | Future> getById(int id) async { 55 | final response = await http.get( 56 | Uri.parse('${Constants.baseUrl}/api/restaurants/$id'), 57 | headers: { 58 | 'Content-Type': 'application/json; charset=UTF-8', 59 | }, 60 | ); 61 | 62 | if (response.statusCode == 200) { 63 | return Right( 64 | AddProductResponseModel.fromJson( 65 | jsonDecode(response.body), 66 | ), 67 | ); 68 | } else { 69 | return const Left('API ERROR'); 70 | } 71 | } 72 | 73 | Future> addProduct( 74 | AddProductRequestModel model) async { 75 | final token = await AuthLocalDatasource().getToken(); 76 | final response = await http.post( 77 | Uri.parse('${Constants.baseUrl}/api/restaurants'), 78 | headers: { 79 | 'Content-Type': 'application/json; charset=UTF-8', 80 | 'Authorization': 'Bearer $token', 81 | }, 82 | body: jsonEncode(model.toJson()), 83 | ); 84 | 85 | if (response.statusCode == 200) { 86 | return Right( 87 | AddProductResponseModel.fromJson( 88 | jsonDecode(response.body), 89 | ), 90 | ); 91 | } else { 92 | return const Left('API ERROR'); 93 | } 94 | } 95 | 96 | Future> uploadImage( 97 | XFile image) async { 98 | final token = await AuthLocalDatasource().getToken(); 99 | final header = { 100 | 'Authorization': 'Bearer $token', 101 | }; 102 | final request = http.MultipartRequest( 103 | 'POST', 104 | Uri.parse('${Constants.baseUrl}/api/upload'), 105 | ); 106 | 107 | final bytes = await image.readAsBytes(); 108 | 109 | final multiPartFile = 110 | http.MultipartFile.fromBytes('files', bytes, filename: image.name); 111 | 112 | request.files.add(multiPartFile); 113 | request.headers.addAll(header); 114 | 115 | http.StreamedResponse response = await request.send(); 116 | 117 | final responseList = await response.stream.toBytes(); 118 | final String responseData = String.fromCharCodes(responseList); 119 | 120 | if (response.statusCode == 200) { 121 | return Right( 122 | UploadImageResponseModel.fromJson(jsonDecode(responseData)[0])); 123 | } else { 124 | return const Left('error upload image'); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /test/bloc/detail_product/detail_product_bloc_test.mocks.dart: -------------------------------------------------------------------------------- 1 | // Mocks generated by Mockito 5.4.2 from annotations 2 | // in flutter_restaurant_fic5/test/bloc/detail_product/detail_product_bloc_test.dart. 3 | // Do not manually edit this file. 4 | 5 | // ignore_for_file: no_leading_underscores_for_library_prefixes 6 | import 'dart:async' as _i4; 7 | 8 | import 'package:dartz/dartz.dart' as _i2; 9 | import 'package:flutter_restaurant_fic5/data/models/requests/add_product_request_model.dart' 10 | as _i7; 11 | import 'package:flutter_restaurant_fic5/data/models/responses/add_product_response_model.dart' 12 | as _i6; 13 | import 'package:flutter_restaurant_fic5/data/models/responses/products_response_model.dart' 14 | as _i5; 15 | import 'package:flutter_restaurant_fic5/data/models/upload_image_response_model.dart' 16 | as _i8; 17 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart' 18 | as _i3; 19 | import 'package:image_picker/image_picker.dart' as _i9; 20 | import 'package:mockito/mockito.dart' as _i1; 21 | 22 | // ignore_for_file: type=lint 23 | // ignore_for_file: avoid_redundant_argument_values 24 | // ignore_for_file: avoid_setters_without_getters 25 | // ignore_for_file: comment_references 26 | // ignore_for_file: implementation_imports 27 | // ignore_for_file: invalid_use_of_visible_for_testing_member 28 | // ignore_for_file: prefer_const_constructors 29 | // ignore_for_file: unnecessary_parenthesis 30 | // ignore_for_file: camel_case_types 31 | // ignore_for_file: subtype_of_sealed_class 32 | 33 | class _FakeEither_0 extends _i1.SmartFake implements _i2.Either { 34 | _FakeEither_0( 35 | Object parent, 36 | Invocation parentInvocation, 37 | ) : super( 38 | parent, 39 | parentInvocation, 40 | ); 41 | } 42 | 43 | /// A class which mocks [RestaurantDatasource]. 44 | /// 45 | /// See the documentation for Mockito's code generation for more information. 46 | class MockRestaurantDatasource extends _i1.Mock 47 | implements _i3.RestaurantDatasource { 48 | MockRestaurantDatasource() { 49 | _i1.throwOnMissingStub(this); 50 | } 51 | 52 | @override 53 | _i4.Future<_i2.Either> getAll() => 54 | (super.noSuchMethod( 55 | Invocation.method( 56 | #getAll, 57 | [], 58 | ), 59 | returnValue: 60 | _i4.Future<_i2.Either>.value( 61 | _FakeEither_0( 62 | this, 63 | Invocation.method( 64 | #getAll, 65 | [], 66 | ), 67 | )), 68 | ) as _i4.Future<_i2.Either>); 69 | @override 70 | _i4.Future<_i2.Either> getByUserId( 71 | int? userId) => 72 | (super.noSuchMethod( 73 | Invocation.method( 74 | #getByUserId, 75 | [userId], 76 | ), 77 | returnValue: 78 | _i4.Future<_i2.Either>.value( 79 | _FakeEither_0( 80 | this, 81 | Invocation.method( 82 | #getByUserId, 83 | [userId], 84 | ), 85 | )), 86 | ) as _i4.Future<_i2.Either>); 87 | @override 88 | _i4.Future<_i2.Either> getById( 89 | int? id) => 90 | (super.noSuchMethod( 91 | Invocation.method( 92 | #getById, 93 | [id], 94 | ), 95 | returnValue: 96 | _i4.Future<_i2.Either>.value( 97 | _FakeEither_0( 98 | this, 99 | Invocation.method( 100 | #getById, 101 | [id], 102 | ), 103 | )), 104 | ) as _i4.Future<_i2.Either>); 105 | @override 106 | _i4.Future<_i2.Either> addProduct( 107 | _i7.AddProductRequestModel? model) => 108 | (super.noSuchMethod( 109 | Invocation.method( 110 | #addProduct, 111 | [model], 112 | ), 113 | returnValue: 114 | _i4.Future<_i2.Either>.value( 115 | _FakeEither_0( 116 | this, 117 | Invocation.method( 118 | #addProduct, 119 | [model], 120 | ), 121 | )), 122 | ) as _i4.Future<_i2.Either>); 123 | @override 124 | _i4.Future<_i2.Either> uploadImage( 125 | _i9.XFile? image) => 126 | (super.noSuchMethod( 127 | Invocation.method( 128 | #uploadImage, 129 | [image], 130 | ), 131 | returnValue: 132 | _i4.Future<_i2.Either>.value( 133 | _FakeEither_0( 134 | this, 135 | Invocation.method( 136 | #uploadImage, 137 | [image], 138 | ), 139 | )), 140 | ) as _i4.Future<_i2.Either>); 141 | } 142 | -------------------------------------------------------------------------------- /test/bloc/get_all_product/get_all_product_bloc_test.mocks.dart: -------------------------------------------------------------------------------- 1 | // Mocks generated by Mockito 5.4.2 from annotations 2 | // in flutter_restaurant_fic5/test/bloc/get_all_product/get_all_product_bloc_test.dart. 3 | // Do not manually edit this file. 4 | 5 | // ignore_for_file: no_leading_underscores_for_library_prefixes 6 | import 'dart:async' as _i4; 7 | 8 | import 'package:dartz/dartz.dart' as _i2; 9 | import 'package:flutter_restaurant_fic5/data/models/requests/add_product_request_model.dart' 10 | as _i7; 11 | import 'package:flutter_restaurant_fic5/data/models/responses/add_product_response_model.dart' 12 | as _i6; 13 | import 'package:flutter_restaurant_fic5/data/models/responses/products_response_model.dart' 14 | as _i5; 15 | import 'package:flutter_restaurant_fic5/data/models/upload_image_response_model.dart' 16 | as _i8; 17 | import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart' 18 | as _i3; 19 | import 'package:image_picker/image_picker.dart' as _i9; 20 | import 'package:mockito/mockito.dart' as _i1; 21 | 22 | // ignore_for_file: type=lint 23 | // ignore_for_file: avoid_redundant_argument_values 24 | // ignore_for_file: avoid_setters_without_getters 25 | // ignore_for_file: comment_references 26 | // ignore_for_file: implementation_imports 27 | // ignore_for_file: invalid_use_of_visible_for_testing_member 28 | // ignore_for_file: prefer_const_constructors 29 | // ignore_for_file: unnecessary_parenthesis 30 | // ignore_for_file: camel_case_types 31 | // ignore_for_file: subtype_of_sealed_class 32 | 33 | class _FakeEither_0 extends _i1.SmartFake implements _i2.Either { 34 | _FakeEither_0( 35 | Object parent, 36 | Invocation parentInvocation, 37 | ) : super( 38 | parent, 39 | parentInvocation, 40 | ); 41 | } 42 | 43 | /// A class which mocks [RestaurantDatasource]. 44 | /// 45 | /// See the documentation for Mockito's code generation for more information. 46 | class MockRestaurantDatasource extends _i1.Mock 47 | implements _i3.RestaurantDatasource { 48 | MockRestaurantDatasource() { 49 | _i1.throwOnMissingStub(this); 50 | } 51 | 52 | @override 53 | _i4.Future<_i2.Either> getAll() => 54 | (super.noSuchMethod( 55 | Invocation.method( 56 | #getAll, 57 | [], 58 | ), 59 | returnValue: 60 | _i4.Future<_i2.Either>.value( 61 | _FakeEither_0( 62 | this, 63 | Invocation.method( 64 | #getAll, 65 | [], 66 | ), 67 | )), 68 | ) as _i4.Future<_i2.Either>); 69 | @override 70 | _i4.Future<_i2.Either> getByUserId( 71 | int? userId) => 72 | (super.noSuchMethod( 73 | Invocation.method( 74 | #getByUserId, 75 | [userId], 76 | ), 77 | returnValue: 78 | _i4.Future<_i2.Either>.value( 79 | _FakeEither_0( 80 | this, 81 | Invocation.method( 82 | #getByUserId, 83 | [userId], 84 | ), 85 | )), 86 | ) as _i4.Future<_i2.Either>); 87 | @override 88 | _i4.Future<_i2.Either> getById( 89 | int? id) => 90 | (super.noSuchMethod( 91 | Invocation.method( 92 | #getById, 93 | [id], 94 | ), 95 | returnValue: 96 | _i4.Future<_i2.Either>.value( 97 | _FakeEither_0( 98 | this, 99 | Invocation.method( 100 | #getById, 101 | [id], 102 | ), 103 | )), 104 | ) as _i4.Future<_i2.Either>); 105 | @override 106 | _i4.Future<_i2.Either> addProduct( 107 | _i7.AddProductRequestModel? model) => 108 | (super.noSuchMethod( 109 | Invocation.method( 110 | #addProduct, 111 | [model], 112 | ), 113 | returnValue: 114 | _i4.Future<_i2.Either>.value( 115 | _FakeEither_0( 116 | this, 117 | Invocation.method( 118 | #addProduct, 119 | [model], 120 | ), 121 | )), 122 | ) as _i4.Future<_i2.Either>); 123 | @override 124 | _i4.Future<_i2.Either> uploadImage( 125 | _i9.XFile? image) => 126 | (super.noSuchMethod( 127 | Invocation.method( 128 | #uploadImage, 129 | [image], 130 | ), 131 | returnValue: 132 | _i4.Future<_i2.Either>.value( 133 | _FakeEither_0( 134 | this, 135 | Invocation.method( 136 | #uploadImage, 137 | [image], 138 | ), 139 | )), 140 | ) as _i4.Future<_i2.Either>); 141 | } 142 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | SF:lib/bloc/detail_product/detail_product_bloc.dart 2 | DA:14,1 3 | DA:16,1 4 | DA:17,2 5 | DA:18,1 6 | DA:19,3 7 | DA:20,1 8 | DA:21,3 9 | DA:22,3 10 | LF:8 11 | LH:8 12 | end_of_record 13 | SF:lib/data/models/responses/add_product_response_model.dart 14 | DA:19,1 15 | DA:20,1 16 | DA:30,2 17 | DA:31,2 18 | DA:49,2 19 | DA:50,2 20 | DA:57,2 21 | LF:7 22 | LH:7 23 | end_of_record 24 | SF:lib/data/models/responses/add_product_response_model.g.dart 25 | DA:9,1 26 | DA:11,1 27 | DA:12,2 28 | DA:13,2 29 | DA:16,0 30 | DA:18,0 31 | DA:19,0 32 | DA:20,0 33 | DA:23,4 34 | DA:24,2 35 | DA:26,4 36 | DA:29,0 37 | DA:30,0 38 | DA:31,0 39 | DA:34,2 40 | DA:35,2 41 | DA:36,2 42 | DA:37,2 43 | DA:38,2 44 | DA:39,2 45 | DA:40,2 46 | DA:41,4 47 | DA:42,4 48 | DA:43,4 49 | DA:44,2 50 | DA:45,2 51 | DA:48,0 52 | DA:49,0 53 | DA:50,0 54 | DA:51,0 55 | DA:52,0 56 | DA:53,0 57 | DA:54,0 58 | DA:55,0 59 | DA:56,0 60 | DA:57,0 61 | DA:58,0 62 | DA:59,0 63 | DA:62,2 64 | DA:64,0 65 | LF:40 66 | LH:20 67 | end_of_record 68 | SF:lib/data/remote_datasources/restaurant_datasource.dart 69 | DA:16,0 70 | DA:17,0 71 | DA:18,0 72 | DA:19,0 73 | DA:24,0 74 | DA:25,0 75 | DA:26,0 76 | DA:27,0 77 | DA:35,0 78 | DA:36,0 79 | DA:37,0 80 | DA:38,0 81 | DA:43,0 82 | DA:44,0 83 | DA:45,0 84 | DA:46,0 85 | DA:54,0 86 | DA:55,0 87 | DA:56,0 88 | DA:57,0 89 | DA:62,0 90 | DA:63,0 91 | DA:64,0 92 | DA:65,0 93 | DA:73,0 94 | DA:75,0 95 | DA:76,0 96 | DA:77,0 97 | DA:78,0 98 | DA:80,0 99 | DA:82,0 100 | DA:85,0 101 | DA:86,0 102 | DA:87,0 103 | DA:88,0 104 | DA:96,0 105 | DA:98,0 106 | DA:99,0 107 | DA:100,0 108 | DA:102,0 109 | DA:104,0 110 | DA:107,0 111 | DA:110,0 112 | DA:112,0 113 | DA:113,0 114 | DA:115,0 115 | DA:117,0 116 | DA:118,0 117 | DA:120,0 118 | DA:121,0 119 | DA:122,0 120 | LF:51 121 | LH:0 122 | end_of_record 123 | SF:lib/data/models/requests/add_product_request_model.dart 124 | DA:18,0 125 | DA:33,0 126 | LF:2 127 | LH:0 128 | end_of_record 129 | SF:lib/data/models/requests/add_product_request_model.g.dart 130 | DA:9,0 131 | DA:11,0 132 | DA:12,0 133 | DA:15,0 134 | DA:17,0 135 | DA:18,0 136 | DA:21,0 137 | DA:22,0 138 | DA:23,0 139 | DA:24,0 140 | DA:25,0 141 | DA:26,0 142 | DA:27,0 143 | DA:28,0 144 | DA:31,0 145 | DA:32,0 146 | DA:33,0 147 | DA:34,0 148 | DA:35,0 149 | DA:36,0 150 | DA:37,0 151 | DA:38,0 152 | LF:22 153 | LH:0 154 | end_of_record 155 | SF:lib/data/models/responses/products_response_model.dart 156 | DA:20,1 157 | DA:21,1 158 | DA:30,2 159 | DA:42,1 160 | DA:43,1 161 | LF:5 162 | LH:5 163 | end_of_record 164 | SF:lib/data/models/responses/products_response_model.g.dart 165 | DA:9,1 166 | DA:11,1 167 | DA:12,1 168 | DA:13,3 169 | DA:14,1 170 | DA:15,2 171 | DA:18,0 172 | DA:20,0 173 | DA:21,0 174 | DA:22,0 175 | DA:25,2 176 | DA:27,2 177 | DA:30,0 178 | DA:31,0 179 | DA:34,1 180 | DA:35,1 181 | DA:36,1 182 | DA:37,1 183 | DA:38,1 184 | DA:39,1 185 | DA:42,0 186 | DA:43,0 187 | DA:44,0 188 | DA:45,0 189 | DA:46,0 190 | DA:47,0 191 | LF:26 192 | LH:14 193 | end_of_record 194 | SF:lib/data/models/upload_image_response_model.dart 195 | DA:33,0 196 | DA:34,0 197 | DA:46,0 198 | DA:47,0 199 | DA:64,0 200 | LF:5 201 | LH:0 202 | end_of_record 203 | SF:lib/data/models/upload_image_response_model.g.dart 204 | DA:9,0 205 | DA:11,0 206 | DA:12,0 207 | DA:13,0 208 | DA:14,0 209 | DA:15,0 210 | DA:16,0 211 | DA:17,0 212 | DA:18,0 213 | DA:20,0 214 | DA:21,0 215 | DA:22,0 216 | DA:23,0 217 | DA:24,0 218 | DA:25,0 219 | DA:26,0 220 | DA:27,0 221 | DA:28,0 222 | DA:29,0 223 | DA:31,0 224 | DA:32,0 225 | DA:34,0 226 | DA:37,0 227 | DA:39,0 228 | DA:40,0 229 | DA:41,0 230 | DA:42,0 231 | DA:43,0 232 | DA:44,0 233 | DA:45,0 234 | DA:46,0 235 | DA:47,0 236 | DA:48,0 237 | DA:49,0 238 | DA:50,0 239 | DA:51,0 240 | DA:52,0 241 | DA:53,0 242 | DA:54,0 243 | DA:55,0 244 | DA:56,0 245 | DA:59,0 246 | DA:60,0 247 | DA:62,0 248 | DA:63,0 249 | DA:65,0 250 | DA:66,0 251 | DA:68,0 252 | DA:69,0 253 | DA:71,0 254 | DA:74,0 255 | DA:75,0 256 | DA:76,0 257 | DA:77,0 258 | DA:78,0 259 | DA:79,0 260 | DA:82,0 261 | DA:83,0 262 | DA:84,0 263 | DA:85,0 264 | DA:86,0 265 | DA:87,0 266 | DA:88,0 267 | DA:89,0 268 | DA:90,0 269 | DA:91,0 270 | DA:94,0 271 | DA:95,0 272 | DA:96,0 273 | DA:97,0 274 | DA:98,0 275 | DA:99,0 276 | DA:100,0 277 | DA:101,0 278 | DA:102,0 279 | DA:103,0 280 | LF:76 281 | LH:0 282 | end_of_record 283 | SF:lib/data/local_datasources/auth_local_datasource.dart 284 | DA:7,0 285 | DA:8,0 286 | DA:9,0 287 | DA:13,0 288 | DA:14,0 289 | DA:15,0 290 | DA:18,0 291 | DA:19,0 292 | DA:20,0 293 | DA:21,0 294 | DA:22,0 295 | DA:25,0 296 | DA:26,0 297 | DA:27,0 298 | DA:28,0 299 | DA:29,0 300 | DA:32,0 301 | DA:33,0 302 | DA:34,0 303 | DA:36,0 304 | LF:20 305 | LH:0 306 | end_of_record 307 | SF:lib/data/models/responses/auth_response_model.dart 308 | DA:19,0 309 | DA:35,0 310 | LF:2 311 | LH:0 312 | end_of_record 313 | SF:lib/data/models/responses/auth_response_model.g.dart 314 | DA:9,0 315 | DA:10,0 316 | DA:11,0 317 | DA:12,0 318 | DA:15,0 319 | DA:17,0 320 | DA:18,0 321 | DA:19,0 322 | DA:22,0 323 | DA:23,0 324 | DA:24,0 325 | DA:25,0 326 | DA:26,0 327 | DA:27,0 328 | DA:28,0 329 | DA:29,0 330 | DA:30,0 331 | DA:33,0 332 | DA:34,0 333 | DA:35,0 334 | DA:36,0 335 | DA:37,0 336 | DA:38,0 337 | DA:39,0 338 | DA:40,0 339 | DA:41,0 340 | LF:26 341 | LH:0 342 | end_of_record 343 | SF:lib/bloc/get_all_product/get_all_product_bloc.dart 344 | DA:15,1 345 | DA:17,1 346 | DA:18,2 347 | DA:19,1 348 | DA:20,2 349 | DA:21,1 350 | DA:22,2 351 | DA:23,3 352 | DA:27,1 353 | DA:28,0 354 | DA:29,0 355 | DA:30,0 356 | DA:31,0 357 | DA:32,0 358 | DA:33,0 359 | LF:15 360 | LH:9 361 | end_of_record 362 | -------------------------------------------------------------------------------- /coverage/bloc/detail_product/detail_product_bloc.dart.gcov.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - bloc/detail_product/detail_product_bloc.dart 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - bloc/detail_product - detail_product_bloc.dartHitTotalCoverage
Test:lcov.infoLines:88100.0 %
Date:2023-07-11 20:39:56
45 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 87 | 88 |

57 |
          Line data    Source code
58 |
59 |        1             : import 'package:bloc/bloc.dart';
60 |        2             : import 'package:freezed_annotation/freezed_annotation.dart';
61 |        3             : 
62 |        4             : import 'package:flutter_restaurant_fic5/data/remote_datasources/restaurant_datasource.dart';
63 |        5             : 
64 |        6             : import '../../data/models/responses/add_product_response_model.dart';
65 |        7             : 
66 |        8             : part 'detail_product_bloc.freezed.dart';
67 |        9             : part 'detail_product_event.dart';
68 |       10             : part 'detail_product_state.dart';
69 |       11             : 
70 |       12             : class DetailProductBloc extends Bloc<DetailProductEvent, DetailProductState> {
71 |       13             :   final RestaurantDatasource datasource;
72 |       14           1 :   DetailProductBloc(
73 |       15             :     this.datasource,
74 |       16           1 :   ) : super(const _Initial()) {
75 |       17           2 :     on<_Get>((event, emit) async {
76 |       18           1 :       emit(const _Loading());
77 |       19           3 :       final result = await datasource.getById(event.id);
78 |       20           1 :       result.fold(
79 |       21           3 :         (l) => emit(_Error(l)),
80 |       22           3 :         (r) => emit(_Loaded(r)),
81 |       23             :       );
82 |       24             :     });
83 |       25             :   }
84 |       26             : }
85 | 
86 |
89 |
90 | 91 | 92 | 93 | 94 |
Generated by: LCOV version 1.16
95 |
96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /coverage/data/models/responses/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/models/responses 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/models/responsesHitTotalCoverage
Test:lcov.infoLines:4610643.4 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | 106 | 107 | 110 | 111 | 112 | 113 |

Filename Sort by nameLine Coverage Sort by line coverage
auth_response_model.dart 68 |
0.0%
69 |
0.0 %0 / 2
auth_response_model.g.dart 76 |
0.0%
77 |
0.0 %0 / 26
add_product_response_model.g.dart 84 |
50.0%50.0%
85 |
50.0 %20 / 40
products_response_model.g.dart 92 |
53.8%53.8%
93 |
53.8 %14 / 26
products_response_model.dart 100 |
100.0%
101 |
100.0 %5 / 5
add_product_response_model.dart 108 |
100.0%
109 |
100.0 %7 / 7
114 |
115 |
116 | 117 | 118 | 119 | 120 |
Generated by: LCOV version 1.16
121 |
122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /coverage/data/models/responses/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info - data/models/responses 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top level - data/models/responsesHitTotalCoverage
Test:lcov.infoLines:4610643.4 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | 106 | 107 | 110 | 111 | 112 | 113 |

Filename Sort by nameLine Coverage Sort by line coverage
add_product_response_model.dart 68 |
100.0%
69 |
100.0 %7 / 7
add_product_response_model.g.dart 76 |
50.0%50.0%
77 |
50.0 %20 / 40
auth_response_model.dart 84 |
0.0%
85 |
0.0 %0 / 2
auth_response_model.g.dart 92 |
0.0%
93 |
0.0 %0 / 26
products_response_model.dart 100 |
100.0%
101 |
100.0 %5 / 5
products_response_model.g.dart 108 |
53.8%53.8%
109 |
53.8 %14 / 26
114 |
115 |
116 | 117 | 118 | 119 | 120 |
Generated by: LCOV version 1.16
121 |
122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /coverage/index-sort-l.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | LCOV - lcov.info 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 |
LCOV - code coverage report
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Current view:top levelHitTotalCoverage
Test:lcov.infoLines:6330520.7 %
Date:2023-07-11 20:39:56
45 |
50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 70 | 71 | 72 | 73 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | 106 | 107 | 110 | 111 | 112 | 113 | 114 | 115 | 118 | 119 | 120 | 121 |

Directory Sort by nameLine Coverage Sort by line coverage
data/local_datasources 68 |
0.0%
69 |
0.0 %0 / 20
data/models/requests 76 |
0.0%
77 |
0.0 %0 / 24
data/remote_datasources 84 |
0.0%
85 |
0.0 %0 / 51
data/models 92 |
0.0%
93 |
0.0 %0 / 81
data/models/responses 100 |
43.4%43.4%
101 |
43.4 %46 / 106
bloc/get_all_product 108 |
60.0%60.0%
109 |
60.0 %9 / 15
bloc/detail_product 116 |
100.0%
117 |
100.0 %8 / 8
122 |
123 |
124 | 125 | 126 | 127 | 128 |
Generated by: LCOV version 1.16
129 |
130 | 131 | 132 | 133 | --------------------------------------------------------------------------------