Feat: done fetch image from database

This commit is contained in:
orangdeso 2025-03-29 21:45:22 +07:00
parent c3c0f41269
commit 5535879255
17 changed files with 222 additions and 76 deletions

View File

@ -157,6 +157,24 @@
"packageUri": "lib/",
"languageVersion": "3.4"
},
{
"name": "firebase_storage",
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage-12.4.4",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "firebase_storage_platform_interface",
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_platform_interface-5.2.4",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "firebase_storage_web",
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_web-3.10.11",
"packageUri": "lib/",
"languageVersion": "3.4"
},
{
"name": "flutter",
"rootUri": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0/packages/flutter",
@ -500,7 +518,7 @@
"languageVersion": "3.4"
}
],
"generated": "2025-03-26T12:09:54.704663Z",
"generated": "2025-03-29T09:11:46.461455Z",
"generator": "pub",
"generatorVersion": "3.5.0",
"flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0",

View File

@ -102,6 +102,18 @@ firebase_core_web
3.4
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_core_web-2.21.1/
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_core_web-2.21.1/lib/
firebase_storage
3.2
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage-12.4.4/
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage-12.4.4/lib/
firebase_storage_platform_interface
3.2
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_platform_interface-5.2.4/
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_platform_interface-5.2.4/lib/
firebase_storage_web
3.4
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_web-3.10.11/
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/firebase_storage_web-3.10.11/lib/
flutter_picker
2.12
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/flutter_picker-2.1.0/

View File

@ -49,6 +49,7 @@ class FlightModel {
final String transitAirplane;
final String stop;
final int price;
final String airlineLogo;
final Map<String, SeatInfo> seat;
FlightModel({
@ -66,6 +67,7 @@ class FlightModel {
required this.transitAirplane,
required this.stop,
required this.price,
required this.airlineLogo,
required this.seat,
});
@ -100,6 +102,7 @@ class FlightModel {
transitAirplane: data['transitAirplane'] ?? '',
stop: data['stop'] ?? '',
price: data['price'] ?? 0,
airlineLogo: data['airlineLogo'] ?? '',
seat: seatMap, // masukkan Map<String, SeatInfo>
);
}
@ -119,7 +122,7 @@ class FlightModel {
'transitAirplane': transitAirplane,
'stop': stop,
'price': price,
// Konversi Map<String, SeatInfo> jadi Map<String, Map<String,dynamic>>
'airlineLogo': airlineLogo,
'seat': seat.map((key, value) => MapEntry(key, value.toMap())),
};
}

View File

@ -1,4 +1,4 @@
import 'package:e_porter/_core/service/logger_service.dart';
import 'dart:developer';
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
@ -9,7 +9,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
logger.d("Firebase Initialized Successfully!");
log("Firebase Initialized Successfully!");
runApp(MyApp(initialRoute: Routes.SPLASH));
}

View File

