first commit

This commit is contained in:
kicap
2023-08-10 01:23:34 +08:00
commit 696d48e3c3
175 changed files with 9675 additions and 0 deletions

58
lib/app/app.dart Normal file
View File

@ -0,0 +1,58 @@
import 'package:stacked_services/stacked_services.dart';
import 'package:stacked/stacked_annotations.dart';
import '../services/global_var.dart';
import '../services/http_services.dart';
import '../services/my_easyloading.dart';
import '../services/other_function.dart';
import '../ui/views/admin_ui/admin_index_tracking/admin_index_tracking_view.dart';
import '../ui/views/admin_ui/akun_admin/akun_admin_view.dart';
import '../ui/views/admin_ui/makanan_list/add_edit_makanan/add_edit_makanan_view.dart';
import '../ui/views/admin_ui/makanan_list/detail_makanan/detail_makanan_view.dart';
import '../ui/views/admin_ui/makanan_list/makanan_list_view.dart';
import '../ui/views/admin_ui/meja_list/meja_detail/meja_detail_view.dart';
import '../ui/views/admin_ui/meja_list/meja_edit/meja_edit_view.dart';
import '../ui/views/admin_ui/meja_list/meja_history_log/meja_history_log_view.dart';
import '../ui/views/admin_ui/meja_list/meja_list_view.dart';
import '../ui/views/admin_ui/pesanan_list/pesanan_list_view.dart';
import '../ui/views/login_user/login_user_view.dart';
import '../ui/views/splash_screen/splash_screen_view.dart';
@StackedApp(
routes: [
MaterialRoute(page: SplashScreenView, initial: true),
MaterialRoute(page: LoginUserView),
MaterialRoute(
page: AdminIndexTrackingView,
// fullscreenDialog: true,
children: [
MaterialRoute(page: MejaListView, initial: true),
MaterialRoute(page: MakananListView),
MaterialRoute(page: PesananListView),
MaterialRoute(page: AkunAdminView),
],
),
MaterialRoute(page: DetailMakananView),
MaterialRoute(page: AddEditMakananView),
MaterialRoute(page: MejaDetailView),
MaterialRoute(page: MejaEditView),
MaterialRoute(page: MejaHistoryLogView),
],
// dialogs: [
// StackedDialog(classType: AddSiswaDialogView),
// ],
dependencies: [
LazySingleton(classType: NavigationService),
LazySingleton(classType: DialogService),
LazySingleton(classType: SnackbarService),
LazySingleton(classType: BottomSheetService),
//
LazySingleton(classType: MyEasyLoading),
LazySingleton(classType: MyHttpServices),
LazySingleton(classType: OtherFunction),
LazySingleton(classType: GlobalVar),
],
logger: StackedLogger(),
)
class App {}

39
lib/app/app.locator.dart Normal file
View File

@ -0,0 +1,39 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// StackedLocatorGenerator
// **************************************************************************
// ignore_for_file: public_member_api_docs, implementation_imports, depend_on_referenced_packages
import 'package:stacked_services/src/bottom_sheet/bottom_sheet_service.dart';
import 'package:stacked_services/src/dialog/dialog_service.dart';
import 'package:stacked_services/src/navigation/navigation_service.dart';
import 'package:stacked_services/src/snackbar/snackbar_service.dart';
import 'package:stacked_shared/stacked_shared.dart';
import '../services/global_var.dart';
import '../services/http_services.dart';
import '../services/my_easyloading.dart';
import '../services/other_function.dart';
final locator = StackedLocator.instance;
Future<void> setupLocator({
String? environment,
EnvironmentFilter? environmentFilter,
}) async {
// Register environments
locator.registerEnvironment(
environment: environment, environmentFilter: environmentFilter);
// Register dependencies
locator.registerLazySingleton(() => NavigationService());
locator.registerLazySingleton(() => DialogService());
locator.registerLazySingleton(() => SnackbarService());
locator.registerLazySingleton(() => BottomSheetService());
locator.registerLazySingleton(() => MyEasyLoading());
locator.registerLazySingleton(() => MyHttpServices());
locator.registerLazySingleton(() => OtherFunction());
locator.registerLazySingleton(() => GlobalVar());
}

159
lib/app/app.logger.dart Normal file
View File

@ -0,0 +1,159 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// StackedLoggerGenerator
// **************************************************************************
// ignore_for_file: avoid_print, depend_on_referenced_packages
/// Maybe this should be generated for the user as well?
///
/// import 'package:customer_app/services/stackdriver/stackdriver_service.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
class SimpleLogPrinter extends LogPrinter {
final String className;
final bool printCallingFunctionName;
final bool printCallStack;
final List<String> exludeLogsFromClasses;
final String? showOnlyClass;
SimpleLogPrinter(
this.className, {
this.printCallingFunctionName = true,
this.printCallStack = false,
this.exludeLogsFromClasses = const [],
this.showOnlyClass,
});
@override
List<String> log(LogEvent event) {
var color = PrettyPrinter.levelColors[event.level];
var emoji = PrettyPrinter.levelEmojis[event.level];
var methodName = _getMethodName();
var methodNameSection =
printCallingFunctionName && methodName != null ? ' | $methodName' : '';
var stackLog = event.stackTrace.toString();
var output =
'$emoji $className$methodNameSection - ${event.message}${event.error != null ? '\nERROR: ${event.error}\n' : ''}${printCallStack ? '\nSTACKTRACE:\n$stackLog' : ''}';
if (exludeLogsFromClasses
.any((excludeClass) => className == excludeClass) ||
(showOnlyClass != null && className != showOnlyClass)) return [];
final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk
List<String> result = [];
for (var line in output.split('\n')) {
result.addAll(pattern.allMatches(line).map((match) {
if (kReleaseMode) {
return match.group(0)!;
} else {
return color!(match.group(0)!);
}
}));
}
return result;
}
String? _getMethodName() {
try {
final currentStack = StackTrace.current;
final formattedStacktrace = _formatStackTrace(currentStack, 3);
if (kIsWeb) {
final classNameParts = _splitClassNameWords(className);
return _findMostMatchedTrace(formattedStacktrace!, classNameParts)
.split(' ')
.last;
} else {
final realFirstLine = formattedStacktrace
?.firstWhere((line) => line.contains(className), orElse: () => "");
final methodName = realFirstLine?.replaceAll('$className.', '');
return methodName;
}
} catch (e) {
// There's no deliberate function call from our code so we return null;
return null;
}
}
List<String> _splitClassNameWords(String className) {
return className
.split(RegExp(r'(?=[A-Z])'))
.map((e) => e.toLowerCase())
.toList();
}
/// When the faulty word exists in the begging this method will not be very usefull
String _findMostMatchedTrace(
List<String> stackTraces, List<String> keyWords) {
String match = stackTraces.firstWhere(
(trace) => _doesTraceContainsAllKeywords(trace, keyWords),
orElse: () => '');
if (match.isEmpty) {
match = _findMostMatchedTrace(
stackTraces, keyWords.sublist(0, keyWords.length - 1));
}
return match;
}
bool _doesTraceContainsAllKeywords(String stackTrace, List<String> keywords) {
final formattedKeywordsAsRegex = RegExp(keywords.join('.*'));
return stackTrace.contains(formattedKeywordsAsRegex);
}
}
final stackTraceRegex = RegExp(r'#[0-9]+[\s]+(.+) \(([^\s]+)\)');
List<String>? _formatStackTrace(StackTrace stackTrace, int methodCount) {
var lines = stackTrace.toString().split('\n');
var formatted = <String>[];
var count = 0;
for (var line in lines) {
var match = stackTraceRegex.matchAsPrefix(line);
if (match != null) {
if (match.group(2)!.startsWith('package:logger')) {
continue;
}
var newLine = ("${match.group(1)}");
formatted.add(newLine.replaceAll('<anonymous closure>', '()'));
if (++count == methodCount) {
break;
}
} else {
formatted.add(line);
}
}
if (formatted.isEmpty) {
return null;
} else {
return formatted;
}
}
Logger getLogger(
String className, {
bool printCallingFunctionName = true,
bool printCallstack = false,
List<String> exludeLogsFromClasses = const [],
String? showOnlyClass,
}) {
return Logger(
printer: SimpleLogPrinter(
className,
printCallingFunctionName: printCallingFunctionName,
printCallStack: printCallstack,
showOnlyClass: showOnlyClass,
exludeLogsFromClasses: exludeLogsFromClasses,
),
output: MultiOutput([
if (!kReleaseMode) ConsoleOutput(),
]),
);
}

