Commit abd9f02e authored by DatHV's avatar DatHV
Browse files

update screen

parent e41fc4fe
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4097 11.9991L17.7061 7.71268C17.8943 7.52453 18 7.26935 18 7.00326C18 6.73718 17.8943 6.482 17.7061 6.29385C17.518 6.1057 17.2628 6 16.9967 6C16.7307 6 16.4755 6.1057 16.2873 6.29385L12.0009 10.5903L7.71439 6.29385C7.52624 6.1057 7.27105 6 7.00497 6C6.73889 6 6.4837 6.1057 6.29555 6.29385C6.10741 6.482 6.00171 6.73718 6.00171 7.00326C6.00171 7.26935 6.10741 7.52453 6.29555 7.71268L10.592 11.9991L6.29555 16.2856C6.2019 16.3785 6.12757 16.489 6.07684 16.6108C6.02612 16.7325 6 16.8631 6 16.995C6 17.1269 6.02612 17.2575 6.07684 17.3793C6.12757 17.501 6.2019 17.6116 6.29555 17.7044C6.38844 17.7981 6.49895 17.8724 6.62071 17.9232C6.74247 17.9739 6.87307 18 7.00497 18C7.13687 18 7.26747 17.9739 7.38923 17.9232C7.51099 17.8724 7.6215 17.7981 7.71439 17.7044L12.0009 13.408L16.2873 17.7044C16.3802 17.7981 16.4907 17.8724 16.6125 17.9232C16.7342 17.9739 16.8648 18 16.9967 18C17.1286 18 17.2592 17.9739 17.381 17.9232C17.5028 17.8724 17.6133 17.7981 17.7061 17.7044C17.7998 17.6116 17.8741 17.501 17.9249 17.3793C17.9756 17.2575 18.0017 17.1269 18.0017 16.995C18.0017 16.8631 17.9756 16.7325 17.9249 16.6108C17.8741 16.489 17.7998 16.3785 17.7061 16.2856L13.4097 11.9991Z" fill="#43494D"/>
</svg>
<svg width="138" height="138" viewBox="0 0 138 138" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="138" height="138" rx="10" fill="#D42230"/>
<path d="M102.755 0.446289V42.2101C102.755 57.5434 90.3969 70.041 75.2347 70.041H61.4571C46.2948 70.041 33.9365 57.5434 33.9365 42.2101V0.446289H47.7141V42.2101C47.7141 49.8767 53.8759 56.1431 61.4571 56.1431H75.2347C82.8158 56.1431 89.0123 49.9117 89.0123 42.2101V0.446289H102.755Z" fill="white"/>
<path d="M102.751 83.9731C102.751 101.232 88.8694 115.27 71.7685 115.27H64.8797C47.8135 115.27 33.8975 101.232 33.8975 83.9731H47.675C47.675 93.5651 55.3947 101.372 64.8797 101.372H71.7685C81.2536 101.372 88.9732 93.5651 88.9732 83.9731H102.751Z" fill="white"/>
</svg>
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -7,6 +7,8 @@ class BaseResponseModel<T> {
final String? status;
@JsonKey(name: "error_message")
final String? errorMessage;
@JsonKey(name: "error_code")
final String? errorCode;
final String? message;
final T? data;
......@@ -16,7 +18,7 @@ class BaseResponseModel<T> {
return status == "success";
}
const BaseResponseModel({this.code, this.status, this.errorMessage, this.message, this.data});
const BaseResponseModel({this.code, this.status, this.errorMessage, this.errorCode, this.message, this.data});
factory BaseResponseModel.fromJson(Map<String, dynamic> json, T Function(Object? json) fromJsonT) {
return _$BaseResponseModelFromJson<T>(json, fromJsonT);
......
......@@ -13,6 +13,7 @@ BaseResponseModel<T> _$BaseResponseModelFromJson<T>(
code: (json['code'] as num?)?.toInt(),
status: json['status'] as String?,
errorMessage: json['error_message'] as String?,
errorCode: json['error_code'] as String?,
message: json['message'] as String?,
data: _$nullableGenericFromJson(json['data'], fromJsonT),
);
......@@ -24,6 +25,7 @@ Map<String, dynamic> _$BaseResponseModelToJson<T>(
'code': instance.code,
'status': instance.status,
'error_message': instance.errorMessage,
'error_code': instance.errorCode,
'message': instance.message,
'data': _$nullableGenericToJson(instance.data, toJsonT),
};
......
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/context_extensions.dart';
import 'package:mypoint_flutter_app/widgets/alert/src/alert.dart';
import '../configs/callbacks.dart';
import '../resouce/base_color.dart';
import '../resouce/define_image.dart';
import '../resouce/text_style.dart';
import '../widgets/alert/custom_alert_dialog.dart';
import '../widgets/alert/data_alert_model.dart';
import '../widgets/alert/src/dialog_button.dart';
abstract class BaseScreen extends StatefulWidget {
const BaseScreen({super.key});
}
abstract class BaseState<Screen extends BaseScreen> extends State<Screen> {
var isShowLoading = false;
@override
void initState() {
super.initState();
if (kDebugMode) {
print("_show: $runtimeType");
}
}
AppBar headerView(
{required String title,
Color backgroundColor = Colors.white,
Color iconColor = Colors.white,
Color textColor = BaseColor.second900,
List<Widget>? actions,
Widget? leading,
TabBar? tabBar,
double elevation = 0.5,
bool isShowBack = true}) {
return AppBar(
iconTheme: IconThemeData(
color: iconColor, //change your color here
),
elevation: elevation,
bottom: tabBar,
backgroundColor: backgroundColor,
centerTitle: true,
automaticallyImplyLeading: isShowBack,
actions: actions,
leading: leading,
title: Text(
title.tr,
textAlign: TextAlign.center,
style: textSemiBold.copyWith(fontSize: 18, color: textColor),
),
);
}
double heightBottomSafa() {
return MediaQuery.of(context).padding.bottom;
}
FToast fToast = FToast();
showMessage(BuildContext context, String message) {
fToast.init(context);
Widget toast = Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: BaseColor.second400,
),
child: Row(mainAxisSize: MainAxisSize.min, children: [
SvgPicture.asset(icLogo, width: 16, height: 16),
const SizedBox(width: 12),
Flexible(
child: Text(message,
style:
textNormal.copyWith(fontSize: 16, color: Colors.white)))
]));
fToast.showToast(
child: toast,
gravity: ToastGravity.BOTTOM,
toastDuration: const Duration(seconds: 2),
);
}
showAlertDialog(BuildContext context, String message,
{Callback<bool>? callback}) {
context.showAlertDialog(message, callback: callback);
}
showConfirmAlertDialog(BuildContext context, String message,
{String cancel = "Huỷ",
String confirm = "Xác nhận",
Callback<bool>? callback}) {
context.showConfirmAlertDialog(message, cancel: cancel, confirm: confirm, callback: callback);
}
showAlertError(String content) {
Get.dialog(
CustomAlertDialog(
alertData: DataAlertModel(
background: "assets/images/bg_alert_header.png",
title: "",
content: content,
buttons: [
AlertButton(
text: "Đã Hiểu",
onPressed: () {
Get.back();
},
bgColor: BaseColor.primary500,
textColor: Colors.white,
isPrimary: true,
),
],
),
),
);
}
hideKeyboard() {
FocusScope.of(context).unfocus();
}
void printDebug(dynamic data) {
if (kDebugMode) {
print(data);
}
}
Widget? createBottomBar() {
return null;
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'base_screen.dart';
mixin BasicState<Screen extends BaseScreen> on BaseState<Screen> {
final GlobalKey<ScaffoldState> _scaffoldStateKey =
GlobalKey(debugLabel: "BasicState");
@override
Widget build(BuildContext context) {
var appBar = createAppBar();
if (numberTabController > 0) {
return DefaultTabController(
length: numberTabController,
child: WillPopScope(
child: Scaffold(
backgroundColor: colorView,
key: _scaffoldStateKey,
appBar: appBar,
bottomNavigationBar: createBottomBar(),
body: isSafeArea == true
? Container(
color: colorSafeArea,
child: SafeArea(
left: false, right: false, child: createBody()))
: createBody(),
),
onWillPop: () {
callBackView();
return willPopToPreviousScreen();
},
),
);
}
if (!isScaffold) {
return PopScope(
// onWillPop: () {
// callBackView();
// return willPopToPreviousScreen();
// },
child: createBody());
}
return WillPopScope(
child: Scaffold(
backgroundColor: colorView,
appBar: appBar,
bottomNavigationBar: createBottomBar(),
body: isSafeArea == true
? GestureDetector(
onPanUpdate: (details) {
// Swiping in right direction.
if (details.delta.dx > 0) {
// Get.back();
}
// Swiping in left direction.
if (details.delta.dx < 0) {}
},
onTap: () {
FocusScope.of(context).unfocus();
},
child: Container(
color: colorSafeArea,
child: SafeArea(
left: false,
right: false,
top: isTopSafeArea,
bottom: isBottomSafeArea,
child: createBody())))
: GestureDetector(
onPanUpdate: (details) {
// Swiping in right direction.
if (details.delta.dx > 0) {
// Get.back();
}
// Swiping in left direction.
if (details.delta.dx < 0) {
// Get.back();
}
},
onTap: () {
FocusScope.of(context).unfocus();
},
child: createBody()),
),
onWillPop: () {
return willPopToPreviousScreen();
},
);
}
bool get isSafeArea {
return false;
}
Color get colorView {
return Colors.white;
}
bool get isScaffold {
return true;
}
bool get isBottomSafeArea {
return true;
}
bool get isTopSafeArea {
return true;
}
Color get colorSafeArea {
return Colors.white;
}
int get numberTabController {
return 0;
}
Widget createBody();
PreferredSizeWidget? createAppBar() {
return null;
}
Future<bool> willPopToPreviousScreen() {
return Future(() => true);
}
void callBackView() {}
}
\ No newline at end of file
class APIPaths {
static const String baseUrl = "https://api.mypoint.com.vn/8854/gup2start/rest";
static const String baseUrl = "https://api.sandbox.mypoint.com.vn/8854/gup2start/rest";
static const String checkUpdate = "/version-management-service/api/v1.0/check-customer-software-update";
static const String getOnboardingInfo = "/resource/api/v2.0/intro-screen";
static const String checkPhoneNumber = "/user/api/v2.0/account/users/checkPhoneNumber";
}
class Constants {
static get commonError => "Có lỗi xảy ra. Vui lòng thử lại!";
// device key
}
class ErrorCodes {
static var deviceLock = "ERR_DEVICE_LOCK";
}
\ No newline at end of file
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
class DeviceInfo {
static Future<String> getDeviceId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? deviceId = prefs.getString('device_id');
if (deviceId == null) {
deviceId = const Uuid().v4(); // Tạo UUID mới
await prefs.setString('device_id', deviceId);
}
return deviceId;
}
}
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/shared/e_grab_navigate.dart';
import 'package:mypoint_flutter_app/shared/navigate_helper.dart';
class ExceptionInterceptor extends Interceptor with navigateHelper {
@override
......
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:mypoint_flutter_app/resouce/base_color.dart';
import 'package:flutter/cupertino.dart';
import '../configs/callbacks.dart';
import '../resouce/text_style.dart';
import '../widgets/button_container.dart';
extension BuildContextAndAlert on BuildContext {
showAlertDialog(String message) {
showCupertinoDialog(
showAlertDialog(String message, {Callback<bool>? callback}) {
_showConfirmAlertDialogTwoButton(message, callback: callback);
}
showConfirmAlertDialog(String message,
{String cancel = "Huỷ",
String confirm = "Xác nhận",
Callback<bool>? callback}) {
_showConfirmAlertDialogTwoButton(message, cancel: cancel, confirm: confirm, callback: callback);
}
_showConfirmAlertDialogTwoButton(String message,
{String cancel = "",
String confirm = "Xác nhận",
Callback<bool>? callback}) {
showDialog<void>(
context: this,
builder: (context) {
return CupertinoAlertDialog(
title: Text('Error'),
content: Text(message),
actions: <Widget>[
CupertinoDialogAction(
isDefaultAction: true,
child: Text('OK'),
builder: (BuildContext context) {
return AlertDialog(
backgroundColor: Colors.white,
title: Text('Thông báo',
textAlign: TextAlign.center,
style: textSemiBold.copyWith(fontSize: 16)),
content: SingleChildScrollView(
child: ListBody(children: [
Text(message),
])),
actionsAlignment: MainAxisAlignment.center,
actionsPadding: EdgeInsets.symmetric(horizontal: 20).copyWith(bottom: 20),
actions: [
ButtonContainer(
height: 40,
color: BaseColor.primary500,
visible: cancel.isNotEmpty,
child: TextButton(
child: Text(cancel,
style: textSemiBold.copyWith(
fontSize: 14, color: Colors.white)),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
Get.back();
if (callback != null) {
callback(false);
}
})),
ButtonContainer(
height: 40,
color: BaseColor.primary500,
visible: confirm.isNotEmpty,
child: TextButton(
child: Text(confirm,
style: textSemiBold.copyWith(
fontSize: 14, color: Colors.white)),
onPressed: () {
Get.back();
if (callback != null) {
callback(true);
}
}))
]);
},
);
}
......
import 'dart:convert';
import 'package:crypto/crypto.dart';
extension PhoneValidator on String {
bool isPhoneValid() {
return RegExp(r'^0\d{9}$').hasMatch(this);
}
}
extension StringConvert on String {
String toSha256() {
var bytes1 = utf8.encode(this); // data being hashed
var digest1 = sha256.convert(bytes1);
return digest1.toString();
}
}
\ No newline at end of file
......@@ -20,9 +20,7 @@ class MyApp extends StatelessWidget {
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.deepPurple),
primaryColor: Colors.deepPurple,
),
home: OnboardingScreen(), //SplashScreen(),
home: SplashScreen(),
);
}
}
\ No newline at end of file
import 'dart:io';
import 'package:mypoint_flutter_app/configs/api_paths.dart';
import 'package:mypoint_flutter_app/base/base_response_model.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/networking/restful_api.dart';
import '../configs/device_info.dart';
import '../model/update_response_object.dart';
import '../onboading/model/check_phone_response_model.dart';
import '../onboading/model/onboarding_info_model.dart';
import 'model_maker.dart';
extension RestfullAPIClientAllApi on RestfulAPIClient {
Future<BaseResponseModel<UpdateResponseObject>> checkUpdateApp() async {
String version = Platform.version;
final body = {"operating_system": "iOS", "software_model": "MyPoint", "version": version, "build_number": "1",};
return requestNormal(APIPaths.checkUpdate, Method.POST, body, (data) => UpdateResponseObject.fromJson(data as Json));
final body = {"operating_system": "iOS", "software_model": "MyPoint", "version": version, "build_number": "1"};
return requestNormal(
APIPaths.checkUpdate,
Method.POST,
body,
(data) => UpdateResponseObject.fromJson(data as Json),
);
}
Future<BaseResponseModel<OnboardingInfoModel>> getOnboardingInfo() async {
return requestNormal(
APIPaths.getOnboardingInfo,
Method.GET,
{},
(data) => OnboardingInfoModel.fromJson(data as Json),
);
}
Future<BaseResponseModel<CheckPhoneResponseModel>> checkPhoneNumber(String phone) async {
var deviceKey = await DeviceInfo.getDeviceId();
var key = "$phone+_=$deviceKey/*8854";
final body = {"device_key": deviceKey, "phone_number": phone, "key": key.toSha256()};
return requestNormal(
APIPaths.checkPhoneNumber,
Method.POST,
body,
(data) => CheckPhoneResponseModel.fromJson(data as Json),
);
}
}
import 'package:json_annotation/json_annotation.dart';
part 'check_phone_response_model.g.dart';
@JsonSerializable()
class CheckPhoneResponseModel {
@JsonKey(name: 'require_recaptcha')
bool? requireRecaptcha;
@JsonKey(name: 'next_action')
String? nextAction;
@JsonKey(name: 'mfa_token')
String? mfaToken;
@JsonKey(name: 'otp_ttl')
int? otpTtl;
CheckPhoneResponseModel({
this.requireRecaptcha,
this.nextAction,
this.mfaToken,
this.otpTtl,});
factory CheckPhoneResponseModel.fromJson(Map<String, dynamic> json) => _$CheckPhoneResponseModelFromJson(json);
Map<String, dynamic> toJson() => _$CheckPhoneResponseModelToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'check_phone_response_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
CheckPhoneResponseModel _$CheckPhoneResponseModelFromJson(
Map<String, dynamic> json,
) => CheckPhoneResponseModel(
requireRecaptcha: json['require_recaptcha'] as bool?,
nextAction: json['next_action'] as String?,
mfaToken: json['mfa_token'] as String?,
otpTtl: (json['otp_ttl'] as num?)?.toInt(),
);
Map<String, dynamic> _$CheckPhoneResponseModelToJson(
CheckPhoneResponseModel instance,
) => <String, dynamic>{
'require_recaptcha': instance.requireRecaptcha,
'next_action': instance.nextAction,
'mfa_token': instance.mfaToken,
'otp_ttl': instance.otpTtl,
};
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment