modify reservation table page, add socket io client for real time data update, modify makanan list page
This commit is contained in:
@ -5,6 +5,7 @@ import 'package:stacked/stacked_annotations.dart';
|
||||
|
||||
import '../services/http_services.dart';
|
||||
import '../services/my_easyloading.dart';
|
||||
import '../services/my_socket_io_client.dart';
|
||||
import '../ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart';
|
||||
import '../ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart';
|
||||
import '../ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart';
|
||||
@ -54,6 +55,7 @@ import '../ui/views/user_ui/user_index_tracking/user_index_tracking_view.dart';
|
||||
LazySingleton(classType: MyHttpServices),
|
||||
LazySingleton(classType: OtherFunction),
|
||||
LazySingleton(classType: GlobalVar),
|
||||
LazySingleton(classType: MySocketIoClient),
|
||||
],
|
||||
logger: StackedLogger(),
|
||||
)
|
||||
|
||||
@ -15,6 +15,7 @@ import 'package:stacked_shared/stacked_shared.dart';
|
||||
import '../services/global_var.dart';
|
||||
import '../services/http_services.dart';
|
||||
import '../services/my_easyloading.dart';
|
||||
import '../services/my_socket_io_client.dart';
|
||||
import '../services/other_function.dart';
|
||||
|
||||
final locator = StackedLocator.instance;
|
||||
@ -36,4 +37,5 @@ Future<void> setupLocator({
|
||||
locator.registerLazySingleton(() => MyHttpServices());
|
||||
locator.registerLazySingleton(() => OtherFunction());
|
||||
locator.registerLazySingleton(() => GlobalVar());
|
||||
locator.registerLazySingleton(() => MySocketIoClient());
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:flutter/material.dart' as _i11;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:reza_app/model/makanan_model.dart' as _i12;
|
||||
import 'package:reza_app/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart'
|
||||
as _i6;
|
||||
import 'package:reza_app/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart'
|
||||
@ -17,21 +18,21 @@ import 'package:reza_app/ui/views/login_user/login_user_view.dart' as _i3;
|
||||
import 'package:reza_app/ui/views/meja_detail/meja_detail_view.dart' as _i9;
|
||||
import 'package:reza_app/ui/views/splash_screen/splash_screen_view.dart' as _i2;
|
||||
import 'package:reza_app/ui/views/user_ui/akun_user/akun_user_view.dart'
|
||||
as _i15;
|
||||
as _i16;
|
||||
import 'package:reza_app/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart'
|
||||
as _i8;
|
||||
import 'package:reza_app/ui/views/user_ui/makanan_list/makanan_list_view.dart'
|
||||
as _i13;
|
||||
as _i14;
|
||||
import 'package:reza_app/ui/views/user_ui/pesanan_list/keranjang_saya/keranjang_saya_view.dart'
|
||||
as _i10;
|
||||
import 'package:reza_app/ui/views/user_ui/pesanan_list/pesanan_list_view.dart'
|
||||
as _i14;
|
||||
as _i15;
|
||||
import 'package:reza_app/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart'
|
||||
as _i12;
|
||||
as _i13;
|
||||
import 'package:reza_app/ui/views/user_ui/user_index_tracking/user_index_tracking_view.dart'
|
||||
as _i7;
|
||||
import 'package:stacked/stacked.dart' as _i1;
|
||||
import 'package:stacked_services/stacked_services.dart' as _i16;
|
||||
import 'package:stacked_services/stacked_services.dart' as _i17;
|
||||
|
||||
class Routes {
|
||||
static const splashScreenView = '/';
|
||||
@ -146,8 +147,10 @@ class StackedRouter extends _i1.RouterBase {
|
||||
);
|
||||
},
|
||||
_i8.DetailMakananView: (data) {
|
||||
final args = data.getArgs<DetailMakananViewArguments>(nullOk: false);
|
||||
return _i11.MaterialPageRoute<dynamic>(
|
||||
builder: (context) => const _i8.DetailMakananView(),
|
||||
builder: (context) => _i8.DetailMakananView(
|
||||
key: args.key, makananModel: args.makananModel),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
@ -200,6 +203,33 @@ class InputInformasiDiriViewArguments {
|
||||
}
|
||||
}
|
||||
|
||||
class DetailMakananViewArguments {
|
||||
const DetailMakananViewArguments({
|
||||
this.key,
|
||||
required this.makananModel,
|
||||
});
|
||||
|
||||
final _i11.Key? key;
|
||||
|
||||
final _i12.MakananModel makananModel;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '{"key": "$key", "makananModel": "$makananModel"}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant DetailMakananViewArguments other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other.key == key && other.makananModel == makananModel;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return key.hashCode ^ makananModel.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
class MejaDetailViewArguments {
|
||||
const MejaDetailViewArguments({
|
||||
this.key,
|
||||
@ -248,44 +278,44 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
|
||||
final _routes = <_i1.RouteDef>[
|
||||
_i1.RouteDef(
|
||||
UserIndexTrackingViewRoutes.reservasiMejaView,
|
||||
page: _i12.ReservasiMejaView,
|
||||
page: _i13.ReservasiMejaView,
|
||||
),
|
||||
_i1.RouteDef(
|
||||
UserIndexTrackingViewRoutes.makananListView,
|
||||
page: _i13.MakananListView,
|
||||
page: _i14.MakananListView,
|
||||
),
|
||||
_i1.RouteDef(
|
||||
UserIndexTrackingViewRoutes.pesananListView,
|
||||
page: _i14.PesananListView,
|
||||
page: _i15.PesananListView,
|
||||
),
|
||||
_i1.RouteDef(
|
||||
UserIndexTrackingViewRoutes.akunUserView,
|
||||
page: _i15.AkunUserView,
|
||||
page: _i16.AkunUserView,
|
||||
),
|
||||
];
|
||||
|
||||
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
||||
_i12.ReservasiMejaView: (data) {
|
||||
_i13.ReservasiMejaView: (data) {
|
||||
return _i11.MaterialPageRoute<dynamic>(
|
||||
builder: (context) => const _i12.ReservasiMejaView(),
|
||||
builder: (context) => const _i13.ReservasiMejaView(),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
_i13.MakananListView: (data) {
|
||||
_i14.MakananListView: (data) {
|
||||
return _i11.MaterialPageRoute<dynamic>(
|
||||
builder: (context) => const _i13.MakananListView(),
|
||||
builder: (context) => const _i14.MakananListView(),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
_i14.PesananListView: (data) {
|
||||
_i15.PesananListView: (data) {
|
||||
return _i11.MaterialPageRoute<dynamic>(
|
||||
builder: (context) => const _i14.PesananListView(),
|
||||
builder: (context) => const _i15.PesananListView(),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
_i15.AkunUserView: (data) {
|
||||
_i16.AkunUserView: (data) {
|
||||
return _i11.MaterialPageRoute<dynamic>(
|
||||
builder: (context) => const _i15.AkunUserView(),
|
||||
builder: (context) => const _i16.AkunUserView(),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
@ -297,7 +327,7 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
|
||||
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
|
||||
}
|
||||
|
||||
extension NavigatorStateExtension on _i16.NavigationService {
|
||||
extension NavigatorStateExtension on _i17.NavigationService {
|
||||
Future<dynamic> navigateToSplashScreenView([
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
@ -385,14 +415,18 @@ extension NavigatorStateExtension on _i16.NavigationService {
|
||||
transition: transition);
|
||||
}
|
||||
|
||||
Future<dynamic> navigateToDetailMakananView([
|
||||
Future<dynamic> navigateToDetailMakananView({
|
||||
_i11.Key? key,
|
||||
required _i12.MakananModel makananModel,
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
Map<String, String>? parameters,
|
||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||
transition,
|
||||
]) async {
|
||||
}) async {
|
||||
return navigateTo<dynamic>(Routes.detailMakananView,
|
||||
arguments:
|
||||
DetailMakananViewArguments(key: key, makananModel: makananModel),
|
||||
id: routerId,
|
||||
preventDuplicates: preventDuplicates,
|
||||
parameters: parameters,
|
||||
@ -574,14 +608,18 @@ extension NavigatorStateExtension on _i16.NavigationService {
|
||||
transition: transition);
|
||||
}
|
||||
|
||||
Future<dynamic> replaceWithDetailMakananView([
|
||||
Future<dynamic> replaceWithDetailMakananView({
|
||||
_i11.Key? key,
|
||||
required _i12.MakananModel makananModel,
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
Map<String, String>? parameters,
|
||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||
transition,
|
||||
]) async {
|
||||
}) async {
|
||||
return replaceWith<dynamic>(Routes.detailMakananView,
|
||||
arguments:
|
||||
DetailMakananViewArguments(key: key, makananModel: makananModel),
|
||||
id: routerId,
|
||||
preventDuplicates: preventDuplicates,
|
||||
parameters: parameters,
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
@ -9,6 +11,7 @@ import 'app/themes/app_theme.dart';
|
||||
|
||||
Future main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
HttpOverrides.global = MyHttpOverrides();
|
||||
await dotenv.load(fileName: ".env");
|
||||
await setupAllLocator();
|
||||
runApp(const MyApp());
|
||||
@ -37,3 +40,12 @@ Future<void> setupAllLocator() async {
|
||||
// setupBottomsheetUi();
|
||||
// setupSnackbarUi();
|
||||
}
|
||||
|
||||
class MyHttpOverrides extends HttpOverrides {
|
||||
@override
|
||||
HttpClient createHttpClient(SecurityContext? context) {
|
||||
return super.createHttpClient(context)
|
||||
..badCertificateCallback =
|
||||
(X509Certificate cert, String host, int port) => true;
|
||||
}
|
||||
}
|
||||
|
||||
32
lib/model/makanan_model.dart
Normal file
32
lib/model/makanan_model.dart
Normal file
@ -0,0 +1,32 @@
|
||||
class MakananModel {
|
||||
int? idMakanan;
|
||||
String? namaMakanan;
|
||||
String? hargaMakanan;
|
||||
String? deskripsiMakanan;
|
||||
String? imgUrl;
|
||||
|
||||
MakananModel(
|
||||
{this.idMakanan,
|
||||
this.namaMakanan,
|
||||
this.hargaMakanan,
|
||||
this.deskripsiMakanan,
|
||||
this.imgUrl});
|
||||
|
||||
MakananModel.fromJson(Map<String, dynamic> json) {
|
||||
idMakanan = json['id_makanan'];
|
||||
namaMakanan = json['nama_makanan'];
|
||||
hargaMakanan = json['harga_makanan'];
|
||||
deskripsiMakanan = json['deskripsi_makanan'];
|
||||
imgUrl = json['img_url'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id_makanan'] = idMakanan;
|
||||
data['nama_makanan'] = namaMakanan;
|
||||
data['harga_makanan'] = hargaMakanan;
|
||||
data['deskripsi_makanan'] = deskripsiMakanan;
|
||||
data['img_url'] = imgUrl;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
21
lib/model/my_model.dart
Normal file
21
lib/model/my_model.dart
Normal file
@ -0,0 +1,21 @@
|
||||
class MyModel {
|
||||
String? message;
|
||||
bool? theBool;
|
||||
dynamic data;
|
||||
|
||||
MyModel({this.message, this.theBool, this.data});
|
||||
|
||||
MyModel.fromJson(Map<String, dynamic> json) {
|
||||
message = json['message'];
|
||||
theBool = json['bool'];
|
||||
data = json['data'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['message'] = message;
|
||||
data['bool'] = theBool;
|
||||
data['data'] = this.data;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
36
lib/model/reservasi_meja_model.dart
Normal file
36
lib/model/reservasi_meja_model.dart
Normal file
@ -0,0 +1,36 @@
|
||||
class ReservasiMejaModel {
|
||||
int? idMeja;
|
||||
int? idUser;
|
||||
String? status;
|
||||
String? jamBooking;
|
||||
String? createdAt;
|
||||
String? updatedAt;
|
||||
|
||||
ReservasiMejaModel(
|
||||
{this.idMeja,
|
||||
this.idUser,
|
||||
this.status,
|
||||
this.jamBooking,
|
||||
this.createdAt,
|
||||
this.updatedAt});
|
||||
|
||||
ReservasiMejaModel.fromJson(Map<String, dynamic> json) {
|
||||
idMeja = json['id_meja'];
|
||||
idUser = json['id_user'];
|
||||
status = json['status'];
|
||||
jamBooking = json['jam_booking'];
|
||||
createdAt = json['created_at'];
|
||||
updatedAt = json['updated_at'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id_meja'] = idMeja;
|
||||
data['id_user'] = idUser;
|
||||
data['status'] = status;
|
||||
data['jam_booking'] = jamBooking;
|
||||
data['created_at'] = createdAt;
|
||||
data['updated_at'] = updatedAt;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@ import '../app/app.logger.dart';
|
||||
class MyHttpServices {
|
||||
final log = getLogger('MyHttpServices');
|
||||
final _options = BaseOptions(
|
||||
baseUrl: dotenv.env['api_url']!,
|
||||
baseUrl: dotenv.env['url']!,
|
||||
connectTimeout: const Duration(seconds: 120),
|
||||
receiveTimeout: const Duration(seconds: 120),
|
||||
);
|
||||
|
||||
48
lib/services/my_socket_io_client.dart
Normal file
48
lib/services/my_socket_io_client.dart
Normal file
@ -0,0 +1,48 @@
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:socket_io_client/socket_io_client.dart';
|
||||
|
||||
import '../app/app.logger.dart';
|
||||
|
||||
class MySocketIoClient {
|
||||
final log = getLogger('MySocketIoClient');
|
||||
final String _url = dotenv.env['url']!;
|
||||
static final MySocketIoClient _instance = MySocketIoClient._internal();
|
||||
factory MySocketIoClient() => _instance;
|
||||
MySocketIoClient._internal();
|
||||
|
||||
late Socket _socket;
|
||||
Socket get socket => _socket;
|
||||
|
||||
Future<void> init() async {
|
||||
try {
|
||||
_socket = io(_url, <String, dynamic>{
|
||||
'transports': ['websocket'],
|
||||
'autoConnect': false,
|
||||
});
|
||||
_socket.connect();
|
||||
log.i('socket connected');
|
||||
} catch (e) {
|
||||
log.e('error : $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> emit(String event, dynamic data) async {
|
||||
_socket.emit(event, data);
|
||||
}
|
||||
|
||||
Future<void> on(String event, Function(dynamic) callback) async {
|
||||
_socket.on(event, callback);
|
||||
}
|
||||
|
||||
Future<void> off(String event) async {
|
||||
_socket.off(event);
|
||||
}
|
||||
|
||||
Future<void> disconnect() async {
|
||||
_socket.disconnect();
|
||||
}
|
||||
|
||||
Future<void> connect() async {
|
||||
_socket.connect();
|
||||
}
|
||||
}
|
||||
@ -85,9 +85,18 @@ class MejaDetailView extends StatelessWidget {
|
||||
style: regularTextStyle,
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Tersedia',
|
||||
text: model.theBool
|
||||
? (model.reservasiMejaModel == null
|
||||
? 'Loading'
|
||||
: model.reservasiMejaModel!.status!
|
||||
.toUpperCase())
|
||||
: 'Tersedia',
|
||||
style: regularTextStyle.copyWith(
|
||||
color: Colors.green,
|
||||
color: model.theBool
|
||||
? (model.reservasiMejaModel == null
|
||||
? Colors.grey
|
||||
: Colors.red)
|
||||
: Colors.green,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
@ -146,10 +155,14 @@ class MejaDetailView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
if (model.theBool == false) {
|
||||
model.showReservasiMeja();
|
||||
}
|
||||
},
|
||||
label: const Text('Pesan'),
|
||||
icon: const Icon(Icons.add_shopping_cart),
|
||||
backgroundColor: mainColor,
|
||||
backgroundColor: mainColor.withOpacity(model.theBool ? 0.5 : 1),
|
||||
),
|
||||
floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling,
|
||||
floatingActionButtonLocation:
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:reza_app/model/reservasi_meja_model.dart';
|
||||
|
||||
import '../../../app/app.logger.dart';
|
||||
import '../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../model/my_model.dart';
|
||||
|
||||
class MejaDetailViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('MejaDetailViewModel');
|
||||
|
||||
late String mejaId;
|
||||
late String namaMeja;
|
||||
late int idMeja;
|
||||
|
||||
String? imgAsset;
|
||||
bool theBool = false;
|
||||
ReservasiMejaModel? reservasiMejaModel;
|
||||
|
||||
Future<void> init(String mejaId) async {
|
||||
log.i('MejaDetailViewModel init');
|
||||
log.i('mejaId : $mejaId');
|
||||
// log.i('MejaDetailViewModel init');
|
||||
// log.i('mejaId : $mejaId');
|
||||
this.mejaId = mejaId;
|
||||
globalVar.backPressed = 'backNormal';
|
||||
// seperate the number from the string
|
||||
@ -27,9 +34,76 @@ class MejaDetailViewModel extends CustomBaseViewModel {
|
||||
namaMeja = 'Meja';
|
||||
imgAsset = 'assets/reza_meja_2.jpeg';
|
||||
}
|
||||
idMeja = number;
|
||||
|
||||
namaMeja = '$namaMeja $number';
|
||||
|
||||
log.i('imgAsset : $imgAsset');
|
||||
// log.i('imgAsset : $imgAsset');
|
||||
getData();
|
||||
}
|
||||
|
||||
getData() async {
|
||||
easyLoading.showLoading();
|
||||
setBusy(true);
|
||||
try {
|
||||
var response = await httpService.get('table/detail/$idMeja');
|
||||
log.i('response : $response');
|
||||
MyModel myModel = MyModel.fromJson(response.data);
|
||||
theBool = myModel.theBool!;
|
||||
|
||||
reservasiMejaModel =
|
||||
theBool ? ReservasiMejaModel.fromJson(myModel.data) : null;
|
||||
|
||||
log.i('reservasiMejaModel : $reservasiMejaModel');
|
||||
} catch (e) {
|
||||
log.e('error : $e');
|
||||
} finally {
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
showReservasiMeja() async {
|
||||
await dialogService
|
||||
.showDialog(
|
||||
title: 'Reservasi Meja',
|
||||
description: 'Apakah anda ingin reservasi meja ini?',
|
||||
buttonTitle: 'Ya',
|
||||
cancelTitle: 'Tidak',
|
||||
)
|
||||
.then((value) {
|
||||
log.i('value : $value');
|
||||
if (value!.confirmed) {
|
||||
reservasiMeja();
|
||||
log.i('confirmed');
|
||||
} else {
|
||||
log.i('not confirmed');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reservasiMeja() async {
|
||||
easyLoading.customLoading('Melakukan reservasi meja...');
|
||||
setBusy(true);
|
||||
try {
|
||||
var formData = FormData.fromMap({'id_user': 1, 'status': 'booking'});
|
||||
|
||||
String path = 'table/reservation/$idMeja';
|
||||
|
||||
await httpService.postWithFormData(path, formData);
|
||||
// log.i('res : $res');
|
||||
getData();
|
||||
snackbarService.showSnackbar(
|
||||
message:
|
||||
'Reservasi meja berhasil\nSila Bayar Rp. 20 ribu jika tiba di cafe',
|
||||
title: 'Berhasil',
|
||||
duration: const Duration(seconds: 2),
|
||||
);
|
||||
} catch (e) {
|
||||
log.e('error : $e');
|
||||
} finally {
|
||||
setBusy(false);
|
||||
easyLoading.dismissLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
import 'package:reza_app/app/app.router.dart';
|
||||
import 'package:reza_app/app/core/custom_base_view_model.dart';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../services/my_socket_io_client.dart';
|
||||
|
||||
class SplashScreenViewModel extends CustomBaseViewModel {
|
||||
final socketIoClient = locator<MySocketIoClient>();
|
||||
Future<void> init() async {
|
||||
// after 2 second, navigate to login page
|
||||
socketIoClient.init();
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
await navigationService.navigateToLoginUserView();
|
||||
}
|
||||
|
||||
@ -62,8 +62,8 @@ class AkunUserView extends StatelessWidget {
|
||||
Center(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(150),
|
||||
child: Image.network(
|
||||
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
|
||||
child: Image.asset(
|
||||
'assets/nasi_goreng.jpg',
|
||||
height: 150,
|
||||
width: 150,
|
||||
fit: BoxFit.fill,
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:reza_app/model/makanan_model.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import '../../../../../app/themes/app_colors.dart';
|
||||
@ -8,8 +10,12 @@ import '../../../../widgets/my_white_container.dart';
|
||||
import './detail_makanan_view_model.dart';
|
||||
|
||||
class DetailMakananView extends HookWidget {
|
||||
const DetailMakananView({Key? key}) : super(key: key);
|
||||
final MakananModel makananModel;
|
||||
|
||||
const DetailMakananView({
|
||||
Key? key,
|
||||
required this.makananModel,
|
||||
}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scrollController = useScrollController();
|
||||
@ -21,7 +27,7 @@ class DetailMakananView extends HookWidget {
|
||||
return ViewModelBuilder<DetailMakananViewModel>.reactive(
|
||||
viewModelBuilder: () => DetailMakananViewModel(),
|
||||
onViewModelReady: (DetailMakananViewModel model) async {
|
||||
await model.init();
|
||||
await model.init(makananModel);
|
||||
},
|
||||
builder: (
|
||||
BuildContext context,
|
||||
@ -127,7 +133,9 @@ class DetailMakananView extends HookWidget {
|
||||
),
|
||||
// bikin dummy text tentang nasi goreng
|
||||
Text(
|
||||
"Nasi goreng adalah makanan yang terbuat dari nasi yang digoreng dan diaduk dalam minyak goreng atau margarin, biasanya ditambah kecap manis, bawang merah, bawang putih, daging ayam, telur, dan bumbu-bumbu lainnya. Nasi goreng sering dianggap sebagai makanan nasional Indonesia. Nasi goreng dapat ditemukan di seluruh Indonesia, dari restoran pinggir jalan, warung, hingga hotel bintang lima dan restoran mewah.",
|
||||
model.isBusy
|
||||
? 'Loading...'
|
||||
: model.makananModel!.deskripsiMakanan!,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 13,
|
||||
color: fontGrey,
|
||||
@ -184,7 +192,9 @@ class DetailMakananView extends HookWidget {
|
||||
height: 5,
|
||||
),
|
||||
Text(
|
||||
"Rp. 35.000",
|
||||
model.isBusy
|
||||
? 'Loading...'
|
||||
: 'Rp. ${int.parse(makananModel.hargaMakanan!) + 10000}',
|
||||
style: boldTextStyle.copyWith(
|
||||
fontSize: 16,
|
||||
color: dangerColor,
|
||||
@ -342,7 +352,9 @@ class SecondWidget extends ViewModelWidget<DetailMakananViewModel> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Burger King Handcrafted Burgers ",
|
||||
viewModel.isBusy
|
||||
? 'Loading...'
|
||||
: viewModel.makananModel!.namaMakanan!,
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 17,
|
||||
),
|
||||
@ -351,7 +363,9 @@ class SecondWidget extends ViewModelWidget<DetailMakananViewModel> {
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
"Rp. 25.000",
|
||||
viewModel.isBusy
|
||||
? 'Loading...'
|
||||
: 'Rp .${viewModel.makananModel!.hargaMakanan!}',
|
||||
style: regularTextStyle.copyWith(
|
||||
fontSize: 18,
|
||||
color: dangerColor,
|
||||
@ -405,37 +419,38 @@ class TopMenuWidget extends ViewModelWidget<DetailMakananViewModel> {
|
||||
return Stack(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: MediaQuery.of(context).size.height * 0.35,
|
||||
child: Image.network(
|
||||
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 5,
|
||||
),
|
||||
// width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'1 / 2',
|
||||
style: TextStyle(
|
||||
color: fontGrey,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
width: double.infinity,
|
||||
height: MediaQuery.of(context).size.height * 0.35,
|
||||
child: viewModel.isBusy
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Image.network(
|
||||
'${dotenv.env['url']}assets/makanan/${viewModel.makananModel!.imgUrl}',
|
||||
fit: BoxFit.cover,
|
||||
)),
|
||||
// Positioned(
|
||||
// bottom: 10,
|
||||
// right: 10,
|
||||
// child: Container(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 5,
|
||||
// ),
|
||||
// // width: 20,
|
||||
// height: 20,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// child: const Center(
|
||||
// child: Text(
|
||||
// '1 / 2',
|
||||
// style: TextStyle(
|
||||
// color: fontGrey,
|
||||
// fontSize: 12,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
import 'package:reza_app/model/makanan_model.dart';
|
||||
|
||||
import '../../../../../app/app.logger.dart';
|
||||
import '../../../../../app/core/custom_base_view_model.dart';
|
||||
|
||||
class DetailMakananViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('DetailMakananViewModel');
|
||||
MakananModel? makananModel;
|
||||
|
||||
Future<void> init() async {
|
||||
Future<void> init(MakananModel makananModel) async {
|
||||
setBusy(true);
|
||||
globalVar.backPressed = 'backNormal';
|
||||
this.makananModel = makananModel;
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:reza_app/ui/widgets/my_textformfield.dart';
|
||||
import 'package:reza_app/ui/widgets/my_white_container.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
@ -147,66 +148,95 @@ class MakananListView extends StatelessWidget {
|
||||
height: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
for (var i = 0; i < 10; i++)
|
||||
GestureDetector(
|
||||
onTap: () => model.goToDetailMakanan(),
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.46,
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.network(
|
||||
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
|
||||
height: 150,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 5,
|
||||
),
|
||||
child: Text(
|
||||
'Product Name',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
child: model.isBusy
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: (model.listMakanan.isEmpty
|
||||
? const Center(
|
||||
child: Text('Data Kosong'),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
child: Wrap(
|
||||
spacing: 5,
|
||||
runSpacing: 10,
|
||||
// alignment: WrapAlignment.spaceAround,
|
||||
// crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
for (var i = 0;
|
||||
i < model.listMakanan.length;
|
||||
i++)
|
||||
GestureDetector(
|
||||
onTap: () => model.goToDetailMakanan(
|
||||
model.listMakanan[i]),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10,
|
||||
// right: 5,
|
||||
),
|
||||
child: Container(
|
||||
width: MediaQuery.of(context)
|
||||
.size
|
||||
.width *
|
||||
0.46,
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Image.network(
|
||||
'${dotenv.env['url']}assets/makanan/${model.listMakanan[i].imgUrl}',
|
||||
height: 150,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
// Image.asset(
|
||||
// 'assets/nasi_goreng.jpg',
|
||||
// height: 150,
|
||||
// width: double.infinity,
|
||||
// fit: BoxFit.fill,
|
||||
// ),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5,
|
||||
),
|
||||
child: Text(
|
||||
model.listMakanan[i]
|
||||
.namaMakanan!,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5,
|
||||
),
|
||||
child: Text(
|
||||
model.listMakanan[i]
|
||||
.deskripsiMakanan!,
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 5,
|
||||
),
|
||||
child: Text(
|
||||
'Rp. 100.000',
|
||||
style: TextStyle(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -1,15 +1,50 @@
|
||||
import '../../../../app/app.locator.dart';
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/app.router.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../../model/makanan_model.dart';
|
||||
import '../../../../model/my_model.dart';
|
||||
import '../../../../services/my_socket_io_client.dart';
|
||||
|
||||
class MakananListViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('MakananListViewModel');
|
||||
final socketIoClient = locator<MySocketIoClient>();
|
||||
List<MakananModel> listMakanan = [];
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
getData();
|
||||
socketIoClient.on('makanan_user', (data) {
|
||||
log.i('data : $data');
|
||||
listMakanan.clear();
|
||||
getData();
|
||||
// webViewController!.reload();
|
||||
});
|
||||
}
|
||||
|
||||
goToDetailMakanan() {
|
||||
getData() async {
|
||||
setBusy(true);
|
||||
easyLoading.showLoading();
|
||||
try {
|
||||
var res = await httpService.get('table/makanan');
|
||||
MyModel myModel = MyModel.fromJson(res.data);
|
||||
|
||||
if (myModel.data.length > 0) {
|
||||
for (var item in myModel.data) {
|
||||
listMakanan.add(MakananModel.fromJson(item));
|
||||
}
|
||||
}
|
||||
log.i(listMakanan);
|
||||
} catch (e) {
|
||||
log.e(e.toString());
|
||||
} finally {
|
||||
easyLoading.dismissLoading();
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
goToDetailMakanan(MakananModel makananModel) {
|
||||
log.i('goToDetailMakanan');
|
||||
navigationService.navigateTo(Routes.detailMakananView);
|
||||
navigationService.navigateTo(Routes.detailMakananView,
|
||||
arguments: DetailMakananViewArguments(makananModel: makananModel));
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,8 +72,8 @@ class KeranjangSayaView extends StatelessWidget {
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Image.network(
|
||||
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
|
||||
child: Image.asset(
|
||||
'assets/nasi_goreng.jpg',
|
||||
height: 150,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.fill,
|
||||
|
||||
@ -157,8 +157,8 @@ class PesananListView extends StatelessWidget {
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Image.network(
|
||||
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
|
||||
child: Image.asset(
|
||||
'assets/nasi_goreng.jpg',
|
||||
height: 100,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.fill,
|
||||
|
||||
@ -104,16 +104,14 @@ class ReservasiMejaView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
// child: SizedBox(),
|
||||
child: WebView(
|
||||
initialUrl: dotenv.env['table_url'],
|
||||
// initialUrl: 'http://172.29.85.181/parkir/user',
|
||||
// initialUrl: 'https://rekam-medis.airlangga-it.com/',
|
||||
javascriptMode: JavascriptMode.unrestricted,
|
||||
onWebViewCreated: (WebViewController webViewController) {
|
||||
// _controller.complete(webViewController);
|
||||
// model.controllerCompleter.future
|
||||
// .then((value) => model.webViewController = value);
|
||||
// model.controllerCompleter.complete(webViewController);
|
||||
model.webViewController = webViewController;
|
||||
},
|
||||
onProgress: (int progress) {
|
||||
// model.log.i('WebView is loading (progress : $progress%)');
|
||||
@ -196,19 +194,19 @@ class ReservasiMejaView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
const Text('Tidak Tersedia'),
|
||||
const Text('Dibooking'),
|
||||
|
||||
const SizedBox(width: 10),
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.blue,
|
||||
color: Colors.grey,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
const Text('Dipesan'),
|
||||
const Text('Tidak Tersedia'),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
),
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:webview_flutter/webview_flutter.dart';
|
||||
|
||||
import '../../../../app/app.locator.dart';
|
||||
import '../../../../app/app.logger.dart';
|
||||
import '../../../../app/core/custom_base_view_model.dart';
|
||||
import '../../../../services/my_socket_io_client.dart';
|
||||
|
||||
class ReservasiMejaViewModel extends CustomBaseViewModel {
|
||||
final log = getLogger('ReservasiMejaViewModel');
|
||||
WebViewController? webViewController;
|
||||
final socketIoClient = locator<MySocketIoClient>();
|
||||
|
||||
List<String> imagePaths = [
|
||||
'assets/reza_gazebo.jpeg',
|
||||
@ -14,5 +20,10 @@ class ReservasiMejaViewModel extends CustomBaseViewModel {
|
||||
|
||||
Future<void> init() async {
|
||||
globalVar.backPressed = 'exitApp';
|
||||
socketIoClient.on('table_admin', (data) {
|
||||
log.i('data : $data');
|
||||
// getData();
|
||||
webViewController!.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user