603
lib/app/app.router.dart Normal file
View File

@ -0,0 +1,603 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// StackedNavigatorGenerator
// **************************************************************************
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:flutter/material.dart' as _i10;
import 'package:flutter/material.dart';
import 'package:reza_admin/ui/views/admin_ui/admin_index_tracking/admin_index_tracking_view.dart'
as _i4;
import 'package:reza_admin/ui/views/admin_ui/akun_admin/akun_admin_view.dart'
as _i14;
import 'package:reza_admin/ui/views/admin_ui/makanan_list/add_edit_makanan/add_edit_makanan_view.dart'
as _i6;
import 'package:reza_admin/ui/views/admin_ui/makanan_list/detail_makanan/detail_makanan_view.dart'
as _i5;
import 'package:reza_admin/ui/views/admin_ui/makanan_list/makanan_list_view.dart'
as _i12;
import 'package:reza_admin/ui/views/admin_ui/meja_list/meja_detail/meja_detail_view.dart'
as _i7;
import 'package:reza_admin/ui/views/admin_ui/meja_list/meja_edit/meja_edit_view.dart'
as _i8;
import 'package:reza_admin/ui/views/admin_ui/meja_list/meja_history_log/meja_history_log_view.dart'
as _i9;
import 'package:reza_admin/ui/views/admin_ui/meja_list/meja_list_view.dart'
as _i11;
import 'package:reza_admin/ui/views/admin_ui/pesanan_list/pesanan_list_view.dart'
as _i13;
import 'package:reza_admin/ui/views/login_user/login_user_view.dart' as _i3;
import 'package:reza_admin/ui/views/splash_screen/splash_screen_view.dart'
as _i2;
import 'package:stacked/stacked.dart' as _i1;
import 'package:stacked_services/stacked_services.dart' as _i15;
class Routes {
static const splashScreenView = '/';
static const loginUserView = '/login-user-view';
static const adminIndexTrackingView = '/admin-index-tracking-view';
static const detailMakananView = '/detail-makanan-view';
static const addEditMakananView = '/add-edit-makanan-view';
static const mejaDetailView = '/meja-detail-view';
static const mejaEditView = '/meja-edit-view';
static const mejaHistoryLogView = '/meja-history-log-view';
static const all = <String>{
splashScreenView,
loginUserView,
adminIndexTrackingView,
detailMakananView,
addEditMakananView,
mejaDetailView,
mejaEditView,
mejaHistoryLogView,
};
}
class StackedRouter extends _i1.RouterBase {
final _routes = <_i1.RouteDef>[
_i1.RouteDef(
Routes.splashScreenView,
page: _i2.SplashScreenView,
),
_i1.RouteDef(
Routes.loginUserView,
page: _i3.LoginUserView,
),
_i1.RouteDef(
Routes.adminIndexTrackingView,
page: _i4.AdminIndexTrackingView,
),
_i1.RouteDef(
Routes.detailMakananView,
page: _i5.DetailMakananView,
),
_i1.RouteDef(
Routes.addEditMakananView,
page: _i6.AddEditMakananView,
),
_i1.RouteDef(
Routes.mejaDetailView,
page: _i7.MejaDetailView,
),
_i1.RouteDef(
Routes.mejaEditView,
page: _i8.MejaEditView,
),
_i1.RouteDef(
Routes.mejaHistoryLogView,
page: _i9.MejaHistoryLogView,
),
];
final _pagesMap = <Type, _i1.StackedRouteFactory>{
_i2.SplashScreenView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i2.SplashScreenView(),
settings: data,
);
},
_i3.LoginUserView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i3.LoginUserView(),
settings: data,
);
},
_i4.AdminIndexTrackingView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i4.AdminIndexTrackingView(),
settings: data,
);
},
_i5.DetailMakananView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i5.DetailMakananView(),
settings: data,
);
},
_i6.AddEditMakananView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i6.AddEditMakananView(),
settings: data,
);
},
_i7.MejaDetailView: (data) {
final args = data.getArgs<MejaDetailViewArguments>(nullOk: false);
return _i10.MaterialPageRoute<dynamic>(
builder: (context) =>
_i7.MejaDetailView(key: args.key, mejaId: args.mejaId),
settings: data,
);
},
_i8.MejaEditView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i8.MejaEditView(),
settings: data,
);
},
_i9.MejaHistoryLogView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i9.MejaHistoryLogView(),
settings: data,
);
},
};
@override
List<_i1.RouteDef> get routes => _routes;
@override
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
class MejaDetailViewArguments {
const MejaDetailViewArguments({
this.key,
required this.mejaId,
});
final _i10.Key? key;
final String mejaId;
@override
String toString() {
return '{"key": "$key", "mejaId": "$mejaId"}';
}
@override
bool operator ==(covariant MejaDetailViewArguments other) {
if (identical(this, other)) return true;
return other.key == key && other.mejaId == mejaId;
}
@override
int get hashCode {
return key.hashCode ^ mejaId.hashCode;
}
}
class AdminIndexTrackingViewRoutes {
static const mejaListView = '';
static const makananListView = 'makanan-list-view';
static const pesananListView = 'pesanan-list-view';
static const akunAdminView = 'akun-admin-view';
static const all = <String>{
mejaListView,
makananListView,
pesananListView,
akunAdminView,
};
}
class AdminIndexTrackingViewRouter extends _i1.RouterBase {
final _routes = <_i1.RouteDef>[
_i1.RouteDef(
AdminIndexTrackingViewRoutes.mejaListView,
page: _i11.MejaListView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.makananListView,
page: _i12.MakananListView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.pesananListView,
page: _i13.PesananListView,
),
_i1.RouteDef(
AdminIndexTrackingViewRoutes.akunAdminView,
page: _i14.AkunAdminView,
),
];
final _pagesMap = <Type, _i1.StackedRouteFactory>{
_i11.MejaListView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i11.MejaListView(),
settings: data,
);
},
_i12.MakananListView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.MakananListView(),
settings: data,
);
},
_i13.PesananListView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i13.PesananListView(),
settings: data,
);
},
_i14.AkunAdminView: (data) {
return _i10.MaterialPageRoute<dynamic>(
builder: (context) => const _i14.AkunAdminView(),
settings: data,
);
},
};
@override
List<_i1.RouteDef> get routes => _routes;
@override
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
extension NavigatorStateExtension on _i15.NavigationService {
Future<dynamic> navigateToSplashScreenView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.splashScreenView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToLoginUserView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.loginUserView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToAdminIndexTrackingView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.adminIndexTrackingView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToDetailMakananView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.detailMakananView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToAddEditMakananView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.addEditMakananView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToMejaDetailView({
_i10.Key? key,
required String mejaId,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return navigateTo<dynamic>(Routes.mejaDetailView,
arguments: MejaDetailViewArguments(key: key, mejaId: mejaId),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToMejaEditView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.mejaEditView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToMejaHistoryLogView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.mejaHistoryLogView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedMejaListViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(AdminIndexTrackingViewRoutes.mejaListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
navigateToNestedMakananListViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(AdminIndexTrackingViewRoutes.makananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
navigateToNestedPesananListViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(AdminIndexTrackingViewRoutes.pesananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedAkunAdminViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(AdminIndexTrackingViewRoutes.akunAdminView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithSplashScreenView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.splashScreenView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithLoginUserView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.loginUserView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithAdminIndexTrackingView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.adminIndexTrackingView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithDetailMakananView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.detailMakananView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithAddEditMakananView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.addEditMakananView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithMejaDetailView({
_i10.Key? key,
required String mejaId,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return replaceWith<dynamic>(Routes.mejaDetailView,
arguments: MejaDetailViewArguments(key: key, mejaId: mejaId),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithMejaEditView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.mejaEditView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithMejaHistoryLogView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.mejaHistoryLogView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithNestedMejaListViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(AdminIndexTrackingViewRoutes.mejaListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedMakananListViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(AdminIndexTrackingViewRoutes.makananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedPesananListViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(AdminIndexTrackingViewRoutes.pesananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithNestedAkunAdminViewInAdminIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(AdminIndexTrackingViewRoutes.akunAdminView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
}

View File

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import '../../services/global_var.dart';
import '../../services/http_services.dart';
import '../../services/my_easyloading.dart';
import '../app.locator.dart';
import '../themes/app_colors.dart';
class CustomBaseViewModel extends BaseViewModel {
final dialogService = locator<DialogService>();
final navigationService = locator<NavigationService>();
final bottomSheetService = locator<BottomSheetService>();
final snackbarService = locator<SnackbarService>();
final easyLoading = locator<MyEasyLoading>();
final httpService = locator<MyHttpServices>();
final globalVar = locator<GlobalVar>();
// late bool backPressed;
void back() {
navigationService.back();
}
quitApp(BuildContext context) {
globalVar.backPressed = 'cantBack';
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Keluar'),
content: const Text('Apakah Anda yakin ingin keluar?'),
actions: [
TextButton(
onPressed: () {
globalVar.backPressed = 'exitApp';
Navigator.of(context).pop(false);
},
child: const Text('Batal'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text(
'Keluar',
style: TextStyle(color: dangerColor),
),
),
],
);
},
).then((value) {
if (value == true) {
SystemNavigator.pop();
}
});
}
}

3
lib/app/mycd Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
ffmpeg -i "rtsp://admin:admin123@192.168.2.109/cam/realmonitor?channel=1&subtype=1" -acodec copy -vcodec copy abcd.mp4 -y

30
lib/app/themes/app_colors.dart Executable file
View File

@ -0,0 +1,30 @@
import 'dart:ui';
const Color mainColor = Color.fromARGB(255, 37, 88, 241);
const Color secondaryColor = Color(0xFFB72025);
const Color dangerColor = Color(0xFFFF4B68);
const Color warningColor = Color(0xFFFBFFA3);
const Color lightColor = Color(0xFFF4FAFE);
const Color lightGreyColor = Color(0xFFFCFCFC);
const Color stockColor = Color(0xFFEEF3F6);
const Color backgroundColor = Color(0xFFE5E5E5);
const Color backgroundColor3 = Color(0xFFF6F7F8);
const Color orangeColor = Color.fromARGB(255, 250, 145, 84);
const Color blueColor = Color(0xFF026AA2);
const Color greenColor = Color(0xFF2ABB52);
const Color redColor = Color(0xFFED1717);
const Color greyBlueColor = Color(0xFF363F72);
const Color fontColor = Color(0xFF101828);
const Color fontSecondaryColor = Color(0xFF667085);
const Color fontParagraphColor = Color(0xFFB2B2B2);
const Color fontGrey = Color(0xFF1C1C1C);
const Color mainGrey = Color(0xFF8991A4);
const Color secondaryGrey = Color(0xFFD0D5DD);
const Color thirdGrey = Color(0xFFF2F4F7);
const Color fourthGrey = Color(0xFF5C5C5C);
const Color fifthGrey = Color(0xFFEBEBEB);
const Color sixthGrey = Color(0xFF151515);

View File

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'app_colors.dart';
const regularTextStyle = TextStyle(
fontFamily: 'Arial',
fontSize: 14,
fontWeight: FontWeight.w400,
color: fontColor);
const italicTextStyle = TextStyle(
fontFamily: 'Arial',
fontSize: 14,
color: fontColor,
fontStyle: FontStyle.italic,
);
const mediumTextStyle = TextStyle(
fontFamily: 'Arial',
fontSize: 14,
fontWeight: FontWeight.w500,
color: fontColor,
);
const semiBoldTextStyle = TextStyle(
fontFamily: 'Arial',
fontSize: 14,
fontWeight: FontWeight.w600,
color: fontColor,
);
const boldTextStyle = TextStyle(
fontFamily: 'Arial',
fontSize: 14,
fontWeight: FontWeight.w700,
color: fontColor,
);
const extraBoldTextStyle = TextStyle(
fontFamily: 'Arial',
fontSize: 14,
fontWeight: FontWeight.w800,
color: fontColor,
);

124
lib/app/themes/app_theme.dart Executable file
View File

@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'app_colors.dart';
import 'app_text.dart';
ThemeData appTheme = ThemeData(
useMaterial3: true,
primaryColor: mainColor,
scaffoldBackgroundColor: Colors.white,
canvasColor: Colors.white,
fontFamily: 'Poppins',
appBarTheme: AppBarTheme(
elevation: 0,
titleTextStyle: boldTextStyle.copyWith(fontSize: 16, color: fontGrey),
centerTitle: true,
),
textTheme: TextTheme(
displayLarge: regularTextStyle.copyWith(fontSize: 32),
displayMedium: regularTextStyle.copyWith(fontSize: 20),
displaySmall: regularTextStyle.copyWith(fontSize: 18),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: mainColor,
foregroundColor: Colors.white,
disabledBackgroundColor: mainColor.withOpacity(.3),
minimumSize: const Size(double.maxFinite, 58),
textStyle: boldTextStyle,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
shadowColor: Colors.transparent,
elevation: 0,
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
textStyle: boldTextStyle,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: const BorderSide(
color: mainColor,
width: 1,
),
foregroundColor: mainColor,
// disabledForegroundColor: mainColor.withOpacity(.3),
minimumSize: const Size(double.maxFinite, 58),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: mainColor,
disabledForegroundColor: mainColor.withOpacity(.3),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: semiBoldTextStyle,
shadowColor: Colors.transparent,
),
),
iconTheme: const IconThemeData(
color: mainColor,
),
listTileTheme: ListTileThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.all(mainColor),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
side: const BorderSide(
color: secondaryGrey,
width: 1,
),
),
radioTheme: RadioThemeData(
fillColor: MaterialStateProperty.all(mainColor),
),
tabBarTheme: TabBarTheme(
labelColor: mainColor,
unselectedLabelColor: secondaryGrey,
labelStyle: boldTextStyle.copyWith(fontSize: 16),
unselectedLabelStyle: mediumTextStyle.copyWith(fontSize: 16),
),
chipTheme: ChipThemeData(
backgroundColor: Colors.white,
disabledColor: Colors.white,
selectedColor: Colors.white,
secondarySelectedColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
side: const BorderSide(color: fifthGrey),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
labelStyle: regularTextStyle.copyWith(fontSize: 12, color: fontGrey),
secondaryLabelStyle:
regularTextStyle.copyWith(fontSize: 12, color: secondaryColor),
deleteIconColor: fontGrey,
showCheckmark: false,
),
popupMenuTheme: PopupMenuThemeData(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(
color: fifthGrey,
width: 1,
),
),
),
colorScheme: const ColorScheme.light(
primary: mainColor,
secondary: secondaryColor,
onPrimary: Colors.white,
onSecondary: Colors.white,
error: dangerColor,
onError: dangerColor,
background: backgroundColor,
).copyWith(background: Colors.white),
);

39
lib/main.dart Normal file
View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:stacked_services/stacked_services.dart';
import 'app/app.locator.dart';
import 'app/app.router.dart';
import 'app/themes/app_theme.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: ".env");
await setupAllLocator();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Reza Admin App',
theme: appTheme,
debugShowCheckedModeBanner: false,
navigatorKey: StackedService.navigatorKey,
onGenerateRoute: StackedRouter().onGenerateRoute,
builder: EasyLoading.init(),
);
}
}
Future<void> setupAllLocator() async {
await setupLocator();
// setupDialogUi();
// setupBottomsheetUi();
// setupSnackbarUi();
}

View File

@ -0,0 +1,3 @@
class GlobalVar {
String backPressed = 'backNormal';
}

View File

@ -0,0 +1,35 @@
import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import '../app/app.logger.dart';
class MyHttpServices {
final log = getLogger('MyHttpServices');
final _options = BaseOptions(
baseUrl: dotenv.env['api_url']!,
connectTimeout: const Duration(seconds: 120),
receiveTimeout: const Duration(seconds: 120),
);
late Dio _dio;
MyHttpServices() {
_dio = Dio(_options);
}
Future<Response> get(String path) async {
try {
return await _dio.get(path);
} on DioException {
rethrow;
}
}
Future<Response> postWithFormData(String path, FormData formData) async {
try {
return await _dio.post(path, data: formData);
} on DioException {
rethrow;
}
}
}

View File

@ -0,0 +1,39 @@
import 'package:flutter_easyloading/flutter_easyloading.dart';
class MyEasyLoading {
showLoading() {
EasyLoading.show(
status: 'loading...',
maskType: EasyLoadingMaskType.black,
dismissOnTap: false,
);
}
dismissLoading() {
EasyLoading.dismiss();
}
customLoading(String message) {
EasyLoading.show(
status: message,
maskType: EasyLoadingMaskType.black,
dismissOnTap: false,
);
}
showSuccess(String message) {
EasyLoading.showSuccess(message);
}
showError(String message) {
EasyLoading.showError(message);
}
showInfo(String message) {
EasyLoading.showInfo(message);
}
showProgress(double progress, String status) {
EasyLoading.showProgress(progress, status: status);
}
}

View File

@ -0,0 +1,18 @@
import 'package:intl/intl.dart';
class OtherFunction {
int umur(String tanggalLahir) {
// change tanggalLahir to DateTime
DateTime date = DateTime.parse(tanggalLahir);
// get current date
DateTime now = DateTime.now();
// get difference in year
int year = now.year - date.year;
return year;
}
String commaFormat(int number) {
final formatter = NumberFormat('#,###');
return formatter.format(number);
}
}

View File

@ -0,0 +1,78 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stylish_bottom_bar/model/bar_items.dart';
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
import '../../../../app/app.router.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../../app/themes/app_text.dart';
import './admin_index_tracking_view_model.dart';
class AdminIndexTrackingView extends StatelessWidget {
const AdminIndexTrackingView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<AdminIndexTrackingViewModel>.reactive(
viewModelBuilder: () => AdminIndexTrackingViewModel(),
onViewModelReady: (AdminIndexTrackingViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
AdminIndexTrackingViewModel model,
Widget? child,
) {
return Scaffold(
extendBody: false,
body: ExtendedNavigator(
navigatorKey: StackedService.nestedNavigationKey(2),
router: AdminIndexTrackingViewRouter(),
observers: [
StackedService.routeObserver,
],
),
bottomNavigationBar: StylishBottomBar(
items: [
for (var item in model.bottomNavBarList)
BottomBarItem(
icon: Icon(item['icon'],
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? mainColor
: backgroundColor),
title: Align(
alignment: Alignment.centerLeft,
child: Text(
item['name'],
style: regularTextStyle.copyWith(
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? mainColor
: Colors.grey,
),
),
),
backgroundColor:
model.currentIndex == model.bottomNavBarList.indexOf(item)
? Colors.white
: Colors.grey,
),
],
currentIndex: model.currentIndex,
hasNotch: true,
backgroundColor: mainColor,
onTap: (value) {
model.handleNavigation(value);
},
option: BubbleBarOptions(
barStyle: BubbleBarStyle.horizotnal,
bubbleFillStyle: BubbleFillStyle.fill,
opacity: 0.3),
),
);
},
);
}
}

View File

@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import '../../../../app/app.locator.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/app.router.dart';
import '../../../../services/global_var.dart';
class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
final log = getLogger('AdminIndexTrackingViewModel');
final globalVar = locator<GlobalVar>();
final navigationService = locator<NavigationService>();
final _bottomNavBarList = [
{
'name': 'Meja',
'icon': Icons.table_restaurant_outlined,
'header': 'RESERVASI MEJA',
},
{
'name': 'Makanan',
'icon': Icons.food_bank_outlined,
'header': 'LIST MAKANAN',
},
{
'name': 'Pesanan',
'icon': Icons.shopping_cart_outlined,
'header': 'LIST PESANAN',
},
{
'name': 'Akun',
'icon': Icons.person_outline,
'header': 'AKUN',
},
];
String header = 'RESERVASI MEJA';
List<Map<String, dynamic>> get bottomNavBarList => _bottomNavBarList;
final List<String> _views = [
AdminIndexTrackingViewRoutes.mejaListView,
AdminIndexTrackingViewRoutes.makananListView,
AdminIndexTrackingViewRoutes.pesananListView,
AdminIndexTrackingViewRoutes.akunAdminView,
];
Future<void> init() async {
globalVar.backPressed = 'exitApp';
}
void handleNavigation(int index) {
// log.d("handleNavigation: $index");
// log.d("currentIndex: $currentIndex");
if (currentIndex == index) return;
setIndex(index);
header = _bottomNavBarList[index]['header'] as String;
navigationService.navigateTo(
_views[index],
id: 2,
);
}
}

View File

@ -0,0 +1,42 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './akun_admin_view_model.dart';
class AkunAdminView extends StatelessWidget {
const AkunAdminView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<AkunAdminViewModel>.reactive(
viewModelBuilder: () => AkunAdminViewModel(),
onViewModelReady: (AkunAdminViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
AkunAdminViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
// model.log.d('onWillPop ini akun');
if (model.globalVar.backPressed == 'exitApp') {
model.quitApp(context);
model.globalVar.backPressed = 'exitApp';
return false;
}
return false;
},
child: const Scaffold(
body: Center(
child: Text(
'AkunAdminView',
),
),
),
);
},
);
}
}

View File

@ -0,0 +1,5 @@
import 'package:reza_admin/app/core/custom_base_view_model.dart';
class AkunAdminViewModel extends CustomBaseViewModel {
Future<void> init() async {}
}

View File

@ -0,0 +1,493 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'add_edit_makanan_view_model.dart';
import 'package:stacked/stacked.dart';
import '../../../../../app/themes/app_colors.dart';
import '../../../../../app/themes/app_text.dart';
import '../../../../widgets/my_white_container.dart';
class AddEditMakananView extends HookWidget {
const AddEditMakananView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final scrollController = useScrollController();
final opacity = useState(0.0);
final theHeight = useState(MediaQuery.of(useContext()).size.height * 0.35);
checkScrollValue(scrollController, opacity, theHeight);
return ViewModelBuilder<AddEditMakananViewModel>.reactive(
viewModelBuilder: () => AddEditMakananViewModel(),
onViewModelReady: (AddEditMakananViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
AddEditMakananViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
model.log.d('onWillPop ini detail makanan');
model.globalVar.backPressed = 'exitApp';
return true;
},
child: Scaffold(
backgroundColor: backgroundColor,
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
ListView.builder(
controller: scrollController,
itemCount: 1,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
const TopMenuWidget(),
const SecondWidget(),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Ongkos Kirim',
style: boldTextStyle.copyWith(
fontSize: 14,
),
),
TextSpan(
text: ' Harga Ongkir Di Sini',
style: boldTextStyle.copyWith(
fontSize: 14,
color: dangerColor,
fontStyle: FontStyle.italic,
),
),
],
),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.edit,
color: dangerColor,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
Text(
"Bisa Dibayar COD sekitar Parepare",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
),
),
],
),
),
),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"Deskripsi",
style: boldTextStyle.copyWith(
fontSize: 15,
),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.edit,
color: mainGrey,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
// bikin dummy text tentang nasi goreng
Text(
"Deskripsi Makanan Di Sini",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.justify,
),
],
),
),
),
const SizedBox(
height: 20,
),
],
);
},
),
TopBarWidget(opacity: opacity),
],
),
),
bottomNavigationBar: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
width: MediaQuery.of(context).size.width,
height: 70,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
spreadRadius: 5,
),
],
),
child: Container(
height: 40,
decoration: BoxDecoration(
color: dangerColor,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
"Tambah Makanan Baru",
style: boldTextStyle.copyWith(
fontSize: 16,
color: Colors.white,
),
),
),
),
)),
);
},
);
}
void checkScrollValue(
ScrollController scrollController,
ValueNotifier<double> opacity,
ValueNotifier<double> theHeight,
) {
scrollController.addListener(() {
opacity.value = scrollController.offset / theHeight.value;
if (opacity.value > 1) {
opacity.value = 1;
} else if (opacity.value < 0) {
opacity.value = 0;
}
});
}
}
class TopBarWidget extends ViewModelWidget<AddEditMakananViewModel> {
const TopBarWidget({
super.key,
required this.opacity,
});
final ValueNotifier<double> opacity;
@override
Widget build(BuildContext context, AddEditMakananViewModel viewModel) {
return Positioned(
top: 0,
child: Container(
padding: const EdgeInsets.all(10),
width: MediaQuery.of(context).size.width,
color: Colors.white.withOpacity(opacity.value),
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
Row(
// create 3 circle widget, with background color is black and opacity is 0.5, ist icon is back, second icon is cart and third icon is 3 dots
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
onPressed: () {
viewModel.globalVar.backPressed = 'exitApp';
viewModel.back();
},
icon: const Icon(
Icons.arrow_back,
color: Colors.white,
),
),
),
// const Expanded(
// child: SizedBox(
// width: 20,
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.black.withOpacity(0.5),
// borderRadius: BorderRadius.circular(20),
// ),
// child: IconButton(
// onPressed: () {},
// icon: const Icon(
// Icons.shopping_cart_outlined,
// color: Colors.white,
// ),
// ),
// ),
// const SizedBox(
// width: 20,
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.black.withOpacity(0.5),
// borderRadius: BorderRadius.circular(20),
// ),
// child: IconButton(
// onPressed: () {},
// icon: const Icon(
// Icons.more_vert,
// color: Colors.white,
// ),
// ),
// ),
],
),
],
),
),
);
}
}
class SecondWidget extends ViewModelWidget<AddEditMakananViewModel> {
const SecondWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, AddEditMakananViewModel viewModel) {
return MyWhiteContainer(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
"Nama Makanan Di Sini",
style: regularTextStyle.copyWith(
fontSize: 17,
fontStyle: FontStyle.italic,
),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.edit,
color: mainGrey,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: Text(
"Harga Makanan Di Sini",
style: regularTextStyle.copyWith(
fontSize: 18,
color: dangerColor,
),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.edit,
color: dangerColor,
),
iconSize: 20,
),
const SizedBox(
width: 10,
),
],
),
const SizedBox(
height: 10,
),
],
),
),
],
),
);
}
}
class TopMenuWidget extends ViewModelWidget<AddEditMakananViewModel> {
const TopMenuWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, AddEditMakananViewModel viewModel) {
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,
// ),
child: Center(
child: Text(
'Add Image',
style: boldTextStyle.copyWith(
fontSize: 20,
),
),
),
),
// 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,
// ),
// ),
// ),
// ),
// ),
Positioned(
bottom: 20,
right: 20,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
width: 50,
height: 50,
decoration: BoxDecoration(
color: mainColor,
borderRadius: BorderRadius.circular(10),
),
child: const Center(
child: Icon(
Icons.camera_alt_outlined,
color: Colors.white,
size: 30,
),
),
),
),
],
);
}
}