@ -21,6 +21,7 @@ class CardFlightInformation extends StatelessWidget {
final String? departurePorter;
final String? arrivalPorter;
final String? transitPorter;
final String? airlineLogo;
const CardFlightInformation({
Key? key,
@ -37,6 +38,7 @@ class CardFlightInformation extends StatelessWidget {
this.departurePorter,
this.arrivalPorter,
this.transitPorter,
this.airlineLogo,
});
@override
@ -45,7 +47,29 @@ class CardFlightInformation extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
airlineLogo != null && airlineLogo!.isNotEmpty
? Image.network(
airlineLogo!,
width: 40.w,
height: 26.h,
errorBuilder: (context, error, stackTrace) {
print("Error loading image: $error");
return Container(
width: 40.w,
height: 10.h,
child: Center(child: Icon(Icons.error)),
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
width: 40.w,
height: 10.h,
child: Center(child: CircularProgressIndicator(strokeWidth: 1.0)),
);
},
)
: SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
SizedBox(height: 10.h),
Row(
children: [
@ -91,17 +115,17 @@ class CardFlightInformation extends StatelessWidget {
servicePorter != null ? _buildText(context, text: servicePorter!) : SizedBox.shrink(),
],
),
if (departurePorter != null && departurePorter!.isNotEmpty) ... [
SizedBox(height: 4.h),
TypographyStyles.small(departurePorter!, color: GrayColors.gray600, fontWeight: FontWeight.w400),
if (departurePorter != null && departurePorter!.isNotEmpty) ...[
SizedBox(height: 4.h),
TypographyStyles.small(departurePorter!, color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
if (arrivalPorter != null && arrivalPorter!.isNotEmpty) ... [
SizedBox(height: 4.h),
TypographyStyles.small(arrivalPorter!, color: GrayColors.gray600, fontWeight: FontWeight.w400),
if (arrivalPorter != null && arrivalPorter!.isNotEmpty) ...[
SizedBox(height: 4.h),
TypographyStyles.small(arrivalPorter!, color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
if (transitPorter != null && transitPorter!.isNotEmpty) ... [
SizedBox(height: 4.h),
TypographyStyles.small(transitPorter!, color: GrayColors.gray600, fontWeight: FontWeight.w400),
if (transitPorter != null && transitPorter!.isNotEmpty) ...[
SizedBox(height: 4.h),
TypographyStyles.small(transitPorter!, color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
SizedBox(height: 4.h),
TypographyStyles.small(

View File

@ -7,6 +7,8 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
const bool DEBUG_LOGO = false;
class CardTickets extends StatelessWidget {
final String departureCity;
final String date;
@ -21,6 +23,7 @@ class CardTickets extends StatelessWidget {
final VoidCallback? onTap;
final bool withContainer;
final bool showFooter;
final String? airlineLogo;
const CardTickets({
Key? key,
@ -37,6 +40,7 @@ class CardTickets extends StatelessWidget {
this.onTap,
this.withContainer = true,
this.showFooter = true,
this.airlineLogo,
});
@override
@ -44,7 +48,29 @@ class CardTickets extends StatelessWidget {
Widget content = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
airlineLogo != null && airlineLogo!.isNotEmpty
? Image.network(
airlineLogo!,
width: 40.w,
height: 26.h,
errorBuilder: (context, error, stackTrace) {
print("Error loading image: $error");
return Container(
width: 40.w,
height: 10.h,
child: Center(child: Icon(Icons.error)),
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
width: 40.w,
height: 10.h,
child: Center(child: CircularProgressIndicator(strokeWidth: 1.0)),
);
},
)
: SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 26.h),
SizedBox(height: 10.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@ -111,6 +111,7 @@ class _ChooseSeatScreenState extends State<ChooseSeatScreen> {
final codeArrival = flight.codeArrival;
final codeTransit = flight.codeTransit;
final flightClass = flight.flightClass;
final airlineLogo = flight.airlineLogo;
cityDeparture = flight.cityDeparture;
cityArrival = flight.cityArrival;
@ -177,7 +178,14 @@ class _ChooseSeatScreenState extends State<ChooseSeatScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildCardFlight(codeDeparture, codeTransit, codeArrival, flightClass, finalDuration),
_buildCardFlight(
departureCode: codeDeparture,
transitCode: codeTransit,
arrivalCode: codeArrival,
kelas: flightClass,
duration: finalDuration,
airlineLogo: airlineLogo,
),
SizedBox(height: 20.h),
SizedBox(
height: 84.h,
@ -264,13 +272,42 @@ class _ChooseSeatScreenState extends State<ChooseSeatScreen> {
);
}
Widget _buildCardFlight(String departureCode, String transitCode, String arrivalCode, String kelas, String duration) {
Widget _buildCardFlight({
required String departureCode,
required String transitCode,
required String arrivalCode,
required String kelas,
required String duration,
String? airlineLogo,
}) {
return Padding(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 20.h),
child: CustomeShadowCotainner(
child: Row(
children: [
SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
airlineLogo != null && airlineLogo.isNotEmpty
? Image.network(
airlineLogo,
width: 40.w,
height: 26.h,
errorBuilder: (context, error, stackTrace) {
print("Error loading image: $error");
return Container(
width: 40.w,
height: 10.h,
child: Center(child: Icon(Icons.error)),
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
width: 40.w,
height: 10.h,
child: Center(child: CircularProgressIndicator(strokeWidth: 1.0)),
);
},
)
: SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
SizedBox(width: 16.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -374,35 +411,6 @@ class _ChooseSeatScreenState extends State<ChooseSeatScreen> {
);
}
// Widget _buildCardSeat(
// BuildContext context, {
// required label,
// }) {
// return Expanded(
// child: Column(
// children: [
// Container(
// width: 32.w,
// height: 32.h,
// child: TypographyStyles.body(label, color: GrayColors.gray800, fontWeight: FontWeight.w500),
// ),
// SizedBox(height: 6.h),
// ListView.builder(
// itemCount: 20,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// itemBuilder: (context, index) {
// return Padding(
// padding: EdgeInsets.symmetric(vertical: 6.h),
// child: CardSeat(),
// );
// },
// ),
// ],
// ),
// );
// }
Widget _buildSeatColumn(String column, List<bool> seatList, int totalSeat) {
return Expanded(
child: Column(

View File

@ -131,6 +131,7 @@ class _SearchTicketsScreenState extends State<SearchTicketsScreen> {
duration: finalDuration,
seatClass: flight.flightClass,
price: formattedPrice,
airlineLogo: flight.airlineLogo,
onTap: () {
final argument = {
"ticketId": ticketId,

View File

@ -55,6 +55,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
String? stop;
String? codeDeparture;
String? codeArrival;
String? airlineLogo;
@override
void initState() {
@ -134,6 +135,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
stop = flight.stop;
codeDeparture = flight.codeDeparture;
codeArrival = flight.codeArrival;
airlineLogo = flight.airlineLogo;
return SafeArea(
child: Padding(
@ -152,6 +154,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
passenger: '$passenger',
transiAirplane: '$transitAirplane',
stop: '$stop',
airlineLogo: airlineLogo,
),
SizedBox(height: 32.h),
TypographyStyles.h6('Detail Pemesanan', color: GrayColors.gray800),
@ -194,6 +197,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
'stop': stop,
'codeDeparture': codeDeparture,
'codeArrival': codeArrival,
'airlineLogo': airlineLogo,
'passenger': passenger,
'selectedPassenger': selectedPassengers,
};

View File

@ -36,6 +36,7 @@ class _TicketBookingStep2ScreenState extends State<TicketBookingStep2Screen> {
String? stop;
String? codeDeparture;
String? codeArrival;
String? airlineLogo;
late final int passenger;
late final List<PassengerModel?> selectedPassengers;
late List<String> selectedSeatNumbers;
@ -58,6 +59,7 @@ class _TicketBookingStep2ScreenState extends State<TicketBookingStep2Screen> {
stop = args['stop'];
codeDeparture = args['codeDeparture'];
codeArrival = args['codeArrival'];
airlineLogo = args['airlineLogo'] ?? '';
passenger = args['passenger'];
selectedPassengers = args['selectedPassenger'] ?? [];
selectedSeatNumbers = args['selectedSeatNumbers'] ?? List.filled(passenger, '');
@ -93,6 +95,7 @@ class _TicketBookingStep2ScreenState extends State<TicketBookingStep2Screen> {
passenger: '$passenger',
transiAirplane: '$transitAirplane',
stop: '$stop',
airlineLogo: airlineLogo,
),
SizedBox(height: 32.h),
TypographyStyles.h6('Pilih Kursi', color: GrayColors.gray800),

View File

@ -214,6 +214,7 @@ class _TicketBookingStep3ScreenState extends State<TicketBookingStep3Screen> {
passenger: "$passenger",
stop: "${flightData?.stop}",
transiAirplane: "${flightData?.transitAirplane}",
airlineLogo: "${flightData?.airlineLogo}",
),
SizedBox(height: 32.h),
TypographyStyles.h6("Layanan Porter", color: GrayColors.gray800),

View File

@ -58,21 +58,6 @@ class _TicketBookingStep4ScreenState extends State<TicketBookingStep4Screen> {
selectedServiceLabels = args['selectedServiceLabels'] ?? [];
selectedPorterServices = args['selectedPorterServices'] ?? {};
// log('Ticket ID Step 4: $ticketId');
// log('Opsi Penerbangan Step 4: $selectedServiceLabels');
// if (selectedServiceLabels.isNotEmpty) {
// log('Opsi Penerbangan Step 4: ${selectedServiceLabels.join(", ")}');
// } else {
// log('Tidak ada opsi penerbangan yang dipilih');
// }
// selectedPorterServices.forEach((key, value) {
// if (value != null) {
// log('Porter $key: ${value.name} - Rp ${value.price}');
// }
// });
fetchDataFlight();
}
@ -152,6 +137,7 @@ class _TicketBookingStep4ScreenState extends State<TicketBookingStep4Screen> {
arrivalPorter: hasArrivalPorter ? "Kedatangan (${getPorterInfo('arrival')})" : null,
transitPorter: hasTransitPorter ? "Transit (${getPorterInfo('transit')})" : null,
stop: "${flightData?.stop}",
airlineLogo: "${flightData?.airlineLogo}",
),
),
SizedBox(height: 32.h),
@ -165,16 +151,9 @@ class _TicketBookingStep4ScreenState extends State<TicketBookingStep4Screen> {
height: MediaQuery.of(context).size.height * 0.4,
child: Column(
children: [
Row(
children: [
TypographyStyles.body(
"${flightData?.airLines} (${flightData?.code})",
color: GrayColors.gray800,
fontWeight: FontWeight.w500,
),
SizedBox(width: 10.w),
SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
],
_buildAirline(
text: '${flightData?.airLines} (${flightData?.code})',
airlineLogo: '${flightData?.airlineLogo}',
),
SizedBox(height: 2.h),
_buildRowPorterWithClass(
@ -298,6 +277,43 @@ class _TicketBookingStep4ScreenState extends State<TicketBookingStep4Screen> {
);
}
Widget _buildAirline({required String text, String? airlineLogo}) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TypographyStyles.body(
text,
color: GrayColors.gray800,
fontWeight: FontWeight.w500,
),
SizedBox(width: 10.w),
airlineLogo != null && airlineLogo.isNotEmpty
? Image.network(
airlineLogo,
width: 40.w,
height: 26.h,
errorBuilder: (context, error, stackTrace) {
print("Error loading image: $error");
return Container(
width: 40.w,
height: 10.h,
child: Center(child: Icon(Icons.error)),
);
},
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Container(
width: 40.w,
height: 10.h,
child: Center(child: CircularProgressIndicator(strokeWidth: 1.0)),
);
},
)
: SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
],
);
}
Widget _buildTextService() {
final hasDeparturePorter =
selectedPorterServices.containsKey('departure') && selectedPorterServices['departure'] != null;

View File

@ -8,6 +8,7 @@ import Foundation
import cloud_firestore
import firebase_auth
import firebase_core
import firebase_storage
import path_provider_foundation
import shared_preferences_foundation
@ -15,6 +16,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View File

@ -209,6 +209,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.21.1"
firebase_storage:
dependency: "direct main"
description:
name: firebase_storage
sha256: "2274bb277d0d56d4a106fd89bad5e8f7c005bae77dc3df5abd36101957010840"
url: "https://pub.dev"
source: hosted
version: "12.4.4"
firebase_storage_platform_interface:
dependency: transitive
description:
name: firebase_storage_platform_interface
sha256: "36ed6ebc2453a500c6d1e63c8126459056a70a798d53636242b0325951814cf5"
url: "https://pub.dev"
source: hosted
version: "5.2.4"
firebase_storage_web:
dependency: transitive
description:
name: firebase_storage_web
sha256: e169fc825cbd91c70d73f75b7e8be9ada272b4297184f779ca124b42945828fe
url: "https://pub.dev"
source: hosted
version: "3.10.11"
flutter:
dependency: "direct main"
description: flutter

View File

@ -2,7 +2,7 @@ name: e_porter
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
publish_to: "none" # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
@ -19,7 +19,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: '>=3.4.4 <4.0.0'
sdk: ">=3.4.4 <4.0.0"
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
@ -31,7 +31,6 @@ dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
@ -47,15 +46,16 @@ dependencies:
firebase_core: ^3.11.0
cloud_firestore: ^5.6.4
firebase_auth: ^5.5.1
firebase_storage: ^12.4.4
shared_preferences: ^2.4.6
logger: ^2.5.0
dropdown_button2: ^2.3.9
google_fonts: ^6.2.1
dotted_dashed_line: ^0.0.3
barcode_widget: ^2.0.4
# pin_code_fields: ^8.0.1
# dio: ^5.8.0+1
dev_dependencies:
flutter_test:

View File

@ -9,6 +9,7 @@
#include <cloud_firestore/cloud_firestore_plugin_c_api.h>
#include <firebase_auth/firebase_auth_plugin_c_api.h>
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <firebase_storage/firebase_storage_plugin_c_api.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
CloudFirestorePluginCApiRegisterWithRegistrar(
@ -17,4 +18,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
FirebaseStoragePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi"));
}

View File

@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
cloud_firestore
firebase_auth
firebase_core
firebase_storage
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST