step 3 : copy login screen app dokter
This commit is contained in:
103
app_petty_cash/lib/app/app_extension.dart
Normal file
103
app_petty_cash/lib/app/app_extension.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
extension AppStringExtension on String {
|
||||
String currencyFormat() {
|
||||
final numberFormat = NumberFormat.currency(
|
||||
locale: 'id_ID',
|
||||
decimalDigits: 0,
|
||||
symbol: 'Rp ',
|
||||
);
|
||||
return numberFormat.format(double.parse(this));
|
||||
}
|
||||
|
||||
String dateFormat() {
|
||||
final dateFormatFromApi = DateFormat('yyyy-M-dd hh:mm:ss');
|
||||
// final dateFormat = DateFormat('dd MMM yyyy');
|
||||
final dateFormat = DateFormat('dd/M/yy');
|
||||
return dateFormat.format(dateFormatFromApi.parse(this));
|
||||
}
|
||||
|
||||
String dateFormatdmy() {
|
||||
final dateFormatFromApi = DateFormat('yyyy-M-dd hh:mm:ss');
|
||||
// final dateFormat = DateFormat('dd MMM yyyy');
|
||||
final dateFormat = DateFormat('dd-MM-yyyy hh:mm:ss');
|
||||
return dateFormat.format(dateFormatFromApi.parse(this));
|
||||
}
|
||||
|
||||
String dateFormatdmyHistorical() {
|
||||
final dateFormatFromApi = DateFormat('yyyy-MM-dd');
|
||||
// final dateFormat = DateFormat('dd MMM yyyy');
|
||||
final dateFormat = DateFormat('dd-MM-yyyy');
|
||||
return dateFormat.format(dateFormatFromApi.parse(this));
|
||||
}
|
||||
}
|
||||
|
||||
String formatBulanIndo(String tanggal) {
|
||||
DateTime dateTime = DateFormat("yyyy-MM-dd").parse(tanggal);
|
||||
|
||||
var m = DateFormat('MM').format(dateTime);
|
||||
var month = "";
|
||||
switch (m) {
|
||||
case '01':
|
||||
{
|
||||
month = "Januari";
|
||||
}
|
||||
break;
|
||||
case '02':
|
||||
{
|
||||
month = "Februari";
|
||||
}
|
||||
break;
|
||||
case '03':
|
||||
{
|
||||
month = "Maret";
|
||||
}
|
||||
break;
|
||||
case '04':
|
||||
{
|
||||
month = "April";
|
||||
}
|
||||
break;
|
||||
case '05':
|
||||
{
|
||||
month = "Mei";
|
||||
}
|
||||
break;
|
||||
case '06':
|
||||
{
|
||||
month = "Juni";
|
||||
}
|
||||
break;
|
||||
case '07':
|
||||
{
|
||||
month = "Juli";
|
||||
}
|
||||
break;
|
||||
case '08':
|
||||
{
|
||||
month = "Agustus";
|
||||
}
|
||||
break;
|
||||
case '09':
|
||||
{
|
||||
month = "September";
|
||||
}
|
||||
break;
|
||||
case '10':
|
||||
{
|
||||
month = "Oktober";
|
||||
}
|
||||
break;
|
||||
case '11':
|
||||
{
|
||||
month = "November";
|
||||
}
|
||||
break;
|
||||
case '12':
|
||||
{
|
||||
month = "Desember";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return month;
|
||||
}
|
||||
556
app_petty_cash/lib/app/constant.dart
Normal file
556
app_petty_cash/lib/app/constant.dart
Normal file
@@ -0,0 +1,556 @@
|
||||
// ignore_for_file: prefer_const_constructors, non_constant_identifier_names
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Constant {
|
||||
static double designHeight = 1024;
|
||||
static double designWidth = 1440;
|
||||
|
||||
static double designHeightPhone = 844;
|
||||
static double designWidthPhone = 390;
|
||||
|
||||
static String bearerName = "petty-cash";
|
||||
static String version = "2.00";
|
||||
|
||||
// static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/";
|
||||
|
||||
// tester devbandungraya
|
||||
static String baseUrl =
|
||||
"http://devbandungraya.aplikasi.web.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
static String baseUrl_appdoctor =
|
||||
"http://devbandungraya.aplikasi.web.id/one-api/app_doctor/";
|
||||
|
||||
// * surabaya
|
||||
// static String baseUrl =
|
||||
// "http://surabaya.bisone.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://surabaya.bisone.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// * jakarta
|
||||
// static String baseUrl =
|
||||
// "http://jakarta.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://jakarta.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// * bandung
|
||||
// static String baseUrl =
|
||||
// "http://bandung.bisone3.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://bandung.bisone3.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// * salatiga
|
||||
// static String baseUrl =
|
||||
// "http://salatigaraya.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://salatigaraya.bisone7.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// * semarang
|
||||
// static String baseUrl =
|
||||
// "http://semarang.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://semarang.bisone7.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// * magelang
|
||||
// static String baseUrl =
|
||||
// "http://magelang.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://magelang.bisone7.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * tegal
|
||||
// static String baseUrl =
|
||||
// "http://tegal.bisone7.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://tegal.bisone7.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * cirebon
|
||||
// static String baseUrl =
|
||||
// "http://cirebon.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://cirebon.bisone4.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * tasik
|
||||
// static String baseUrl =
|
||||
// "http://tasikmalaya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://tasikmalaya.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * jogja
|
||||
// static String baseUrl =
|
||||
// "http://jogja.bisone.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://jogja.bisone.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * bali
|
||||
// static String baseUrl =
|
||||
// "http://bali.bisone.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://bali.bisone.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * medan
|
||||
// static String baseUrl =
|
||||
// "http://medan.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://medan.bisone4.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * palembang
|
||||
// static String baseUrl =
|
||||
// "http://palembang.bisone5.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://palembang.bisone5.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * pontianak
|
||||
// static String baseUrl =
|
||||
// "http://pontianakraya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://pontianakraya.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * balikpapan
|
||||
// static String baseUrl =
|
||||
// "http://balikpapan.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://balikpapan.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * padang
|
||||
// static String baseUrl =
|
||||
// "http://padang.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://padang.bisone4.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * pekanbaru
|
||||
// static String baseUrl =
|
||||
// "http://pekanbaru.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://pekanbaru.bisone4.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * makassar
|
||||
// static String baseUrl =
|
||||
// "http://makassar.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://makassar.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// // * manado
|
||||
// static String baseUrl =
|
||||
// "http://manado.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://manado.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
// * bekasi
|
||||
// static String baseUrl =
|
||||
// "http://bekasiraya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/";
|
||||
|
||||
// static String baseUrl_appdoctor =
|
||||
// "http://bekasiraya.bisone2.pramitalab.id/one-api/app_doctor/";
|
||||
|
||||
//color Theme
|
||||
// login marketing
|
||||
static Color subTitleBlack = const Color(0xff000000);
|
||||
static Color backgroundColor = const Color(0xffFFFFFF);
|
||||
static Color buttonLoginBackgroundColor = const Color(0xffE61301);
|
||||
|
||||
static Color buttonRedBackgroundColor = const Color(0xffd90504);
|
||||
static Color textLoginColor = const Color(0xffFFFFFF);
|
||||
static Color shadowLoginMarketing = Colors.grey.withOpacity(0.3);
|
||||
static Color boxDecorationShadowLoginMaketing = Colors.blueGrey;
|
||||
static Color textRedProblemMaketing = const Color(0xffE61301);
|
||||
|
||||
// home
|
||||
static Color backgroundColorWelcome = const Color(0xffE61301);
|
||||
static Color textMonthToDate = const Color(0xff80848E);
|
||||
static Color textListStatusOrder = const Color(0xff070708);
|
||||
static Color confirmed = const Color(0xff0BAF48);
|
||||
static Color backgroundTotalOrderRight = const Color(0xffF6F5F5);
|
||||
static Color dividerHorizontal = const Color(0xffF4F6F8);
|
||||
static Color backgroundTopHome = const Color(0xffFEF0EB);
|
||||
|
||||
// order detail
|
||||
static Color textOrderDetail = const Color(0xff7E7F81);
|
||||
static Color cardConfirmed = const Color(0xffEBF9F0);
|
||||
static Color cardUnconfirmed = const Color(0xffFEF0EB);
|
||||
static Color textDropdown = const Color(0xff282828);
|
||||
|
||||
// pendaftaran Pasien
|
||||
static Color textCardPendaftaranPasien = const Color(0xff2E2D2D);
|
||||
// static Color cardColorPendaftaranPasien = const Color(0xffFDFDFD);
|
||||
static Color cardColorPendaftaranPasien = const Color(0xffF4F6F8);
|
||||
static Color floatingbg = const Color(0xffDC2626);
|
||||
|
||||
// pendaftaran pasien - demografi
|
||||
static Color backgroundCardNetral1_100 = const Color(0xffD1D2D6);
|
||||
static Color backgroundCardGreen_600 = const Color(0xff0BAF48);
|
||||
|
||||
// divider
|
||||
static Color dividerColor = Color(0xffD1D2D6);
|
||||
|
||||
// grey
|
||||
static Color greyColor = Color(0xff80848E);
|
||||
static Color chipText = Color(0xff637381);
|
||||
|
||||
// chip bg color
|
||||
static Color chipBg = Color(0xffEDEFF2);
|
||||
|
||||
// checkbox color
|
||||
static Color checkboxActive = Colors.red;
|
||||
static Color checkboxCheck = Colors.white;
|
||||
static Color checkboxSelected = Colors.red.shade100;
|
||||
|
||||
// icon file
|
||||
static Color fileColor = Color(0xFF087D33);
|
||||
|
||||
// fixing color
|
||||
static Color red_100 = Color(0xffFFB9B3);
|
||||
static Color red_200 = Color(0xffFE8A80);
|
||||
static Color red_300 = Color(0xffFE5B4D);
|
||||
static Color red_400 = Color(0xffFE2C1A);
|
||||
static Color red_500 = Color(0xffE61301);
|
||||
static Color red_600 = Color(0xffB20F01);
|
||||
static Color red_700 = Color(0xff7F0A01);
|
||||
static Color red_800 = Color(0xff4C0600);
|
||||
static Color red_900 = Color(0xff190200);
|
||||
|
||||
static Color green_100 = Color(0xffBCFBD3);
|
||||
static Color green_200 = Color(0xff8CF8B4);
|
||||
static Color green_300 = Color(0xff5CF595);
|
||||
static Color green_400 = Color(0xff2CF275);
|
||||
static Color green_500 = Color(0xff0EDD5B);
|
||||
static Color green_600 = Color(0xff0BAF48);
|
||||
static Color green_700 = Color(0xff087D33);
|
||||
static Color green_800 = Color(0xff054D20);
|
||||
static Color green_900 = Color(0xff021D0C);
|
||||
|
||||
static Color netral_100 = Color(0xffD1D2D6);
|
||||
static Color netral_200 = Color(0xffB6B8BE);
|
||||
static Color netral_300 = Color(0xff9B9EA6);
|
||||
static Color netral_400 = Color(0xff80848E);
|
||||
static Color netral_500 = Color(0xff676A74);
|
||||
static Color netral_600 = Color(0xff4F5259);
|
||||
static Color netral_700 = Color(0xff37393E);
|
||||
static Color netral_800 = Color(0xff1F2023);
|
||||
static Color netral_900 = Color(0xff070708);
|
||||
|
||||
static Color white = Color(0xffFDFDFD);
|
||||
|
||||
static Color textBlack = Color(0xff070708);
|
||||
static Color textRed = Color(0xffE61301);
|
||||
static Color textGrey = Color(0xff80848E);
|
||||
static Color textWhite = Color(0xffFDFDFD);
|
||||
static Color textGreen = Color(0xff0BAF48);
|
||||
|
||||
//typoGraphy
|
||||
static TextStyle titleH1Login({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH3_700({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH3_700V2({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 32),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH3_700GantiPassword({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH3_700SignOut({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 30),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH4Login({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
// homescreen
|
||||
static TextStyle titleLast30Days({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH4_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 20),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H4_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 20),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H4_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 20),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H4_700V2({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 28),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH5({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 18),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle caption1_400({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 11),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle caption3_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 9),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH2({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 32),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH1_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 36),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body3({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 12),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body1({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body1_400({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body1_400_dibulan({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body1_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body1_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body2_400({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH3({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH3_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H3_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H3_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H5_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 18),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body2({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body2_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body2_500_italic({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w400,
|
||||
fontStyle: FontStyle.italic);
|
||||
}
|
||||
|
||||
static TextStyle body1_700({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 16),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle H3_700({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body3_400({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 12),
|
||||
fontWeight: FontWeight.w400,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle body3_500({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 12),
|
||||
fontWeight: FontWeight.w500,
|
||||
);
|
||||
}
|
||||
|
||||
static TextStyle titleH7_700({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 12),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
// pendaftaran pasien
|
||||
static TextStyle titleH5_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 18),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
// demografi
|
||||
static TextStyle body2_600({required BuildContext context}) {
|
||||
return TextStyle(
|
||||
fontSize: Constant.getActualYPhone(context: context, y: 14),
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
}
|
||||
|
||||
//size convertion
|
||||
static double getActualX({
|
||||
required BuildContext context,
|
||||
required double x,
|
||||
}) {
|
||||
return x / designWidth * MediaQuery.of(context).size.width;
|
||||
}
|
||||
|
||||
static double getActualY({
|
||||
required BuildContext context,
|
||||
required double y,
|
||||
}) {
|
||||
return y / designHeight * MediaQuery.of(context).size.height;
|
||||
}
|
||||
|
||||
static double getActualXPhone({
|
||||
required BuildContext context,
|
||||
required double x,
|
||||
}) {
|
||||
return x / designWidthPhone * MediaQuery.of(context).size.width;
|
||||
}
|
||||
|
||||
static double getActualYPhone({
|
||||
required BuildContext context,
|
||||
required double y,
|
||||
}) {
|
||||
return y / designHeightPhone * MediaQuery.of(context).size.height;
|
||||
}
|
||||
}
|
||||
19
app_petty_cash/lib/app/route.dart
Normal file
19
app_petty_cash/lib/app/route.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../screen/login/login_screen.dart';
|
||||
|
||||
const loginRoute = "/loginRoute";
|
||||
const menuRoute = "/menuRoute";
|
||||
|
||||
class AppRoute {
|
||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||
// default
|
||||
return MaterialPageRoute(builder: (context) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context)
|
||||
.copyWith(textScaleFactor: 1.0, padding: const EdgeInsets.all(0)),
|
||||
child: const LoginScreen(),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
72
app_petty_cash/lib/model/auth_model.dart
Normal file
72
app_petty_cash/lib/model/auth_model.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
class AuthModel {
|
||||
final String token;
|
||||
final AuthDoctorModel model;
|
||||
|
||||
AuthModel({
|
||||
required this.token,
|
||||
required this.model,
|
||||
});
|
||||
}
|
||||
|
||||
class AuthDoctorModel {
|
||||
|
||||
// "M_UserID": "1",
|
||||
// "M_UserUsername": "alhadad",
|
||||
// "M_UserM_DoctorCode": "3101210841",
|
||||
// "M_UserM_DoctorID": "9562",
|
||||
// "M_UserM_StaffID": "376",
|
||||
// "ip": "139.194.156.91",
|
||||
// "agent": "PostmanRuntime/7.29.2"
|
||||
|
||||
late String doctorID;
|
||||
late String doctorName;
|
||||
|
||||
// new
|
||||
late String M_UserID;
|
||||
late String M_UserUsername;
|
||||
late String M_UserM_DoctorCode;
|
||||
late String M_UserM_DoctorID;
|
||||
late String M_UserM_StaffID;
|
||||
late String M_UserM_MouID;
|
||||
late String ip;
|
||||
late String agent;
|
||||
|
||||
AuthDoctorModel({
|
||||
// required this.doctorID,
|
||||
// required this.doctorName,
|
||||
|
||||
required this.M_UserID,
|
||||
required this.M_UserUsername,
|
||||
required this.M_UserM_DoctorCode,
|
||||
required this.M_UserM_DoctorID,
|
||||
this.M_UserM_StaffID = "",
|
||||
this.M_UserM_MouID = "",
|
||||
this.ip = "",
|
||||
this.agent = ""
|
||||
});
|
||||
|
||||
AuthDoctorModel.fromJson(Map<String, dynamic> json) {
|
||||
M_UserID = json['M_UserID'].toString();
|
||||
M_UserUsername = json['M_UserUsername'].toString();
|
||||
M_UserM_DoctorCode = json['M_UserM_DoctorCode'].toString();
|
||||
M_UserM_DoctorID = json['M_UserM_DoctorID'].toString();
|
||||
M_UserM_StaffID = json['M_UserM_StaffID'].toString();
|
||||
M_UserM_MouID = json['M_UserM_MouID'].toString();
|
||||
ip = json['ip'].toString();
|
||||
agent = json['agent'].toString();
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['M_UserID'] = M_UserID;
|
||||
data['M_UserUsername'] = M_UserUsername;
|
||||
data['M_UserM_DoctorCode'] = M_UserM_DoctorCode;
|
||||
data['M_UserM_DoctorID'] = M_UserM_DoctorID;
|
||||
data['M_UserM_StaffID'] = M_UserM_StaffID;
|
||||
data['M_UserM_MouID'] = M_UserM_MouID;
|
||||
data['ip'] = ip;
|
||||
data['agent'] = agent;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
3
app_petty_cash/lib/provider/current_menu_provider.dart
Normal file
3
app_petty_cash/lib/provider/current_menu_provider.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final currentPageProvider = StateProvider<int?>((ref) => null);
|
||||
4
app_petty_cash/lib/provider/current_user_provider.dart
Normal file
4
app_petty_cash/lib/provider/current_user_provider.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../model/auth_model.dart';
|
||||
|
||||
final currentUserProvider = StateProvider<AuthModel?>((ref) => null);
|
||||
4
app_petty_cash/lib/provider/dio_provider.dart
Normal file
4
app_petty_cash/lib/provider/dio_provider.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final dioProvider = Provider<Dio>((ref) => Dio());
|
||||
90
app_petty_cash/lib/repository/auth_repository.dart
Normal file
90
app_petty_cash/lib/repository/auth_repository.dart
Normal file
@@ -0,0 +1,90 @@
|
||||
import '../app/constant.dart';
|
||||
import '../model/auth_model.dart';
|
||||
import 'base_repository.dart';
|
||||
|
||||
class AuthRepository extends BaseRepository {
|
||||
AuthRepository({required super.dio});
|
||||
|
||||
Future<AuthModel> login({
|
||||
required String username,
|
||||
required String dokterId,
|
||||
required String password,
|
||||
}) async {
|
||||
final param = {
|
||||
"username": username,
|
||||
"doctor_id": dokterId,
|
||||
"password": password
|
||||
|
||||
// "username": "alhadad1",
|
||||
// "doctor_id": "2891",
|
||||
// "password": "3"
|
||||
};
|
||||
// final service = "${Constant.baseUrl}xauth/login";
|
||||
final service = "${Constant.baseUrl}auth/login";
|
||||
final resp = await post(param: param, service: service);
|
||||
final result = AuthModel(
|
||||
token: resp["data"]["token"],
|
||||
model: AuthDoctorModel.fromJson(resp["data"]["user"]),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<String> logout({
|
||||
required String M_UserID,
|
||||
required String M_UserUsername,
|
||||
}) async {
|
||||
final param = {
|
||||
"M_UserID": M_UserID,
|
||||
"M_UserUsername": M_UserUsername
|
||||
// "username": "alhadad",
|
||||
// "doctor_id": "3101210841",
|
||||
// "password": "riau123"
|
||||
};
|
||||
|
||||
final service = "${Constant.baseUrl}auth/logout";
|
||||
final resp = await post(param: param, service: service);
|
||||
|
||||
if (resp["status"] == "OK") {
|
||||
return resp['status'];
|
||||
} else {
|
||||
return resp['message'];
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> change_password({
|
||||
required String token,
|
||||
required String M_UserID,
|
||||
required String username,
|
||||
required String doctor_id,
|
||||
required String new_password,
|
||||
required String confirm_password,
|
||||
}) async {
|
||||
final param = {
|
||||
"token": token,
|
||||
"M_UserID": M_UserID,
|
||||
"username": username,
|
||||
"doctor_id": doctor_id,
|
||||
"new_password": new_password,
|
||||
"confirm_password": confirm_password
|
||||
|
||||
// "username": "alhadad",
|
||||
// "doctor_id": "3101210841",
|
||||
// "password": "riau123"
|
||||
};
|
||||
|
||||
final service = "${Constant.baseUrl}auth/change_password";
|
||||
final resp = await post(param: param, service: service);
|
||||
|
||||
// final result = AuthModel(
|
||||
// token: resp["data"]["token"],
|
||||
// model: AuthDoctorModel.fromJson(resp["data"]["user"]),
|
||||
// );
|
||||
// return result;
|
||||
|
||||
if (resp["status"] == "OK") {
|
||||
return resp['message'];
|
||||
} else {
|
||||
return resp['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
104
app_petty_cash/lib/repository/base_repository.dart
Normal file
104
app_petty_cash/lib/repository/base_repository.dart
Normal file
@@ -0,0 +1,104 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
abstract class BaseRepository {
|
||||
final Dio dio;
|
||||
BaseRepository({required this.dio});
|
||||
|
||||
Future<Map<String, dynamic>> post({
|
||||
required Map<String, dynamic> param,
|
||||
required String service,
|
||||
String? token,
|
||||
}) async {
|
||||
try {
|
||||
final response = await dio.post(
|
||||
// Constant.baseUrl + service,
|
||||
service,
|
||||
data: jsonEncode(param),
|
||||
options: Options(
|
||||
headers: token != null
|
||||
? {
|
||||
HttpHeaders.contentTypeHeader: "application/json",
|
||||
HttpHeaders.authorizationHeader: "Bearer $token",
|
||||
}
|
||||
: {
|
||||
HttpHeaders.contentTypeHeader: "application/json",
|
||||
},
|
||||
contentType: "application/json",
|
||||
),
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
throw BaseRepositoryException(
|
||||
message: "Invalid Http Response ${response.statusCode}",
|
||||
);
|
||||
}
|
||||
Map<String, dynamic> jsonData = jsonDecode(response.data);
|
||||
if (jsonData["status"] != "OK") {
|
||||
throw BaseRepositoryException(
|
||||
message: jsonData["message"],
|
||||
);
|
||||
} else {
|
||||
return jsonData;
|
||||
}
|
||||
} on DioError catch (e) {
|
||||
throw BaseRepositoryException(message: e.message);
|
||||
} on SocketException catch (e) {
|
||||
throw BaseRepositoryException(message: e.message);
|
||||
} on BaseRepositoryException catch (e) {
|
||||
throw BaseRepositoryException(message: e.message);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> get({
|
||||
// required Map<String, dynamic> param,
|
||||
required String service,
|
||||
String? token,
|
||||
}) async {
|
||||
try {
|
||||
final response = await dio.post(
|
||||
// Constant.baseUrl + service,
|
||||
service,
|
||||
// data: jsonEncode(param),
|
||||
options: Options(
|
||||
headers: token != null
|
||||
? {
|
||||
HttpHeaders.contentTypeHeader: "application/json",
|
||||
HttpHeaders.authorizationHeader: "Bearer $token",
|
||||
}
|
||||
: {
|
||||
HttpHeaders.contentTypeHeader: "application/json",
|
||||
},
|
||||
contentType: "application/json",
|
||||
),
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
throw BaseRepositoryException(
|
||||
message: "Invalid Http Response ${response.statusCode}",
|
||||
);
|
||||
}
|
||||
Map<String, dynamic> jsonData = jsonDecode(response.data);
|
||||
if (jsonData["status"] != "OK") {
|
||||
throw BaseRepositoryException(
|
||||
message: jsonData["message"],
|
||||
);
|
||||
} else {
|
||||
return jsonData;
|
||||
}
|
||||
} on DioError catch (e) {
|
||||
throw BaseRepositoryException(message: e.message);
|
||||
} on SocketException catch (e) {
|
||||
throw BaseRepositoryException(message: e.message);
|
||||
} on BaseRepositoryException catch (e) {
|
||||
throw BaseRepositoryException(message: e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BaseRepositoryException implements Exception {
|
||||
final String message;
|
||||
BaseRepositoryException({
|
||||
required this.message,
|
||||
});
|
||||
}
|
||||
278
app_petty_cash/lib/screen/login/block_body.dart
Normal file
278
app_petty_cash/lib/screen/login/block_body.dart
Normal file
@@ -0,0 +1,278 @@
|
||||
// ignore_for_file: prefer_const_constructors, use_full_hex_values_for_flutter_colors
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../app/route.dart';
|
||||
import '../../provider/current_menu_provider.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import 'custom_text_field.dart';
|
||||
import 'login_provider.dart';
|
||||
|
||||
class BlockBody extends HookConsumerWidget {
|
||||
const BlockBody({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isPasswordObscured = useState<bool>(true);
|
||||
final ctrlUsername = useTextEditingController(text: "");
|
||||
final ctrlDokterId = useTextEditingController(text: "");
|
||||
final ctrlPassword = useTextEditingController(text: "");
|
||||
final isLoading = useState(false);
|
||||
final errorMessage = useState("");
|
||||
final isSuccess = useState(false);
|
||||
|
||||
ref.listen(loginProvider, (prev, next) {
|
||||
if (next is LoginStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is LoginStateError) {
|
||||
isLoading.value = false;
|
||||
errorMessage.value = next.message;
|
||||
Timer(const Duration(seconds: 3), () {
|
||||
errorMessage.value = "";
|
||||
});
|
||||
} else if (next is LoginStateDone) {
|
||||
isLoading.value = false;
|
||||
isSuccess.value = true;
|
||||
ref.read(currentPageProvider.state).update((state) => 0);
|
||||
ref.read(currentUserProvider.notifier).state = next.model;
|
||||
|
||||
// print(next.model.model.doctorName);
|
||||
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pushNamedAndRemoveUntil(menuRoute,(route) => true,);
|
||||
// Navigator.popAndPushNamed(context,menuRoute);
|
||||
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(menuRoute, (route) => false);
|
||||
}
|
||||
});
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 390),
|
||||
height: Constant.getActualYPhone(context: context, y: 343),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('images/header_tanpa_logo.png'),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 136),
|
||||
),
|
||||
Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 148),
|
||||
height: Constant.getActualYPhone(context: context, y: 78),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.fitHeight,
|
||||
image: AssetImage('images/logo_pramita.png'),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 43),
|
||||
),
|
||||
Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 391),
|
||||
height: Constant.getActualYPhone(context: context, y: 454),
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(context: context, x: 32),
|
||||
right: Constant.getActualXPhone(context: context, x: 32),
|
||||
top: Constant.getActualYPhone(context: context, y: 20),
|
||||
bottom: Constant.getActualYPhone(context: context, y: 20),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// form
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 180),
|
||||
height: Constant.getActualYPhone(context: context, y: 29),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text("LOGIN DOKTER",
|
||||
style: Constant.titleH3_700(context: context)
|
||||
.copyWith(color: Constant.subTitleBlack)),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 4),
|
||||
),
|
||||
|
||||
// notify error dari backend start
|
||||
|
||||
if (isLoading.value)
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 20),
|
||||
height: Constant.getActualYPhone(context: context, y: 20),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
|
||||
if (errorMessage.value != "")
|
||||
Text(
|
||||
"Peringatan : ${errorMessage.value}",
|
||||
style: Constant.titleH7_700(context: context)
|
||||
.copyWith(color: Constant.textRedProblemMaketing),
|
||||
),
|
||||
|
||||
// notify error dari backend end
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 24),
|
||||
),
|
||||
// textfield marketing ID
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
child: CustomTextField(
|
||||
ctrl: ctrlDokterId,
|
||||
isPassword: false,
|
||||
hintText: "Doctor ID",
|
||||
labelText: "Doctor ID",
|
||||
isError: (errorMessage.value != "") ? true : false,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 20),
|
||||
),
|
||||
// textfield username
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
child: CustomTextField(
|
||||
ctrl: ctrlUsername,
|
||||
isPassword: false,
|
||||
hintText: "Username",
|
||||
labelText: "Username",
|
||||
isError: (errorMessage.value != "") ? true : false,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 20),
|
||||
),
|
||||
// textfield password
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
child: CustomTextField(
|
||||
ctrl: ctrlPassword,
|
||||
isPassword: false,
|
||||
obscureText: isPasswordObscured.value,
|
||||
hintText: "Password",
|
||||
labelText: "Password",
|
||||
onToggle: () {
|
||||
isPasswordObscured.value = !isPasswordObscured.value;
|
||||
},
|
||||
isError: (errorMessage.value != "") ? true : false,
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 40),
|
||||
),
|
||||
// button login
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
child: ElevatedButton(
|
||||
onPressed: (isSuccess.value == true)
|
||||
? () {}
|
||||
: () {
|
||||
if (ctrlUsername.text.isEmpty ||
|
||||
ctrlDokterId.text.isEmpty ||
|
||||
ctrlPassword.text.isEmpty) {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = 'Inputan harus diisi';
|
||||
Timer(const Duration(seconds: 3), () {
|
||||
isLoading.value = false;
|
||||
errorMessage.value = "";
|
||||
});
|
||||
} else {
|
||||
ref.read(loginProvider.notifier).login(
|
||||
username: ctrlUsername.text,
|
||||
dokterId: ctrlDokterId.text,
|
||||
password: ctrlPassword.text);
|
||||
}
|
||||
},
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateColor.resolveWith((st) =>
|
||||
(isSuccess.value == true)
|
||||
? Constant.textGrey
|
||||
: Constant.buttonLoginBackgroundColor),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
side: BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
shadowColor: MaterialStateProperty.all(Color(0xffff48423d)),
|
||||
elevation: MaterialStateProperty.all(4.0),
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'LOGIN',
|
||||
style: Constant.titleH3_700(context: context)
|
||||
.copyWith(color: Constant.textLoginColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 22),
|
||||
),
|
||||
|
||||
// versi
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Versi ${Constant.version}',
|
||||
style: Constant.titleH4Login(context: context)
|
||||
.copyWith(color: Constant.textGrey),
|
||||
),
|
||||
),
|
||||
|
||||
// text problem login
|
||||
|
||||
// SizedBox(
|
||||
// width: Constant.getActualXPhone(context: context, x: 121),
|
||||
// height: Constant.getActualYPhone(context: context, y: 20),
|
||||
// // color: Colors.brown,
|
||||
// child: Align(
|
||||
// alignment: Alignment.center,
|
||||
// child: InkWell(
|
||||
// onTap: () {
|
||||
// Navigator.of(context).pushNamed(problemLoginRoute);
|
||||
// },
|
||||
// child: Text(
|
||||
// 'Problem Login ? ',
|
||||
// style: Constant.body1_400(context: context)
|
||||
// .copyWith(color: Constant.textRedProblemMaketing),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
375
app_petty_cash/lib/screen/login/block_bodyv2.dart
Normal file
375
app_petty_cash/lib/screen/login/block_bodyv2.dart
Normal file
@@ -0,0 +1,375 @@
|
||||
// ignore_for_file: prefer_const_constructors, use_full_hex_values_for_flutter_colors
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../app/route.dart';
|
||||
import '../../provider/current_menu_provider.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import 'custom_text_field.dart';
|
||||
import 'login_provider.dart';
|
||||
|
||||
class BlockBodyV2 extends HookConsumerWidget {
|
||||
const BlockBodyV2({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isPasswordObscured = useState<bool>(true);
|
||||
final ctrlUsername = useTextEditingController(text: "");
|
||||
final ctrlDokterId = useTextEditingController(text: "");
|
||||
final ctrlPassword = useTextEditingController(text: "");
|
||||
final isLoading = useState(false);
|
||||
final errorMessage = useState("");
|
||||
final isSuccess = useState(false);
|
||||
final focusNodeDokterID = useFocusNode();
|
||||
final focusNodeDokterUsername = useFocusNode();
|
||||
final focusNodeDokterPassword = useFocusNode();
|
||||
|
||||
final dokterIDhasFocus = useState(false);
|
||||
final usernamehasFocus = useState(false);
|
||||
final passwordhasFocus = useState(false);
|
||||
|
||||
focusNodeDokterID.addListener(() {
|
||||
if (focusNodeDokterID.hasPrimaryFocus) {
|
||||
dokterIDhasFocus.value = true;
|
||||
usernamehasFocus.value = false;
|
||||
passwordhasFocus.value = false;
|
||||
} else {
|
||||
dokterIDhasFocus.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
focusNodeDokterUsername.addListener(() {
|
||||
if (focusNodeDokterUsername.hasFocus) {
|
||||
dokterIDhasFocus.value = false;
|
||||
usernamehasFocus.value = true;
|
||||
passwordhasFocus.value = false;
|
||||
} else {
|
||||
usernamehasFocus.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
focusNodeDokterPassword.addListener(() {
|
||||
if (focusNodeDokterPassword.hasFocus) {
|
||||
dokterIDhasFocus.value = false;
|
||||
usernamehasFocus.value = false;
|
||||
passwordhasFocus.value = true;
|
||||
} else {
|
||||
passwordhasFocus.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
ref.listen(loginProvider, (prev, next) {
|
||||
if (next is LoginStateLoading) {
|
||||
isLoading.value = true;
|
||||
} else if (next is LoginStateError) {
|
||||
isLoading.value = false;
|
||||
errorMessage.value = next.message;
|
||||
Timer(const Duration(seconds: 3), () {
|
||||
errorMessage.value = "";
|
||||
});
|
||||
} else if (next is LoginStateDone) {
|
||||
isLoading.value = false;
|
||||
isSuccess.value = true;
|
||||
ref.read(currentPageProvider.state).update((state) => 0);
|
||||
ref.read(currentUserProvider.notifier).state = next.model;
|
||||
|
||||
// print(next.model.model.doctorName);
|
||||
|
||||
// Navigator.of(context).pop();
|
||||
// Navigator.of(context).pushNamedAndRemoveUntil(menuRoute,(route) => true,);
|
||||
// Navigator.popAndPushNamed(context,menuRoute);
|
||||
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil(menuRoute, (route) => false);
|
||||
}
|
||||
});
|
||||
|
||||
return ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 30),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(context: context, x: 40),
|
||||
right: Constant.getActualXPhone(context: context, x: 40),
|
||||
),
|
||||
child: Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 283),
|
||||
height: Constant.getActualYPhone(context: context, y: 100),
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.green,
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.fitWidth,
|
||||
// image: AssetImage('images/logo_pramita.png'),
|
||||
image: AssetImage('images/logo_gabung_bg_png.png'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 60),
|
||||
),
|
||||
// form
|
||||
Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 180),
|
||||
height: Constant.getActualYPhone(context: context, y: 40),
|
||||
// color: Colors.amber,
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Text(
|
||||
"LOGIN",
|
||||
style: Constant.titleH3_700V2(context: context)
|
||||
.copyWith(color: Constant.subTitleBlack),
|
||||
),
|
||||
Text(
|
||||
" DOKTER",
|
||||
style: Constant.titleH3_700V2(context: context).copyWith(
|
||||
color: Color(0xffd70302),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 20),
|
||||
),
|
||||
|
||||
// notify error dari backend start
|
||||
|
||||
if (isLoading.value)
|
||||
SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 20),
|
||||
height: Constant.getActualYPhone(context: context, y: 20),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
|
||||
if (errorMessage.value != "")
|
||||
Center(
|
||||
child: Text(
|
||||
"Peringatan : ${errorMessage.value}",
|
||||
style: Constant.titleH7_700(context: context)
|
||||
.copyWith(color: Constant.textRedProblemMaketing),
|
||||
),
|
||||
),
|
||||
|
||||
// notify error dari backend end
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
),
|
||||
// textfield marketing ID
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(context: context, x: 100),
|
||||
right: Constant.getActualXPhone(context: context, x: 100),
|
||||
),
|
||||
child: Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
// color: Colors.blue,
|
||||
// decoration: BoxDecoration(
|
||||
// // border: Border.all(color: Colors.black),
|
||||
// color: Color(0xffee0606),
|
||||
// borderRadius: BorderRadius.circular(30),
|
||||
// ),
|
||||
child: CustomTextFieldLogin(
|
||||
// onTap: () {
|
||||
// dokterIDhasFocus.value = true;
|
||||
// },
|
||||
// onEditingComplete: () {
|
||||
// dokterIDhasFocus.value = false;
|
||||
// },
|
||||
onChange: (String x) {
|
||||
// print(x);
|
||||
if (x.isNotEmpty || ctrlDokterId.text.isNotEmpty) {
|
||||
print('onchange');
|
||||
focusNodeDokterID.requestFocus();
|
||||
}
|
||||
},
|
||||
ctrl: ctrlDokterId,
|
||||
focusNode: focusNodeDokterID,
|
||||
hasFocus: dokterIDhasFocus.value,
|
||||
isPassword: false,
|
||||
hintText: "DOKTER ID",
|
||||
labelText: "DOKTER ID",
|
||||
isError: (errorMessage.value != "") ? true : false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 40),
|
||||
),
|
||||
// textfield username
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(context: context, x: 100),
|
||||
right: Constant.getActualXPhone(context: context, x: 100),
|
||||
),
|
||||
child: Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
// color: Colors.blue,
|
||||
// decoration: BoxDecoration(
|
||||
// // border: Border.all(color: Colors.black),
|
||||
// color: Color(0xffee0606),
|
||||
// borderRadius: BorderRadius.circular(30),
|
||||
// ),
|
||||
child: CustomTextFieldLogin(
|
||||
// onTap: () {
|
||||
// if (ctrlUsername.text.isNotEmpty) {
|
||||
// focusNodeDokterUsername.requestFocus();
|
||||
// }
|
||||
// },
|
||||
onChange: (String x) {
|
||||
// print(x);
|
||||
if (x.isNotEmpty || ctrlUsername.text.isNotEmpty) {
|
||||
focusNodeDokterUsername.requestFocus();
|
||||
}
|
||||
},
|
||||
ctrl: ctrlUsername,
|
||||
focusNode: focusNodeDokterUsername,
|
||||
hasFocus: usernamehasFocus.value,
|
||||
isPassword: false,
|
||||
hintText: "USERNAME",
|
||||
labelText: "USERNAME",
|
||||
isError: (errorMessage.value != "") ? true : false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 40),
|
||||
),
|
||||
// textfield password
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(context: context, x: 100),
|
||||
right: Constant.getActualXPhone(context: context, x: 100),
|
||||
),
|
||||
child: Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
// color: Colors.blue,
|
||||
// decoration: BoxDecoration(
|
||||
// // border: Border.all(color: Colors.black),
|
||||
// color: Color(0xffee0606),
|
||||
// borderRadius: BorderRadius.circular(30),
|
||||
// ),
|
||||
child: CustomTextFieldLogin(
|
||||
// onTap: () {
|
||||
// if (ctrlPassword.text.isNotEmpty) {
|
||||
// focusNodeDokterPassword.requestFocus();
|
||||
// }
|
||||
// },
|
||||
onChange: (String x) {
|
||||
// print(x);
|
||||
if (x.isNotEmpty || ctrlPassword.text.isNotEmpty) {
|
||||
focusNodeDokterPassword.requestFocus();
|
||||
}
|
||||
},
|
||||
ctrl: ctrlPassword,
|
||||
focusNode: focusNodeDokterPassword,
|
||||
hasFocus: passwordhasFocus.value,
|
||||
isPassword: false,
|
||||
obscureText: isPasswordObscured.value,
|
||||
hintText: "PASSWORD",
|
||||
labelText: "PASSWORD",
|
||||
onToggle: () {
|
||||
isPasswordObscured.value = !isPasswordObscured.value;
|
||||
},
|
||||
isError: (errorMessage.value != "") ? true : false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 40),
|
||||
),
|
||||
// button login
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: Constant.getActualXPhone(context: context, x: 100),
|
||||
right: Constant.getActualXPhone(context: context, x: 100),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: Constant.getActualXPhone(context: context, x: 320),
|
||||
height: Constant.getActualYPhone(context: context, y: 50),
|
||||
child: ElevatedButton(
|
||||
onPressed: (isSuccess.value == true)
|
||||
? () {}
|
||||
: () {
|
||||
if (ctrlUsername.text.isEmpty ||
|
||||
ctrlDokterId.text.isEmpty ||
|
||||
ctrlPassword.text.isEmpty) {
|
||||
isLoading.value = true;
|
||||
errorMessage.value = 'Inputan harus diisi';
|
||||
Timer(const Duration(seconds: 3), () {
|
||||
isLoading.value = false;
|
||||
errorMessage.value = "";
|
||||
});
|
||||
} else {
|
||||
ref.read(loginProvider.notifier).login(
|
||||
username: ctrlUsername.text,
|
||||
dokterId: ctrlDokterId.text,
|
||||
password: ctrlPassword.text);
|
||||
}
|
||||
},
|
||||
style: ButtonStyle(
|
||||
backgroundColor: MaterialStateColor.resolveWith((st) =>
|
||||
(isSuccess.value == true)
|
||||
? Constant.textGrey
|
||||
: Constant.buttonRedBackgroundColor),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
side: BorderSide(color: Colors.red),
|
||||
),
|
||||
),
|
||||
shadowColor: MaterialStateProperty.all(Color(0xffff48423d)),
|
||||
elevation: MaterialStateProperty.all(4.0),
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'SIGN IN',
|
||||
style: Constant.titleH3_700(context: context)
|
||||
.copyWith(color: Constant.textLoginColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(context: context, y: 22),
|
||||
),
|
||||
|
||||
// versi
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
'Versi ${Constant.version}',
|
||||
style: Constant.titleH4Login(context: context)
|
||||
.copyWith(color: Constant.textGrey),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
19
app_petty_cash/lib/screen/login/block_header.dart
Normal file
19
app_petty_cash/lib/screen/login/block_header.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
|
||||
class BlokHeader extends StatelessWidget {
|
||||
const BlokHeader({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Image.asset(
|
||||
'images/Background.png',
|
||||
fit: BoxFit.fill,
|
||||
width: Constant.getActualXPhone(context: context, x: 390),
|
||||
height: double.infinity,
|
||||
);
|
||||
}
|
||||
}
|
||||
290
app_petty_cash/lib/screen/login/custom_text_field.dart
Normal file
290
app_petty_cash/lib/screen/login/custom_text_field.dart
Normal file
@@ -0,0 +1,290 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
|
||||
// login
|
||||
class CustomTextFieldLogin extends StatelessWidget {
|
||||
final String hintText;
|
||||
final String labelText;
|
||||
final bool isPassword;
|
||||
final bool obscureText;
|
||||
final bool isMaxLine;
|
||||
final void Function()? onToggle;
|
||||
final TextEditingController? ctrl;
|
||||
final void Function(String)? onChange;
|
||||
final void Function(String)? onSubmitted;
|
||||
final void Function()? onTap;
|
||||
final void Function()? onEditingComplete;
|
||||
final FocusNode? focusNode;
|
||||
final bool isPrefix;
|
||||
|
||||
final bool isError;
|
||||
final bool isTextArea;
|
||||
final bool isReadOnly;
|
||||
|
||||
final bool hasFocus;
|
||||
|
||||
const CustomTextFieldLogin({
|
||||
Key? key,
|
||||
required this.hintText,
|
||||
required this.labelText,
|
||||
this.isPassword = false,
|
||||
this.isMaxLine = false,
|
||||
this.onToggle,
|
||||
this.obscureText = false,
|
||||
this.ctrl,
|
||||
this.onChange,
|
||||
this.onSubmitted,
|
||||
this.focusNode,
|
||||
this.isPrefix = false,
|
||||
this.isTextArea = false,
|
||||
this.isError = false,
|
||||
this.isReadOnly = false,
|
||||
this.hasFocus = false,
|
||||
this.onTap,
|
||||
this.onEditingComplete
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
autofocus: true,
|
||||
showCursor: (hasFocus) ? true : false,
|
||||
readOnly: isReadOnly,
|
||||
controller: ctrl,
|
||||
enableInteractiveSelection: false,
|
||||
style:
|
||||
Constant.titleH4Login(context: context).copyWith(color: Colors.white),
|
||||
obscureText: obscureText,
|
||||
onChanged: onChange,
|
||||
onSubmitted: onSubmitted,
|
||||
onTap: onTap,
|
||||
onEditingComplete: onEditingComplete,
|
||||
focusNode: focusNode,
|
||||
maxLines: (isTextArea) ? 4 : 1,
|
||||
cursorColor: Colors.white,
|
||||
decoration: InputDecoration(
|
||||
fillColor: (hasFocus) ? Color(0xffff6868) : Color(0xffd90504),
|
||||
filled: true,
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Constant.buttonLoginBackgroundColor, width: 2),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
enabledBorder: (isError == true)
|
||||
? OutlineInputBorder(
|
||||
// ignore: prefer_const_constructors
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
borderSide: BorderSide(
|
||||
color: Constant.textRedProblemMaketing,
|
||||
width: 1,
|
||||
),
|
||||
)
|
||||
: OutlineInputBorder(
|
||||
// ignore: prefer_const_constructors
|
||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||
borderSide: BorderSide(
|
||||
color: Constant.buttonLoginBackgroundColor,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
// hintStyle: Constant.body1_400(context: context)
|
||||
// .copyWith(color: Constant.textBlack),
|
||||
// labelStyle: Constant.body3_400(context: context),
|
||||
hintStyle:
|
||||
Constant.body3_400(context: context).copyWith(color: Colors.white),
|
||||
labelStyle: Constant.body3_400(context: context),
|
||||
// labelText: labelText,
|
||||
hintText: hintText,
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
prefixIcon: isPrefix ? const Icon(Icons.search) : null,
|
||||
prefixStyle: isPrefix ? Constant.titleH4Login(context: context) : null,
|
||||
// suffixIcon: isPassword
|
||||
// ? IconButton(
|
||||
// alignment: Alignment.centerRight,
|
||||
// onPressed: onToggle,
|
||||
// icon: const Icon(Icons.remove_red_eye),
|
||||
// iconSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
// )
|
||||
// : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// selain login
|
||||
class CustomTextField extends StatelessWidget {
|
||||
final String hintText;
|
||||
final String labelText;
|
||||
final bool isPassword;
|
||||
final bool obscureText;
|
||||
final bool isMaxLine;
|
||||
final void Function()? onToggle;
|
||||
final TextEditingController? ctrl;
|
||||
final void Function(String)? onChange;
|
||||
final void Function(String)? onSubmitted;
|
||||
final FocusNode? focusNode;
|
||||
final bool isPrefix;
|
||||
|
||||
final bool isError;
|
||||
final bool isTextArea;
|
||||
final bool isReadOnly;
|
||||
|
||||
const CustomTextField(
|
||||
{Key? key,
|
||||
required this.hintText,
|
||||
required this.labelText,
|
||||
this.isPassword = false,
|
||||
this.isMaxLine = false,
|
||||
this.onToggle,
|
||||
this.obscureText = false,
|
||||
this.ctrl,
|
||||
this.onChange,
|
||||
this.onSubmitted,
|
||||
this.focusNode,
|
||||
this.isPrefix = false,
|
||||
this.isTextArea = false,
|
||||
this.isError = false,
|
||||
this.isReadOnly = false})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
readOnly: isReadOnly,
|
||||
controller: ctrl,
|
||||
style: Constant.titleH4Login(context: context),
|
||||
obscureText: obscureText,
|
||||
onChanged: onChange,
|
||||
onSubmitted: onSubmitted,
|
||||
focusNode: focusNode,
|
||||
maxLines: (isTextArea) ? 4 : 1,
|
||||
decoration: InputDecoration(
|
||||
// focusedBorder: OutlineInputBorder(
|
||||
// borderSide: BorderSide(color: Constant.textGrey, width: 1),
|
||||
// borderRadius: BorderRadius.circular(8.0),
|
||||
// ),
|
||||
enabledBorder: (isError == true)
|
||||
? OutlineInputBorder(
|
||||
// ignore: prefer_const_constructors
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
borderSide: BorderSide(
|
||||
color: Constant.textRedProblemMaketing,
|
||||
width: 1,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
// hintStyle: Constant.body1_400(context: context)
|
||||
// .copyWith(color: Constant.textBlack),
|
||||
// labelStyle: Constant.body3_400(context: context),
|
||||
hintStyle: Constant.body3_400(context: context),
|
||||
labelStyle: Constant.body3_400(context: context),
|
||||
labelText: labelText,
|
||||
hintText: hintText,
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
prefixIcon: isPrefix ? const Icon(Icons.search) : null,
|
||||
prefixStyle: isPrefix ? Constant.titleH4Login(context: context) : null,
|
||||
// suffixIcon: isPassword
|
||||
// ? IconButton(
|
||||
// alignment: Alignment.centerRight,
|
||||
// onPressed: onToggle,
|
||||
// icon: const Icon(Icons.remove_red_eye),
|
||||
// iconSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
// )
|
||||
// : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// untuk inputan selain login
|
||||
class CustomTextFieldV2 extends StatelessWidget {
|
||||
final String hintText;
|
||||
final String labelText;
|
||||
final bool isPassword;
|
||||
final bool obscureText;
|
||||
final bool isMaxLine;
|
||||
final void Function()? onToggle;
|
||||
final TextEditingController? ctrl;
|
||||
final void Function(String)? onChange;
|
||||
final void Function(String)? onSubmitted;
|
||||
final FocusNode? focusNode;
|
||||
final bool isPrefix;
|
||||
final InkWell? suffixIcon;
|
||||
|
||||
final bool isError;
|
||||
final bool isTextArea;
|
||||
|
||||
const CustomTextFieldV2(
|
||||
{Key? key,
|
||||
required this.hintText,
|
||||
required this.labelText,
|
||||
this.isPassword = false,
|
||||
this.isMaxLine = false,
|
||||
this.onToggle,
|
||||
this.obscureText = false,
|
||||
this.ctrl,
|
||||
this.onChange,
|
||||
this.onSubmitted,
|
||||
this.focusNode,
|
||||
this.isPrefix = false,
|
||||
this.isTextArea = false,
|
||||
this.isError = false,
|
||||
this.suffixIcon})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
controller: ctrl,
|
||||
style: Constant.titleH4Login(context: context),
|
||||
obscureText: obscureText,
|
||||
onChanged: onChange,
|
||||
onSubmitted: onSubmitted,
|
||||
focusNode: focusNode,
|
||||
maxLines: (isTextArea) ? 4 : 1,
|
||||
decoration: InputDecoration(
|
||||
// focusedBorder: OutlineInputBorder(
|
||||
// borderSide: BorderSide(color: Constant.textGrey, width: 1),
|
||||
// borderRadius: BorderRadius.circular(8.0),
|
||||
// ),
|
||||
enabledBorder: (isError == true)
|
||||
? OutlineInputBorder(
|
||||
// ignore: prefer_const_constructors
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
borderSide: BorderSide(
|
||||
color: Constant.textRedProblemMaketing,
|
||||
width: 1,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
hintStyle: Constant.body3_400(context: context),
|
||||
labelStyle: Constant.body3_400(context: context),
|
||||
labelText: labelText,
|
||||
hintText: hintText,
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
prefixIcon: isPrefix ? const Icon(Icons.search) : null,
|
||||
prefixStyle:
|
||||
isPrefix ? Constant.titleH4Login(context: context) : null,
|
||||
suffixIcon: suffixIcon
|
||||
// suffixIcon: isPassword
|
||||
// ? IconButton(
|
||||
// alignment: Alignment.centerRight,
|
||||
// onPressed: onToggle,
|
||||
// icon: const Icon(Icons.remove_red_eye),
|
||||
// iconSize: Constant.getActualYPhone(context: context, y: 24),
|
||||
// )
|
||||
// : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
83
app_petty_cash/lib/screen/login/login_provider.dart
Normal file
83
app_petty_cash/lib/screen/login/login_provider.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../model/auth_model.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import '../../provider/dio_provider.dart';
|
||||
import '../../repository/auth_repository.dart';
|
||||
import '../../repository/base_repository.dart';
|
||||
|
||||
// 3. state provider
|
||||
final loginProvider = StateNotifierProvider<LoginNotifier, LoginState>(
|
||||
(ref) => LoginNotifier(ref: ref));
|
||||
|
||||
// 2. notifier
|
||||
class LoginNotifier extends StateNotifier<LoginState> {
|
||||
final Ref ref;
|
||||
LoginNotifier({required this.ref}) : super(LoginStateInit());
|
||||
void login({
|
||||
required String username,
|
||||
required String dokterId,
|
||||
required String password,
|
||||
}) async {
|
||||
try {
|
||||
state = LoginStateLoading();
|
||||
final resp = await AuthRepository(dio: ref.read(dioProvider))
|
||||
.login(username: username, dokterId: dokterId, password: password);
|
||||
|
||||
// print(resp);
|
||||
state = LoginStateDone(model: resp);
|
||||
//Simpan ke token
|
||||
final shared = await SharedPreferences.getInstance();
|
||||
final token = jsonEncode({
|
||||
"date": DateTime.now().toString(),
|
||||
"model": resp.model,
|
||||
"token": resp.token
|
||||
});
|
||||
await shared.setString(Constant.bearerName, token);
|
||||
ref.read(currentUserProvider.notifier).state = resp;
|
||||
|
||||
// print(shared.getString(Constant.bearerName));
|
||||
} catch (e) {
|
||||
if (e is BaseRepositoryException) {
|
||||
state = LoginStateError(message: e.message);
|
||||
} else {
|
||||
state = LoginStateError(message: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. state
|
||||
abstract class LoginState extends Equatable {
|
||||
final DateTime date;
|
||||
const LoginState(this.date);
|
||||
@override
|
||||
List<Object?> get props => [date];
|
||||
}
|
||||
|
||||
class LoginStateInit extends LoginState {
|
||||
LoginStateInit() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class LoginStateLoading extends LoginState {
|
||||
LoginStateLoading() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class LoginStateError extends LoginState {
|
||||
final String message;
|
||||
LoginStateError({
|
||||
required this.message,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
|
||||
class LoginStateDone extends LoginState {
|
||||
final AuthModel model;
|
||||
LoginStateDone({
|
||||
required this.model,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
79
app_petty_cash/lib/screen/login/login_screen.dart
Normal file
79
app_petty_cash/lib/screen/login/login_screen.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
// ignore_for_file: use_build_context_synchronously, prefer_const_constructors
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../app/route.dart';
|
||||
import '../../model/auth_model.dart';
|
||||
import '../../provider/current_menu_provider.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
import 'block_body.dart';
|
||||
import 'block_bodyv2.dart';
|
||||
|
||||
class LoginScreen extends HookConsumerWidget {
|
||||
const LoginScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
useEffect(() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
final shared = await SharedPreferences.getInstance();
|
||||
final bearerString = shared.get(Constant.bearerName).toString();
|
||||
final xmodel = jsonDecode(bearerString);
|
||||
if (xmodel == null) return;
|
||||
final authModel = AuthModel(
|
||||
token: xmodel["token"],
|
||||
model: AuthDoctorModel(
|
||||
M_UserM_DoctorID: xmodel["model"]["M_UserM_DoctorID"],
|
||||
M_UserUsername: xmodel["model"]["M_UserUsername"],
|
||||
M_UserM_DoctorCode: xmodel["model"]["M_UserM_DoctorCode"],
|
||||
M_UserM_MouID: xmodel["model"]["M_UserM_MouID"] ?? "",
|
||||
M_UserID: xmodel["model"]["M_UserID"]),
|
||||
);
|
||||
ref.read(currentUserProvider.notifier).state = authModel;
|
||||
|
||||
ref.read(currentPageProvider.state).update((state) => 0);
|
||||
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
menuRoute,
|
||||
(route) => false,
|
||||
);
|
||||
});
|
||||
return () {};
|
||||
}, []);
|
||||
|
||||
return GestureDetector(
|
||||
// buat dismiss keyboard
|
||||
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
backgroundColor: Constant.backgroundColor,
|
||||
body: SafeArea(
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 390),
|
||||
height: Constant.getActualYPhone(context: context, y: 844),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Color(0xffdadae6),
|
||||
Color(0xfff6f7fb),
|
||||
],
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
),
|
||||
),
|
||||
// child: BlockBody(),
|
||||
child: BlockBodyV2(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
64
app_petty_cash/lib/screen/splash/splash_screen.dart
Normal file
64
app_petty_cash/lib/screen/splash/splash_screen.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import '../../app/constant.dart';
|
||||
import '../../app/route.dart';
|
||||
import '../../provider/current_user_provider.dart';
|
||||
|
||||
class SplashScreen extends HookConsumerWidget {
|
||||
const SplashScreen({super.key});
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// useEffect(() {
|
||||
// WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
// final doctorID =
|
||||
// ref.read(currentUserProvider)?.model.M_UserM_DoctorCode ?? "0";
|
||||
// // print(doctorID);
|
||||
|
||||
// if (doctorID == "0") {
|
||||
// //not login
|
||||
|
||||
// Navigator.of(context)
|
||||
// .pushNamedAndRemoveUntil(loginRoute, (route) => false);
|
||||
// return;
|
||||
|
||||
// } else {
|
||||
// Navigator.of(context)
|
||||
// .pushNamedAndRemoveUntil(menuRoute, (route) => false);
|
||||
// }
|
||||
// });
|
||||
// return () {};
|
||||
// }, []);
|
||||
|
||||
// setelah 3 detik redirect ke login route
|
||||
Timer(const Duration(seconds: 3), () {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
loginRoute,
|
||||
(route) => false,
|
||||
);
|
||||
});
|
||||
|
||||
return Scaffold(
|
||||
// appBar: AppBar(
|
||||
// backgroundColor: Constant.backgroundColor,
|
||||
// elevation: 0,
|
||||
// ),
|
||||
backgroundColor: Constant.backgroundColor,
|
||||
body: SafeArea(
|
||||
child: Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 390),
|
||||
height: Constant.getActualYPhone(context: context, y: 844),
|
||||
child: Image.asset(
|
||||
"images/splashscreen.png",
|
||||
fit: BoxFit.cover,
|
||||
// scale: 1,
|
||||
),
|
||||
// color: Colors.green,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user