View File

@ -0,0 +1,9 @@
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
class AddEditMakananViewModel extends CustomBaseViewModel {
final log = getLogger('AddMakananViewModel');
Future<void> init() async {
globalVar.backPressed = 'backNormal';
}
}

View File

@ -0,0 +1,406 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:stacked/stacked.dart';
import '../../../../../app/themes/app_colors.dart';
import '../../../../../app/themes/app_text.dart';
import '../../../../widgets/my_white_container.dart';
import './detail_makanan_view_model.dart';
class DetailMakananView extends HookWidget {
const DetailMakananView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final scrollController = useScrollController();
final opacity = useState(0.0);
final theHeight = useState(MediaQuery.of(useContext()).size.height * 0.35);
checkScrollValue(scrollController, opacity, theHeight);
return ViewModelBuilder<DetailMakananViewModel>.reactive(
viewModelBuilder: () => DetailMakananViewModel(),
onViewModelReady: (DetailMakananViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
DetailMakananViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
model.log.d('onWillPop ini detail makanan');
model.globalVar.backPressed = 'exitApp';
return true;
},
child: Scaffold(
backgroundColor: backgroundColor,
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
ListView.builder(
controller: scrollController,
itemCount: 1,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
const TopMenuWidget(),
const SecondWidget(),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Ongkos Kirim',
style: boldTextStyle.copyWith(
fontSize: 14,
),
),
TextSpan(
text: ' Rp. 10.000',
style: boldTextStyle.copyWith(
fontSize: 14,
color: dangerColor,
),
),
],
),
),
const SizedBox(
height: 10,
),
Text(
"Bisa Dibayar COD sekitar Parepare",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
),
),
],
),
),
),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Deskripsi",
style: boldTextStyle.copyWith(
fontSize: 15,
),
),
const SizedBox(
height: 10,
),
// 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.",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
),
textAlign: TextAlign.justify,
),
],
),
),
),
const SizedBox(
height: 20,
),
],
);
},
),
TopBarWidget(opacity: opacity),
],
),
),
bottomNavigationBar: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
width: MediaQuery.of(context).size.width,
height: 70,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
spreadRadius: 5,
),
],
),
child: Container(
height: 40,
decoration: BoxDecoration(
color: dangerColor,
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Text(
"Edit Detail Makanan",
style: boldTextStyle.copyWith(
fontSize: 16,
color: Colors.white,
),
),
),
),
)),
);
},
);
}
void checkScrollValue(
ScrollController scrollController,
ValueNotifier<double> opacity,
ValueNotifier<double> theHeight,
) {
scrollController.addListener(() {
opacity.value = scrollController.offset / theHeight.value;
if (opacity.value > 1) {
opacity.value = 1;
} else if (opacity.value < 0) {
opacity.value = 0;
}
});
}
}
class TopBarWidget extends ViewModelWidget<DetailMakananViewModel> {
const TopBarWidget({
super.key,
required this.opacity,
});
final ValueNotifier<double> opacity;
@override
Widget build(BuildContext context, DetailMakananViewModel viewModel) {
return Positioned(
top: 0,
child: Container(
padding: const EdgeInsets.all(10),
width: MediaQuery.of(context).size.width,
color: Colors.white.withOpacity(opacity.value),
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
Row(
// create 3 circle widget, with background color is black and opacity is 0.5, ist icon is back, second icon is cart and third icon is 3 dots
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
onPressed: () {
viewModel.globalVar.backPressed = 'exitApp';
viewModel.back();
},
icon: const Icon(
Icons.arrow_back,
color: Colors.white,
),
),
),
// const Expanded(
// child: SizedBox(
// width: 20,
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.black.withOpacity(0.5),
// borderRadius: BorderRadius.circular(20),
// ),
// child: IconButton(
// onPressed: () {},
// icon: const Icon(
// Icons.shopping_cart_outlined,
// color: Colors.white,
// ),
// ),
// ),
// const SizedBox(
// width: 20,
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.black.withOpacity(0.5),
// borderRadius: BorderRadius.circular(20),
// ),
// child: IconButton(
// onPressed: () {},
// icon: const Icon(
// Icons.more_vert,
// color: Colors.white,
// ),
// ),
// ),
],
),
],
),
),
);
}
}
class SecondWidget extends ViewModelWidget<DetailMakananViewModel> {
const SecondWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, DetailMakananViewModel viewModel) {
return MyWhiteContainer(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Burger King Handcrafted Burgers ",
style: regularTextStyle.copyWith(
fontSize: 17,
),
),
const SizedBox(
height: 10,
),
Text(
"Rp. 25.000",
style: regularTextStyle.copyWith(
fontSize: 18,
color: dangerColor,
),
),
const SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: Text(
"49 Terjual",
style: regularTextStyle.copyWith(
fontSize: 14,
color: fontGrey,
),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.favorite_border,
color: fontGrey,
),
),
const SizedBox(
width: 10,
),
],
)
],
),
),
],
),
);
}
}
class TopMenuWidget extends ViewModelWidget<DetailMakananViewModel> {
const TopMenuWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, DetailMakananViewModel viewModel) {
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,
),
),
),
),
),
],
);
}
}

