added other
This commit is contained in:
parent
b82edc2db9
commit
949474b8ef
4
.env
4
.env
|
@ -1,2 +1,2 @@
|
||||||
url = 'http://20.20.20.25/perumahan/'
|
url = 'http://20.20.20.25/panti_asuhan2/'
|
||||||
api_url = 'http://20.20.20.25/perumahan/api/'
|
api_url = 'http://20.20.20.25/panti_asuhan2/api/'
|
|
@ -2,11 +2,13 @@ import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index/admin_ind
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart';
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart';
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart';
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart';
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/profil/profil_view.dart';
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/profil/profil_view.dart';
|
||||||
|
import 'package:panti_asuhan/ui/views/tambah_dana_sosial/tambah_dana_sosial_view.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:stacked/stacked_annotations.dart';
|
import 'package:stacked/stacked_annotations.dart';
|
||||||
|
|
||||||
import '../services/http_services.dart';
|
import '../services/http_services.dart';
|
||||||
import '../services/my_easyloading.dart';
|
import '../services/my_easyloading.dart';
|
||||||
|
import '../ui/views/admin_index_tracking/add_siswa_dialog/add_siswa_dialog/add_siswa_dialog_view.dart';
|
||||||
import '../ui/views/admin_index_tracking/admin_index_tracking_view.dart';
|
import '../ui/views/admin_index_tracking/admin_index_tracking_view.dart';
|
||||||
import '../ui/views/login_screen/login_screen_view.dart';
|
import '../ui/views/login_screen/login_screen_view.dart';
|
||||||
import '../ui/views/splash_screen/splash_screen_view.dart';
|
import '../ui/views/splash_screen/splash_screen_view.dart';
|
||||||
|
@ -24,6 +26,10 @@ import '../ui/views/splash_screen/splash_screen_view.dart';
|
||||||
MaterialRoute(page: ProfilView),
|
MaterialRoute(page: ProfilView),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
MaterialRoute(page: TambahDanaSosialView),
|
||||||
|
],
|
||||||
|
dialogs: [
|
||||||
|
StackedDialog(classType: AddSiswaDialogView),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
LazySingleton(classType: NavigationService),
|
LazySingleton(classType: NavigationService),
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// StackedDialogGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
|
||||||
|
import 'app.locator.dart';
|
||||||
|
import '../ui/views/admin_index_tracking/add_siswa_dialog/add_siswa_dialog/add_siswa_dialog_view.dart';
|
||||||
|
|
||||||
|
enum DialogType {
|
||||||
|
addSiswaDialogView,
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupDialogUi() {
|
||||||
|
final dialogService = locator<DialogService>();
|
||||||
|
|
||||||
|
final Map<DialogType, DialogBuilder> builders = {
|
||||||
|
DialogType.addSiswaDialogView: (context, request, completer) =>
|
||||||
|
AddSiswaDialogView(request: request, completer: completer),
|
||||||
|
};
|
||||||
|
|
||||||
|
dialogService.registerCustomDialogBuilders(builders);
|
||||||
|
}
|
|
@ -5,24 +5,26 @@
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'package:flutter/material.dart' as _i5;
|
import 'package:flutter/material.dart' as _i6;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index/admin_index_view.dart'
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index/admin_index_view.dart'
|
||||||
as _i6;
|
as _i7;
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index_tracking_view.dart'
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/admin_index_tracking_view.dart'
|
||||||
as _i4;
|
as _i4;
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart'
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/dana_sosial_admin/dana_sosial_admin_view.dart'
|
||||||
as _i7;
|
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart'
|
|
||||||
as _i8;
|
as _i8;
|
||||||
import 'package:panti_asuhan/ui/views/admin_index_tracking/profil/profil_view.dart'
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/data_siswa/data_siswa_view.dart'
|
||||||
as _i9;
|
as _i9;
|
||||||
|
import 'package:panti_asuhan/ui/views/admin_index_tracking/profil/profil_view.dart'
|
||||||
|
as _i10;
|
||||||
import 'package:panti_asuhan/ui/views/login_screen/login_screen_view.dart'
|
import 'package:panti_asuhan/ui/views/login_screen/login_screen_view.dart'
|
||||||
as _i3;
|
as _i3;
|
||||||
import 'package:panti_asuhan/ui/views/splash_screen/splash_screen_view.dart'
|
import 'package:panti_asuhan/ui/views/splash_screen/splash_screen_view.dart'
|
||||||
as _i2;
|
as _i2;
|
||||||
|
import 'package:panti_asuhan/ui/views/tambah_dana_sosial/tambah_dana_sosial_view.dart'
|
||||||
|
as _i5;
|
||||||
import 'package:stacked/stacked.dart' as _i1;
|
import 'package:stacked/stacked.dart' as _i1;
|
||||||
import 'package:stacked_services/stacked_services.dart' as _i10;
|
import 'package:stacked_services/stacked_services.dart' as _i11;
|
||||||
|
|
||||||
class Routes {
|
class Routes {
|
||||||
static const splashScreenView = '/';
|
static const splashScreenView = '/';
|
||||||
|
@ -31,10 +33,13 @@ class Routes {
|
||||||
|
|
||||||
static const adminIndexTrackingView = '/admin-index-tracking-view';
|
static const adminIndexTrackingView = '/admin-index-tracking-view';
|
||||||
|
|
||||||
|
static const tambahDanaSosialView = '/tambah-dana-sosial-view';
|
||||||
|
|
||||||
static const all = <String>{
|
static const all = <String>{
|
||||||
splashScreenView,
|
splashScreenView,
|
||||||
loginScreenView,
|
loginScreenView,
|
||||||
adminIndexTrackingView,
|
adminIndexTrackingView,
|
||||||
|
tambahDanaSosialView,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,30 +57,41 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
Routes.adminIndexTrackingView,
|
Routes.adminIndexTrackingView,
|
||||||
page: _i4.AdminIndexTrackingView,
|
page: _i4.AdminIndexTrackingView,
|
||||||
),
|
),
|
||||||
|
_i1.RouteDef(
|
||||||
|
Routes.tambahDanaSosialView,
|
||||||
|
page: _i5.TambahDanaSosialView,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
||||||
_i2.SplashScreenView: (data) {
|
_i2.SplashScreenView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i2.SplashScreenView(),
|
builder: (context) => const _i2.SplashScreenView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i3.LoginScreenView: (data) {
|
_i3.LoginScreenView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i3.LoginScreenView(),
|
builder: (context) => const _i3.LoginScreenView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i4.AdminIndexTrackingView: (data) {
|
_i4.AdminIndexTrackingView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i4.AdminIndexTrackingView(),
|
builder: (context) => const _i4.AdminIndexTrackingView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
_i5.TambahDanaSosialView: (data) {
|
||||||
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
|
builder: (context) => _i5.TambahDanaSosialView(),
|
||||||
|
settings: data,
|
||||||
|
maintainState: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -105,47 +121,47 @@ class AdminIndexTrackingViewRouter extends _i1.RouterBase {
|
||||||
final _routes = <_i1.RouteDef>[
|
final _routes = <_i1.RouteDef>[
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
AdminIndexTrackingViewRoutes.adminIndexView,
|
AdminIndexTrackingViewRoutes.adminIndexView,
|
||||||
page: _i6.AdminIndexView,
|
page: _i7.AdminIndexView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
AdminIndexTrackingViewRoutes.danaSosialAdminView,
|
AdminIndexTrackingViewRoutes.danaSosialAdminView,
|
||||||
page: _i7.DanaSosialAdminView,
|
page: _i8.DanaSosialAdminView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
AdminIndexTrackingViewRoutes.dataSiswaView,
|
AdminIndexTrackingViewRoutes.dataSiswaView,
|
||||||
page: _i8.DataSiswaView,
|
page: _i9.DataSiswaView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
AdminIndexTrackingViewRoutes.profilView,
|
AdminIndexTrackingViewRoutes.profilView,
|
||||||
page: _i9.ProfilView,
|
page: _i10.ProfilView,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
||||||
_i6.AdminIndexView: (data) {
|
_i7.AdminIndexView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i6.AdminIndexView(),
|
builder: (context) => const _i7.AdminIndexView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i7.DanaSosialAdminView: (data) {
|
_i8.DanaSosialAdminView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i7.DanaSosialAdminView(),
|
builder: (context) => const _i8.DanaSosialAdminView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i8.DataSiswaView: (data) {
|
_i9.DataSiswaView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i8.DataSiswaView(),
|
builder: (context) => const _i9.DataSiswaView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i9.ProfilView: (data) {
|
_i10.ProfilView: (data) {
|
||||||
return _i5.MaterialPageRoute<dynamic>(
|
return _i6.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i9.ProfilView(),
|
builder: (context) => const _i10.ProfilView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
maintainState: false,
|
maintainState: false,
|
||||||
);
|
);
|
||||||
|
@ -158,7 +174,7 @@ class AdminIndexTrackingViewRouter extends _i1.RouterBase {
|
||||||
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
|
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NavigatorStateExtension on _i10.NavigationService {
|
extension NavigatorStateExtension on _i11.NavigationService {
|
||||||
Future<dynamic> navigateToSplashScreenView([
|
Future<dynamic> navigateToSplashScreenView([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
@ -201,6 +217,20 @@ extension NavigatorStateExtension on _i10.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> navigateToTambahDanaSosialView([
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
]) async {
|
||||||
|
return navigateTo<dynamic>(Routes.tambahDanaSosialView,
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToNestedAdminIndexViewInAdminIndexTrackingViewRouter([
|
Future<dynamic> navigateToNestedAdminIndexViewInAdminIndexTrackingViewRouter([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
@ -300,6 +330,20 @@ extension NavigatorStateExtension on _i10.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> replaceWithTambahDanaSosialView([
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
]) async {
|
||||||
|
return replaceWith<dynamic>(Routes.tambahDanaSosialView,
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic>
|
Future<dynamic>
|
||||||
replaceWithNestedAdminIndexViewInAdminIndexTrackingViewRouter([
|
replaceWithNestedAdminIndexViewInAdminIndexTrackingViewRouter([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
|
||||||
|
import 'app/app.dialogs.dart';
|
||||||
import 'app/app.locator.dart';
|
import 'app/app.locator.dart';
|
||||||
import 'app/app.router.dart';
|
import 'app/app.router.dart';
|
||||||
import 'app/themes/app_theme.dart';
|
import 'app/themes/app_theme.dart';
|
||||||
|
@ -33,7 +34,7 @@ class MyApp extends StatelessWidget {
|
||||||
|
|
||||||
Future<void> setupAllLocator() async {
|
Future<void> setupAllLocator() async {
|
||||||
await setupLocator();
|
await setupLocator();
|
||||||
// setupDialogUi();
|
setupDialogUi();
|
||||||
// setupBottomsheetUi();
|
// setupBottomsheetUi();
|
||||||
// setupSnackbarUi();
|
// setupSnackbarUi();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
import '../app/app.logger.dart';
|
||||||
|
|
||||||
class MyHttpServices {
|
class MyHttpServices {
|
||||||
|
final log = getLogger('MyHttpServices');
|
||||||
final _options = BaseOptions(
|
final _options = BaseOptions(
|
||||||
baseUrl: dotenv.env['api_url']!,
|
baseUrl: dotenv.env['api_url']!,
|
||||||
connectTimeout: const Duration(seconds: 60),
|
connectTimeout: const Duration(seconds: 60),
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:panti_asuhan/app/themes/app_text.dart';
|
||||||
|
import 'package:panti_asuhan/ui/widgets/my_textformfield.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
import 'package:validatorless/validatorless.dart';
|
||||||
|
|
||||||
|
import '../../../../../app/themes/app_colors.dart';
|
||||||
|
import './add_siswa_dialog_view_model.dart';
|
||||||
|
|
||||||
|
class DataSiswa {
|
||||||
|
final String? nama;
|
||||||
|
|
||||||
|
DataSiswa({required this.nama, r});
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddSiswaDialogView extends StatelessWidget {
|
||||||
|
final DialogRequest<DataSiswa> request;
|
||||||
|
final Function(DialogResponse) completer;
|
||||||
|
|
||||||
|
const AddSiswaDialogView({
|
||||||
|
Key? key,
|
||||||
|
required DialogRequest request,
|
||||||
|
required this.completer,
|
||||||
|
}) : request = request as DialogRequest<DataSiswa>,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ViewModelBuilder<AddSiswaDialogViewModel>.reactive(
|
||||||
|
viewModelBuilder: () => AddSiswaDialogViewModel(),
|
||||||
|
onViewModelReady: (AddSiswaDialogViewModel model) async {
|
||||||
|
await model.init();
|
||||||
|
},
|
||||||
|
builder: (
|
||||||
|
BuildContext context,
|
||||||
|
AddSiswaDialogViewModel model,
|
||||||
|
Widget? child,
|
||||||
|
) {
|
||||||
|
return Dialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Form(
|
||||||
|
key: model.formKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Tambah Siswa',
|
||||||
|
style: boldTextStyle.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
// create circle avatar
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
CircleAvatar(
|
||||||
|
radius: 50,
|
||||||
|
backgroundColor: fontParagraphColor,
|
||||||
|
child: model.imageBytes == null
|
||||||
|
? const Icon(
|
||||||
|
Icons.person,
|
||||||
|
size: 50,
|
||||||
|
color: Colors.white,
|
||||||
|
)
|
||||||
|
: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(50),
|
||||||
|
child: Image.memory(
|
||||||
|
model.imageBytes!,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
child: CircleAvatar(
|
||||||
|
radius: 15,
|
||||||
|
backgroundColor: blueColor,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
model.addImage();
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.add,
|
||||||
|
color: lightColor,
|
||||||
|
size: 15,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
MyTextFormField(
|
||||||
|
labelText: 'NIS',
|
||||||
|
controller: model.nisController,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
validator: Validatorless.multiple([
|
||||||
|
Validatorless.required('NIS tidak boleh kosong'),
|
||||||
|
Validatorless.number('NIS harus angka'),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
MyTextFormField(
|
||||||
|
labelText: 'Nama',
|
||||||
|
controller: model.namaController,
|
||||||
|
validator:
|
||||||
|
Validatorless.required('Nama tidak boleh kosong'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
MyTextFormField(
|
||||||
|
labelText: 'Tanggal Lahir',
|
||||||
|
controller: model.tanggalLahirController,
|
||||||
|
readOnly: true,
|
||||||
|
validator: Validatorless.required(
|
||||||
|
'Tanggal lahir tidak boleh kosong'),
|
||||||
|
onTap: () {
|
||||||
|
model.changeDate(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
// create dropdown button
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
border: Border.all(
|
||||||
|
color: mainColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton<String>(
|
||||||
|
value: model.jenisKelamin,
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
// model.setSelectedJenisKelamin(newValue!);
|
||||||
|
model.log.i(newValue);
|
||||||
|
model.jenisKelamin = newValue!;
|
||||||
|
model.notifyListeners();
|
||||||
|
},
|
||||||
|
items: model.jenisKelaminList.map((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(
|
||||||
|
value,
|
||||||
|
style: regularTextStyle.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
MyTextFormField(
|
||||||
|
labelText: 'Alamat',
|
||||||
|
controller: model.alamatController,
|
||||||
|
maxLines: 2,
|
||||||
|
validator:
|
||||||
|
Validatorless.required('Alamat tidak boleh kosong'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
MyTextFormField(
|
||||||
|
labelText: 'Keahlian',
|
||||||
|
controller: model.keahlianController,
|
||||||
|
maxLines: 4,
|
||||||
|
validator: Validatorless.required(
|
||||||
|
'Keahlian tidak boleh kosong'),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => completer(
|
||||||
|
DialogResponse(
|
||||||
|
confirmed: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Text(
|
||||||
|
'Batal',
|
||||||
|
style: TextStyle(
|
||||||
|
color: dangerColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (model.formKey.currentState!.validate()) {
|
||||||
|
bool res = await model.postData();
|
||||||
|
model.log.i("res: $res");
|
||||||
|
// if (res) {
|
||||||
|
// completer(
|
||||||
|
// DialogResponse(
|
||||||
|
// confirmed: true,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text(
|
||||||
|
'Simpan',
|
||||||
|
style: TextStyle(
|
||||||
|
color: blueColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_holo_date_picker/flutter_holo_date_picker.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:panti_asuhan/app/app.locator.dart';
|
||||||
|
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||||
|
|
||||||
|
import '../../../../../app/app.logger.dart';
|
||||||
|
import '../../../../../services/http_services.dart';
|
||||||
|
import '../../../../../services/my_easyloading.dart';
|
||||||
|
|
||||||
|
class AddSiswaDialogViewModel extends CustomBaseViewModel {
|
||||||
|
final log = getLogger('AddSiswaDialogViewModel');
|
||||||
|
final _httpService = locator<MyHttpServices>();
|
||||||
|
final easyLoading = locator<MyEasyLoading>();
|
||||||
|
List<String> jenisKelaminList = ['Laki-laki', 'Perempuan'];
|
||||||
|
|
||||||
|
String jenisKelamin = 'Laki-laki';
|
||||||
|
|
||||||
|
// image picker
|
||||||
|
String? _imagePath;
|
||||||
|
final ImagePicker _picker = ImagePicker();
|
||||||
|
XFile? imageFile;
|
||||||
|
Uint8List? imageBytes;
|
||||||
|
|
||||||
|
// form and text controller
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
TextEditingController nisController = TextEditingController();
|
||||||
|
TextEditingController namaController = TextEditingController();
|
||||||
|
TextEditingController tanggalLahirController = TextEditingController();
|
||||||
|
TextEditingController alamatController = TextEditingController();
|
||||||
|
TextEditingController keahlianController = TextEditingController();
|
||||||
|
|
||||||
|
Future<void> init() async {}
|
||||||
|
|
||||||
|
void changeDate(BuildContext context) async {
|
||||||
|
// get today's date
|
||||||
|
var datePicked = await DatePicker.showSimpleDatePicker(
|
||||||
|
context,
|
||||||
|
initialDate: DateTime(2010),
|
||||||
|
firstDate: DateTime(2000),
|
||||||
|
lastDate: DateTime(2015),
|
||||||
|
dateFormat: "dd-MMMM-yyyy",
|
||||||
|
locale: DateTimePickerLocale.id,
|
||||||
|
looping: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (datePicked != null) {
|
||||||
|
String date = datePicked.toString().split(' ')[0];
|
||||||
|
tanggalLahirController.text = date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addImage() async {
|
||||||
|
try {
|
||||||
|
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
|
||||||
|
if (image != null) {
|
||||||
|
imageFile = image;
|
||||||
|
_imagePath = image.path;
|
||||||
|
imageBytes = await image.readAsBytes();
|
||||||
|
|
||||||
|
log.i('image path: $_imagePath');
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log.e(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> postData() async {
|
||||||
|
if (imageBytes == null) {
|
||||||
|
easyLoading.showError('Foto belum dipilih');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
easyLoading.customLoading('Menambahkan data...');
|
||||||
|
try {
|
||||||
|
var formData = FormData.fromMap({
|
||||||
|
'nis': nisController.text,
|
||||||
|
'nama': namaController.text,
|
||||||
|
'jenis_kelamin': jenisKelamin,
|
||||||
|
'tanggal_lahir': tanggalLahirController.text,
|
||||||
|
'alamat': alamatController.text,
|
||||||
|
'keahlian': keahlianController.text,
|
||||||
|
'foto': await MultipartFile.fromFile(_imagePath!),
|
||||||
|
});
|
||||||
|
|
||||||
|
var response = await _httpService.postWithFormData('siswa', formData);
|
||||||
|
easyLoading.dismissLoading();
|
||||||
|
log.i(response.data);
|
||||||
|
easyLoading.showSuccess('Siswa berhasil ditambahkan');
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
easyLoading.dismissLoading();
|
||||||
|
snackbarService.showSnackbar(
|
||||||
|
message: 'Terjadi kesalahan',
|
||||||
|
title: 'Gagal',
|
||||||
|
duration: const Duration(seconds: 4),
|
||||||
|
);
|
||||||
|
log.e(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// completer(
|
||||||
|
// DialogResponse(
|
||||||
|
// confirmed: true,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,10 +20,9 @@ class AdminIndexView extends StatelessWidget {
|
||||||
) {
|
) {
|
||||||
return const Scaffold(
|
return const Scaffold(
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Text(
|
child: CircularProgressIndicator(
|
||||||
'AdminIndexView asdas asda aasdsda a',
|
color: Colors.grey,
|
||||||
),
|
)),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,6 +36,12 @@ class AdminIndexTrackingViewModel extends IndexTrackingViewModel {
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
setIndex(1);
|
setIndex(1);
|
||||||
|
// await 2 seconds to make sure the view is loaded
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
_navigationService.navigateTo(
|
||||||
|
_views[1],
|
||||||
|
id: 3,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNavigation(int index) {
|
void handleNavigation(int index) {
|
||||||
|
|
|
@ -35,8 +35,7 @@ class DanaSosialAdminView extends StatelessWidget {
|
||||||
color: mainGrey.withOpacity(0.5),
|
color: mainGrey.withOpacity(0.5),
|
||||||
spreadRadius: 5,
|
spreadRadius: 5,
|
||||||
blurRadius: 7,
|
blurRadius: 7,
|
||||||
offset:
|
offset: const Offset(0, 3), // changes position of shadow
|
||||||
const Offset(0, 3), // changes position of shadow
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -114,10 +113,13 @@ class DanaSosialAdminView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: const FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: null,
|
onPressed: () {
|
||||||
child: Icon(Icons.add),
|
model.goToTambahDanaSosial();
|
||||||
));
|
},
|
||||||
|
child: const Icon(Icons.add),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
|
||||||
|
|
||||||
import '../../../../app/app.logger.dart';
|
import '../../../../app/app.logger.dart';
|
||||||
|
import '../../../../app/app.router.dart';
|
||||||
|
import '../../../../app/core/custom_base_view_model.dart';
|
||||||
|
|
||||||
class DanaSosialAdminViewModel extends CustomBaseViewModel {
|
class DanaSosialAdminViewModel extends CustomBaseViewModel {
|
||||||
final log = getLogger('DanaSosialAdminViewModel');
|
final log = getLogger('DanaSosialAdminViewModel');
|
||||||
Future<void> init() async {}
|
Future<void> init() async {}
|
||||||
|
|
||||||
|
goToTambahDanaSosial() {
|
||||||
|
navigationService.navigateTo(Routes.tambahDanaSosialView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
|
import '../../../../app/themes/app_colors.dart';
|
||||||
|
import '../../../../app/themes/app_text.dart';
|
||||||
import './data_siswa_view_model.dart';
|
import './data_siswa_view_model.dart';
|
||||||
|
|
||||||
class DataSiswaView extends StatelessWidget {
|
class DataSiswaView extends StatelessWidget {
|
||||||
|
@ -18,11 +20,102 @@ class DataSiswaView extends StatelessWidget {
|
||||||
DataSiswaViewModel model,
|
DataSiswaViewModel model,
|
||||||
Widget? child,
|
Widget? child,
|
||||||
) {
|
) {
|
||||||
return const Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
body: Column(
|
||||||
child: Text(
|
children: [
|
||||||
'DataSiswaView',
|
Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: mainColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: mainGrey.withOpacity(0.5),
|
||||||
|
spreadRadius: 5,
|
||||||
|
blurRadius: 7,
|
||||||
|
offset: const Offset(0, 3), // changes position of shadow
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Total Siswa',
|
||||||
|
style: regularTextStyle.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'20 orang',
|
||||||
|
style: regularTextStyle.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 25),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: mainGrey.withOpacity(0.5),
|
||||||
|
spreadRadius: 5,
|
||||||
|
blurRadius: 7,
|
||||||
|
offset:
|
||||||
|
const Offset(0, 3), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 15, vertical: 10),
|
||||||
|
itemCount: 20,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Card(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
model.log.i('Card $index tapped');
|
||||||
|
},
|
||||||
|
child: ListTile(
|
||||||
|
title: Text('Namanya',
|
||||||
|
style: boldTextStyle.copyWith(
|
||||||
|
fontSize: 13, color: mainColor)),
|
||||||
|
subtitle: Text('Umurnya : $index'),
|
||||||
|
// circle avatar
|
||||||
|
trailing: Container(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: mainColor,
|
||||||
|
borderRadius: BorderRadius.circular(50),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.person,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () {
|
||||||
|
model.addSiswa();
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.add),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||||
|
|
||||||
|
import '../../../../app/app.dialogs.dart';
|
||||||
|
import '../../../../app/app.logger.dart';
|
||||||
|
import '../add_siswa_dialog/add_siswa_dialog/add_siswa_dialog_view.dart';
|
||||||
|
|
||||||
class DataSiswaViewModel extends CustomBaseViewModel {
|
class DataSiswaViewModel extends CustomBaseViewModel {
|
||||||
|
final log = getLogger('DataSiswaViewModel');
|
||||||
Future<void> init() async {}
|
Future<void> init() async {}
|
||||||
|
|
||||||
|
void addSiswa() async {
|
||||||
|
final res = await dialogService.showCustomDialog(
|
||||||
|
variant: DialogType.addSiswaDialogView,
|
||||||
|
data: DataSiswa(nama: null),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res?.confirmed != true) return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ class LoginScreenView extends StatelessWidget {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
|
||||||
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
@ -78,6 +79,7 @@ class LoginScreenView extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:panti_asuhan/app/themes/app_colors.dart';
|
||||||
|
import 'package:panti_asuhan/app/themes/app_text.dart';
|
||||||
|
import 'package:panti_asuhan/ui/widgets/my_button.dart';
|
||||||
|
import 'package:panti_asuhan/ui/widgets/my_textformfield.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:validatorless/validatorless.dart';
|
||||||
|
|
||||||
|
import './tambah_dana_sosial_view_model.dart';
|
||||||
|
|
||||||
|
class TambahDanaSosialView extends StatelessWidget {
|
||||||
|
const TambahDanaSosialView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ViewModelBuilder<TambahDanaSosialViewModel>.reactive(
|
||||||
|
viewModelBuilder: () => TambahDanaSosialViewModel(),
|
||||||
|
onViewModelReady: (TambahDanaSosialViewModel model) async {
|
||||||
|
await model.init();
|
||||||
|
},
|
||||||
|
builder: (
|
||||||
|
BuildContext context,
|
||||||
|
TambahDanaSosialViewModel model,
|
||||||
|
Widget? child,
|
||||||
|
) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text(
|
||||||
|
"Form Dana Sosial",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: mainColor,
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||||
|
child: Form(
|
||||||
|
key: model.formKey,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Keterangan",
|
||||||
|
style: regularTextStyle.copyWith(color: mainColor),
|
||||||
|
),
|
||||||
|
MyTextFormField(
|
||||||
|
hintText: "Keterangan",
|
||||||
|
controller: model.ketController,
|
||||||
|
maxLines: 3,
|
||||||
|
validator: Validatorless.required(
|
||||||
|
'Keterangan tidak boleh kosong'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"Jumlah (Rp. )",
|
||||||
|
style: regularTextStyle.copyWith(color: mainColor),
|
||||||
|
),
|
||||||
|
MyTextFormField(
|
||||||
|
hintText: "Jumlah (Rp. )",
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
controller: model.jumlahController,
|
||||||
|
validator: Validatorless.multiple(
|
||||||
|
[
|
||||||
|
Validatorless.required('Jumlah tidak boleh kosong'),
|
||||||
|
Validatorless.number('Jumlah harus angka'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"Tanggal",
|
||||||
|
style: regularTextStyle.copyWith(color: mainColor),
|
||||||
|
),
|
||||||
|
MyTextFormField(
|
||||||
|
hintText: 'Tanggal',
|
||||||
|
readOnly: true,
|
||||||
|
validator: Validatorless.required(
|
||||||
|
'Tanggal lahir tidak boleh kosong'),
|
||||||
|
onTap: () {
|
||||||
|
model.changeDate(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
"Jenis Dana",
|
||||||
|
style: regularTextStyle.copyWith(color: mainColor),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
border: Border.all(
|
||||||
|
color: mainColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton<String>(
|
||||||
|
value: model.jenisDana,
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
model.jenisDana = newValue!;
|
||||||
|
},
|
||||||
|
items: model.jenisDanaList
|
||||||
|
.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value,
|
||||||
|
style: const TextStyle(fontSize: 16)),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
MyButton(
|
||||||
|
text: "Simpan",
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:panti_asuhan/app/core/custom_base_view_model.dart';
|
||||||
|
|
||||||
|
class TambahDanaSosialViewModel extends CustomBaseViewModel {
|
||||||
|
String jenisDana = 'Pemasukan';
|
||||||
|
List<String> jenisDanaList = ['Pemasukan', 'Pengeluaran'];
|
||||||
|
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
TextEditingController ketController = TextEditingController();
|
||||||
|
TextEditingController jumlahController = TextEditingController();
|
||||||
|
TextEditingController tanggalController = TextEditingController();
|
||||||
|
|
||||||
|
Future<void> init() async {}
|
||||||
|
|
||||||
|
void changeDate(BuildContext context) async {
|
||||||
|
// get today's date
|
||||||
|
var datePicked = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: DateTime.now(),
|
||||||
|
firstDate: DateTime(2000),
|
||||||
|
// last date is today's date
|
||||||
|
lastDate: DateTime.now(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (datePicked != null) {
|
||||||
|
String date = datePicked.toString().split(' ')[0];
|
||||||
|
tanggalController.text = date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,9 @@ class MyTextFormField extends StatelessWidget {
|
||||||
this.controller,
|
this.controller,
|
||||||
this.maxLines = 1,
|
this.maxLines = 1,
|
||||||
this.onEditingComplete,
|
this.onEditingComplete,
|
||||||
|
this.readOnly = false,
|
||||||
|
this.onTap,
|
||||||
|
this.keyboardType = TextInputType.text,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String? labelText;
|
final String? labelText;
|
||||||
|
@ -27,6 +30,9 @@ class MyTextFormField extends StatelessWidget {
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final int maxLines;
|
final int maxLines;
|
||||||
final VoidCallback? onEditingComplete;
|
final VoidCallback? onEditingComplete;
|
||||||
|
final bool readOnly;
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
final TextInputType keyboardType;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -36,6 +42,9 @@ class MyTextFormField extends StatelessWidget {
|
||||||
controller: controller,
|
controller: controller,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
obscureText: obscureText ?? false,
|
obscureText: obscureText ?? false,
|
||||||
|
readOnly: readOnly,
|
||||||
|
onTap: onTap,
|
||||||
|
keyboardType: keyboardType,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: prefixIcon,
|
prefixIcon: prefixIcon,
|
||||||
suffixIcon: suffixIcon,
|
suffixIcon: suffixIcon,
|
||||||
|
|
24
pubspec.lock
24
pubspec.lock
|
@ -33,6 +33,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.10.0"
|
||||||
|
auto_size_text:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: auto_size_text
|
||||||
|
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -246,6 +254,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.5"
|
version: "3.0.5"
|
||||||
|
flutter_holo_date_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_holo_date_picker
|
||||||
|
sha256: "94cf29471ffac123043745b65c690dcf6d481e98c11bda71f78a34dd6f726247"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -813,6 +829,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
|
validatorless:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: validatorless
|
||||||
|
sha256: ddb46df636114b3322d289489164cac309767b157191ba43c7ad49b28c2b57c7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.3"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -46,6 +46,9 @@ dependencies:
|
||||||
google_fonts:
|
google_fonts:
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
stylish_bottom_bar: ^1.0.0
|
stylish_bottom_bar: ^1.0.0
|
||||||
|
# calendar_date_picker2: ^0.5.2
|
||||||
|
flutter_holo_date_picker: ^1.1.0
|
||||||
|
validatorless: ^1.2.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in New Issue