View File

@ -0,0 +1,10 @@
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
class DetailMakananViewModel extends CustomBaseViewModel {
final log = getLogger('DetailMakananViewModel');
Future<void> init() async {
globalVar.backPressed = 'backNormal';
}
}

View File

@ -0,0 +1,219 @@
import 'package:flutter/material.dart';
import 'package:reza_admin/app/app.router.dart';
import 'package:stacked/stacked.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../widgets/my_textformfield.dart';
import '../../../widgets/my_white_container.dart';
import './makanan_list_view_model.dart';
class MakananListView extends StatelessWidget {
const MakananListView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<MakananListViewModel>.reactive(
viewModelBuilder: () => MakananListViewModel(),
onViewModelReady: (MakananListViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
MakananListViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
model.log.d('onWillPop ini makanan');
if (model.globalVar.backPressed == 'exitApp') {
model.quitApp(context);
model.globalVar.backPressed = 'exitApp';
return false;
}
return false;
},
child: Scaffold(
backgroundColor: backgroundColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// get the top height of the notification bar
SizedBox(
height: MediaQuery.of(context).padding.top,
),
MyWhiteContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 2,
child: IconButton(
onPressed: () => model.back(),
icon: const Icon(Icons.arrow_back),
),
),
const SizedBox(
width: 10,
),
Expanded(
flex: 10,
child: MyTextFormField(
// controller: model.searchController,
hintText: 'Cari Makanan',
suffixIcon: IconButton(
onPressed: () {},
icon: const Icon(Icons.search),
),
),
),
Expanded(
flex: 1,
child: IconButton(
onPressed: () {},
icon: const Icon(Icons.filter_list),
),
),
TextButton(
onPressed: () {},
child: const Text('Filter'),
),
],
),
),
const SizedBox(
height: 5,
),
MyWhiteContainer(
child: IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: TextButton(
onPressed: () {},
child: const Text('Terbaru'),
),
),
const VerticalDivider(
color: mainGrey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Text(
'Terlaris',
style: TextStyle(
color: mainGrey,
),
),
),
),
const VerticalDivider(
color: Colors.grey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Row(
children: [
Text(
'Harga',
style: TextStyle(
color: mainGrey,
),
),
Icon(
Icons.arrow_drop_down,
color: mainGrey,
),
],
),
),
),
],
),
),
),
const SizedBox(
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,
),
),
),
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,
),
],
),
),
),
],
),
),
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
model.navigationService.navigateToAddEditMakananView();
},
// create a add product button
child: const Icon(Icons.add),
),
),
);
},
);
}
}

View File

@ -0,0 +1,15 @@
import '../../../../app/app.logger.dart';
import '../../../../app/app.router.dart';
import '../../../../app/core/custom_base_view_model.dart';
class MakananListViewModel extends CustomBaseViewModel {
final log = getLogger('MakananListViewModel');
Future<void> init() async {
globalVar.backPressed = 'exitApp';
}
goToDetailMakanan() {
log.i('goToDetailMakanan');
navigationService.navigateTo(Routes.detailMakananView);
}
}

View File

@ -0,0 +1,302 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import '../../../../../app/themes/app_colors.dart';
import '../../../../../app/themes/app_text.dart';
import './meja_detail_view_model.dart';
class MejaDetailView extends StatelessWidget {
final String mejaId;
const MejaDetailView({
Key? key,
required this.mejaId,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ViewModelBuilder<MejaDetailViewModel>.reactive(
viewModelBuilder: () => MejaDetailViewModel(),
onViewModelReady: (MejaDetailViewModel model) async {
await model.init(mejaId);
},
builder: (
BuildContext context,
MejaDetailViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
if (model.globalVar.backPressed == 'backNormal') {
model.globalVar.backPressed = 'exitApp';
return true;
}
// model.quitApp(context);
return false;
},
child: Scaffold(
appBar: AppBar(
title: const Text('MejaDetailView',
style: TextStyle(color: Colors.white)),
backgroundColor: mainColor,
leading: IconButton(
onPressed: () {
if (model.globalVar.backPressed == 'backNormal') {
model.globalVar.backPressed = 'exitApp';
model.navigationService.back();
// return true;
}
},
icon: const Icon(Icons.arrow_back, color: Colors.white),
),
),
body: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 250,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: model.imgAsset == null
? const Center(child: CircularProgressIndicator())
: Image.asset(model.imgAsset!, fit: BoxFit.cover),
),
),
const SizedBox(height: 5),
Text(
model.namaMeja,
style: const TextStyle(
fontSize: 20,
// fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
RichText(
text: TextSpan(
text: 'Status : ',
style: regularTextStyle,
children: [
TextSpan(
text: 'Tersedia',
style: regularTextStyle.copyWith(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 10),
RichText(
text: TextSpan(
text: 'Kapasitas : ',
style: regularTextStyle,
children: [
TextSpan(
text: 'Maksimal 8 Orang',
style: regularTextStyle.copyWith(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 10),
RichText(
text: TextSpan(
text: 'Lokasi : ',
style: regularTextStyle,
children: [
TextSpan(
text: 'Luar Ruangan',
style: regularTextStyle.copyWith(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 10),
RichText(
text: TextSpan(
text: 'Harga : ',
style: regularTextStyle,
children: [
TextSpan(
text: 'Rp. 20.000',
style: regularTextStyle.copyWith(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
),
],
),
),
const SizedBox(height: 10),
Expanded(
child: ListView.builder(
itemCount: 2,
shrinkWrap: true,
itemBuilder: (context, index) {
// make the color random between red and blue
const color = Colors.blue;
String pesanStatus = 'Menunggu Pengesahan';
return Card(
color: color,
child: ListTile(
// leading: CircleAvatar(
// backgroundColor: Colors.white,
// child: Text(
// index.toString(),
// style: regularTextStyle,
// ),
// ),
title: Text(
'Nama Pemesan',
style: regularTextStyle.copyWith(
fontSize: 18,
color: Colors.white,
fontStyle: FontStyle.italic,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'08:00.00 - 09:00.00',
style: TextStyle(
color: Colors.white,
),
),
Text(
pesanStatus,
style: const TextStyle(
color: Colors.white,
),
),
],
),
trailing: const Icon(Icons.arrow_forward_ios,
color: Colors.white),
onTap: () {
model.log.i('Meja 1');
},
),
);
},
),
),
],
),
),
bottomNavigationBar: Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
width: MediaQuery.of(context).size.width,
height: 70,
decoration: BoxDecoration(
color: mainColor,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
spreadRadius: 5,
),
],
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Row(
children: [
Expanded(
child: GestureDetector(
onTap: () {
model.log.i('Edit');
},
child: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.edit,
color: Colors.white,
),
SizedBox(
height: 5,
),
Text(
'Edit',
style: TextStyle(
color: Colors.white,
),
),
],
),
),
),
// divider
Container(
width: 1,
height: 30,
color: Colors.white,
),
Expanded(
child: GestureDetector(
onTap: () {
model.log.i('List');
// model.navigationService.navigateToMakananListView();
},
child: const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.list,
color: Colors.white,
),
SizedBox(
height: 5,
),
Text(
'History Booking',
style: TextStyle(
color: Colors.white,
),
),
],
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: orangeColor,
onPressed: () {
// model.navigationService.navigateToAddEditMakananView();
},
// create a add product button
child: const Icon(
Icons.edit_calendar_outlined,
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.miniEndTop,
),
);
},
);
}
}

View File

@ -0,0 +1,35 @@
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
class MejaDetailViewModel extends CustomBaseViewModel {
final log = getLogger('MejaDetailViewModel');
late String mejaId;
late String namaMeja;
String? imgAsset;
Future<void> init(String mejaId) async {
log.i('MejaDetailViewModel init');
log.i('mejaId : $mejaId');
this.mejaId = mejaId;
globalVar.backPressed = 'backNormal';
// seperate the number from the string
var number = int.parse(mejaId.replaceAll(RegExp(r'[^0-9]'), ''));
// log.i('number : $number');
if (number <= 4) {
namaMeja = 'Gazebo';
imgAsset = 'assets/reza_gazebo.jpeg';
} else if (number >= 5 && number <= 12) {
namaMeja = 'Meja';
imgAsset = 'assets/reza_meja_1.jpeg';
} else if (number >= 13 && number <= 22) {
namaMeja = 'Meja';
imgAsset = 'assets/reza_meja_2.jpeg';
}
namaMeja = '$namaMeja $number';
log.i('imgAsset : $imgAsset');
}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './meja_edit_view_model.dart';
class MejaEditView extends StatelessWidget {
const MejaEditView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<MejaEditViewModel>.reactive(
viewModelBuilder: () => MejaEditViewModel(),
onViewModelReady: (MejaEditViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
MejaEditViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'MejaEditView',
),
),
);
},
);
}
}

View File

@ -0,0 +1,7 @@
import '../../../../../app/core/custom_base_view_model.dart';
class MejaEditViewModel extends CustomBaseViewModel {
Future<void> init() async {
globalVar.backPressed = 'backNormal';
}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './meja_history_log_view_model.dart';
class MejaHistoryLogView extends StatelessWidget {
const MejaHistoryLogView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<MejaHistoryLogViewModel>.reactive(
viewModelBuilder: () => MejaHistoryLogViewModel(),
onViewModelReady: (MejaHistoryLogViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
MejaHistoryLogViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'MejaHistoryLogView',
),
),
);
},
);
}
}

View File

@ -0,0 +1,7 @@
import '../../../../../app/core/custom_base_view_model.dart';
class MejaHistoryLogViewModel extends CustomBaseViewModel {
Future<void> init() async {
globalVar.backPressed = 'backNormal';
}
}

View File

@ -0,0 +1,235 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:reza_admin/app/app.router.dart';
import 'package:reza_admin/app/themes/app_colors.dart';
import 'package:reza_admin/app/themes/app_text.dart';
import 'package:stacked/stacked.dart';
import 'package:webview_flutter/webview_flutter.dart';
import './meja_list_view_model.dart';
class MejaListView extends StatelessWidget {
const MejaListView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<MejaListViewModel>.reactive(
viewModelBuilder: () => MejaListViewModel(),
onViewModelReady: (MejaListViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
MejaListViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
model.log.d('onWillPop ini meja');
if (model.globalVar.backPressed == 'exitApp') {
model.quitApp(context);
model.globalVar.backPressed = 'exitApp';
return false;
}
return false;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Reservasi Meja',
style: TextStyle(
color: Colors.white,
)),
backgroundColor: mainColor,
automaticallyImplyLeading: false,
),
body: Column(
children: [
const SizedBox(
height: 20,
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.35,
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);
},
onProgress: (int progress) {
// model.log.i('WebView is loading (progress : $progress%)');
// show a loading indicator when the WebView is loading using circular progress indicator
model.easyLoading.customLoading('Loading Data Meja');
},
// javascriptChannels: <JavascriptChannel>{
// _toasterJavascriptChannel(context),
// },
javascriptChannels: <JavascriptChannel>{
JavascriptChannel(
name: 'messageHandler',
onMessageReceived: (JavascriptMessage message) async {
model.log.i('messageHandler : ${message.message}');
model.navigationService.navigateToMejaDetailView(
mejaId: message.message,
);
},
),
JavascriptChannel(
name: 'messageHandler1',
onMessageReceived: (JavascriptMessage message) async {
// String no_telpon = message.message;
// dev.i('no_telpon : $no_telpon');
// await launchUrl(Uri.parse('tel:$no_telpon'));
},
),
},
navigationDelegate: (NavigationRequest request) async {
// if (request.url.startsWith('https://www.youtube.com/')) {
// dev.log('blocking navigation to $request}');
// return NavigationDecision.prevent;
// }
// check if request.url has 'nrm'
return NavigationDecision.navigate;
},
onPageStarted: (String url) {
model.log.i('Page started loading: $url');
},
onPageFinished: (String url) {
model.log.i('Page finished loading: $url');
model.easyLoading.dismissLoading();
},
gestureNavigationEnabled: true,
backgroundColor: const Color(0x00000000),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
// create 3 circle color
Container(
width: 20,
height: 20,
decoration: const BoxDecoration(
color: Color.fromRGBO(223, 216, 214, 1),
shape: BoxShape.circle,
),
),
const SizedBox(width: 5),
const Text('Tersedia'),
const SizedBox(width: 10),
Container(
width: 20,
height: 20,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
const SizedBox(width: 5),
const Text('Dibooking'),
const SizedBox(width: 10),
Container(
width: 20,
height: 20,
decoration: const BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
const SizedBox(width: 5),
const Text('Menunggu'),
const SizedBox(width: 10),
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.grey[600],
shape: BoxShape.circle,
),
),
const SizedBox(width: 5),
const Text('Tidak Tersedia'),
const SizedBox(width: 10),
],
),
),
),
const SizedBox(
height: 15,
),
Expanded(
child: ListView.builder(
itemCount: 15,
shrinkWrap: true,
itemBuilder: (context, index) {
// make the color random between red and blue
final color = index % 2 == 0 ? Colors.red : Colors.blue;
String pesanStatus =
index % 2 == 0 ? 'Dibooking' : 'Menunggu Pengesahan';
return Card(
color: color,
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.white,
child: Text(
index.toString(),
style: regularTextStyle,
),
),
title: Text(
'Nama Pemesan',
style: regularTextStyle.copyWith(
fontSize: 18,
color: Colors.white,
fontStyle: FontStyle.italic,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'08:00.00 - 09:00.00',
style: TextStyle(
color: Colors.white,
),
),
Text(
pesanStatus,
style: const TextStyle(
color: Colors.white,
),
),
],
),
trailing: const Icon(Icons.arrow_forward_ios,
color: Colors.white),
onTap: () {
model.log.i('Meja 1');
},
),
);
},
),
),
const SizedBox(
height: 15,
),
],
),
),
);
},
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:reza_admin/app/app.logger.dart';
import '../../../../app/core/custom_base_view_model.dart';
class MejaListViewModel extends CustomBaseViewModel {
final log = getLogger('MejaListViewModel');
Future<void> init() async {
globalVar.backPressed = 'exitApp';
}
}

View File

@ -0,0 +1,298 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../../app/themes/app_text.dart';
import '../../../widgets/my_white_container.dart';
import './pesanan_list_view_model.dart';
class PesananListView extends StatelessWidget {
const PesananListView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<PesananListViewModel>.reactive(
viewModelBuilder: () => PesananListViewModel(),
onViewModelReady: (PesananListViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
PesananListViewModel model,
Widget? child,
) {
return WillPopScope(
onWillPop: () async {
model.log.d('onWillPop ini pesanan');
if (model.globalVar.backPressed == 'exitApp') {
model.quitApp(context);
model.globalVar.backPressed = 'exitApp';
return false;
}
return false;
},
child: Scaffold(
appBar: AppBar(
title: Text(
'List Pesanan',
style: boldTextStyle.copyWith(color: Colors.white),
),
backgroundColor: mainColor,
automaticallyImplyLeading: false,
),
backgroundColor: backgroundColor,
body: Column(
children: [
MyWhiteContainer(
child: IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: TextButton(
onPressed: () {},
child: const Text(
'Orderan',
style: TextStyle(color: mainGrey),
),
),
),
const VerticalDivider(
color: mainGrey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Text('Dikemas'),
),
),
const VerticalDivider(
color: mainGrey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Text(
'Dikirim',
style: TextStyle(
color: mainGrey,
),
),
),
),
const VerticalDivider(
color: Colors.grey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Text(
'Selesai',
style: TextStyle(
color: mainGrey,
),
),
),
),
],
),
),
),
const SizedBox(
height: 15,
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: 10,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
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',
height: 100,
width: double.infinity,
fit: BoxFit.fill,
errorBuilder:
(context, error, stackTrace) {
return const Icon(Icons.error);
},
),
),
),
const SizedBox(
width: 20,
),
Expanded(
child: IntrinsicHeight(
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
'Nama Makanan',
style:
regularTextStyle.copyWith(
fontSize: 17,
),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(
height: 5,
),
Align(
alignment: Alignment.centerRight,
child: Text(
'x 1',
style:
regularTextStyle.copyWith(
color: mainGrey,
fontSize: 17,
),
),
),
const SizedBox(
height: 5,
),
Align(
alignment: Alignment.centerRight,
child: Text(
'Rp. 100.000',
style:
regularTextStyle.copyWith(
color: redColor,
fontSize: 17,
),
),
),
],
),
),
)
],
),
const SizedBox(
height: 10,
),
Center(
child: Text(
'Tampilkan Produk Lain',
style: regularTextStyle.copyWith(
color: mainGrey,
),
),
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Text(
'3 Item',
style: regularTextStyle,
),
const Expanded(child: SizedBox()),
RichText(
text: TextSpan(
text: 'Total Pesanan: ',
style: regularTextStyle,
children: [
TextSpan(
text: 'Rp. 300.000',
style: regularTextStyle.copyWith(
color: redColor,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
const SizedBox(
height: 15,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
// lorry icon
const Icon(
Icons.local_shipping_outlined,
color: mainColor,
),
const SizedBox(
width: 5,
),
Text(
'Pesanan telah sampai',
style: regularTextStyle.copyWith(
color: mainColor,
),
),
const Expanded(child: SizedBox()),
const Icon(
Icons.arrow_forward_ios,
color: mainGrey,
size: 15,
),
],
),
],
),
),
),
);
},
),
),
],
),
// floatingActionButton: FloatingActionButton.extended(
// onPressed: () {},
// label: Text(
// 'Pesan',
// style: boldTextStyle.copyWith(color: Colors.white),
// ),
// icon: const Icon(
// Icons.shopping_cart,
// color: Colors.white,
// ),
// backgroundColor: mainColor,
// ),
),
);
},
);
}
}

View File

@ -0,0 +1,9 @@
import '../../../../app/app.logger.dart';
import '../../../../app/core/custom_base_view_model.dart';
class PesananListViewModel extends CustomBaseViewModel {
final log = getLogger('PesananListViewModel');
Future<void> init() async {
globalVar.backPressed = 'exitApp';
}
}

View File

@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import '../../../app/themes/app_text.dart';
import '../../widgets/my_button.dart';
import '../../widgets/my_textformfield.dart';
import './login_user_view_model.dart';
class LoginUserView extends StatelessWidget {
const LoginUserView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<LoginUserViewModel>.reactive(
viewModelBuilder: () => LoginUserViewModel(),
onViewModelReady: (LoginUserViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
LoginUserViewModel model,
Widget? child,
) {
return Scaffold(
body: WillPopScope(
onWillPop: () async {
if (model.globalVar.backPressed == 'bacNormal') {
// model.back();
model.quitApp(context);
}
return false;
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Center(
child: SingleChildScrollView(
child: Form(
key: model.formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/logo.png',
width: 200,
height: 200,
),
const SizedBox(height: 16),
const Text(
'Halaman Login',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Text(
'Admin App',
style: regularTextStyle.copyWith(
fontSize: 12,
fontStyle: FontStyle.italic,
),
),
const SizedBox(height: 16),
MyTextFormField(
maxLength: 13,
hintText: 'No. HP',
keyboardType: TextInputType.phone,
controller: model.noHpController,
),
const SizedBox(height: 16),
MyTextFormField(
hintText: 'Password',
obscureText: model.showPassword,
controller: model.passwordController,
suffixIcon: IconButton(
onPressed: () {
model.showPassword = !model.showPassword;
model.notifyListeners();
},
icon: Icon(
model.showPassword
? Icons.visibility_off
: Icons.visibility,
),
),
),
const SizedBox(height: 16),
MyButton(
text: 'Login',
onPressed: () {
FocusScope.of(context).unfocus();
model.log.i('Login button pressed');
model.login();
},
),
],
),
),
),
),
),
),
);
},
);
}
}

View File

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:reza_admin/app/app.router.dart';
import '../../../app/app.logger.dart';
import '../../../app/core/custom_base_view_model.dart';
class LoginUserViewModel extends CustomBaseViewModel {
final log = getLogger('LoginUserViewModel');
TextEditingController noHpController = TextEditingController();
TextEditingController passwordController = TextEditingController();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
bool showPassword = true;
Future<void> init() async {}
login() async {
setBusy(true);
globalVar.backPressed = 'cantBack';
easyLoading.showLoading();
await Future.delayed(const Duration(seconds: 2));
easyLoading.dismissLoading();
setBusy(false);
globalVar.backPressed = 'backNormal';
notifyListeners();
await navigationService.navigateToAdminIndexTrackingView();
}
}

View File

@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
import 'package:reza_admin/app/themes/app_text.dart';
import 'package:stacked/stacked.dart';
import './splash_screen_view_model.dart';
class SplashScreenView extends StatelessWidget {
const SplashScreenView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<SplashScreenViewModel>.reactive(
viewModelBuilder: () => SplashScreenViewModel(),
onViewModelReady: (SplashScreenViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
SplashScreenViewModel model,
Widget? child,
) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Expanded(
flex: 1,
child: SizedBox(
height: 20,
),
),
Expanded(
flex: 2,
child: Column(
children: [
Center(
child: Image.asset(
'assets/logo.png',
width: 200,
height: 200,
),
),
const Text(
'Reza Table Reservation \n& Food Order',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 5),
Text(
'Admin App',
style: regularTextStyle.copyWith(
fontSize: 12,
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.center,
),
],
),
),
const SizedBox(height: 20),
const Text(
'Alamat jalan jendral sudirman',
style: TextStyle(
fontSize: 16,
),
),
const SizedBox(height: 20),
],
),
);
},
);
}
}

View File

@ -0,0 +1,10 @@
import '../../../app/app.router.dart';
import '../../../app/core/custom_base_view_model.dart';
class SplashScreenViewModel extends CustomBaseViewModel {
Future<void> init() async {
await Future.delayed(const Duration(seconds: 2));
await navigationService.navigateToLoginUserView();
}
}

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import '../../app/themes/app_colors.dart';
class MyButton extends StatelessWidget {
const MyButton({
Key? key,
required this.text,
this.onPressed,
}) : super(key: key);
final String text;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: mainColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
),
onPressed: onPressed,
child: Text(
text,
style: const TextStyle(
color: backgroundColor,
fontSize: 18,
),
),
);
}
}

View File

@ -0,0 +1,91 @@
import 'package:flutter/material.dart';
import '../../app/themes/app_colors.dart';
class MyTextFormField extends StatelessWidget {
const MyTextFormField({
Key? key,
this.labelText,
this.hintText,
this.obscureText,
this.validator,
this.suffixIcon,
this.prefixIcon,
this.focusNode,
this.controller,
this.maxLines = 1,
this.onEditingComplete,
this.readOnly = false,
this.onTap,
this.keyboardType = TextInputType.text,
this.initialValue,
this.enabled = true,
this.maxLength,
}) : super(key: key);
final String? labelText;
final String? hintText;
final bool? obscureText;
final FormFieldValidator<String>? validator;
final Widget? suffixIcon;
final Widget? prefixIcon;
final FocusNode? focusNode;
final TextEditingController? controller;
final int maxLines;
final VoidCallback? onEditingComplete;
final bool readOnly;
final VoidCallback? onTap;
final TextInputType keyboardType;
final String? initialValue;
final bool enabled;
final int? maxLength;
@override
Widget build(BuildContext context) {
return TextFormField(
maxLength: maxLength,
enabled: enabled,
initialValue: initialValue,
onEditingComplete: onEditingComplete,
maxLines: maxLines,
controller: controller,
focusNode: focusNode,
obscureText: obscureText ?? false,
readOnly: readOnly,
onTap: onTap,
keyboardType: keyboardType,
decoration: InputDecoration(
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: mainColor,
),
),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: mainColor,
),
),
focusedErrorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: dangerColor,
),
),
errorBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
borderSide: BorderSide(
color: dangerColor,
),
),
labelText: labelText,
hintText: hintText,
labelStyle: const TextStyle(color: fontColor),
),
validator: validator,
);
}
}

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class MyWhiteContainer extends StatelessWidget {
final Widget? child;
final double? height;
const MyWhiteContainer({
Key? key,
this.child,
this.height,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: height,
padding: const EdgeInsets.symmetric(
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: child,
);
}
}