Commit 56e8b038 authored by DatHV's avatar DatHV
Browse files

update game, shopping

parent c285d072
......@@ -41,9 +41,9 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
Get.dialog(
CustomAlertDialog(
alertData: DataAlertModel(
background: "assets/images/bg_alert_header.png",
localHeaderImage: "assets/images/bg_alert_header.png",
title: "Cài đặt mật khẩu",
content: message,
description: message,
buttons: [
AlertButton(
text: "Cài đặt ngay",
......@@ -52,7 +52,6 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
},
bgColor: BaseColor.primary500,
textColor: Colors.white,
isPrimary: true,
),
],
),
......@@ -68,9 +67,9 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
Get.dialog(
CustomAlertDialog(
alertData: DataAlertModel(
background: "assets/images/bg_alert_header.png",
localHeaderImage: "assets/images/bg_alert_header.png",
title: "",
content: message,
description: message,
buttons: [
AlertButton(
text: "Quên mật khẩu",
......@@ -79,7 +78,6 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
},
bgColor: BaseColor.primary500,
textColor: Colors.white,
isPrimary: true,
),
AlertButton(
text: "Đã hiểu",
......@@ -88,7 +86,6 @@ class _LoginScreenState extends BaseState<LoginScreen> with BasicState {
},
bgColor: Colors.white,
textColor: Colors.black,
isPrimary: true,
),
],
),
......
......@@ -3,7 +3,7 @@ import '../../resouce/base_color.dart';
import '../game/game_tab_screen.dart';
import '../home/home_screen.dart';
import '../personal/personal_screen.dart';
import '../support/transaction_history_screen.dart';
import '../shopping/shopping_tab_screen.dart';
import '../voucher/voucher_tab_screen.dart';
class MainTabScreen extends StatefulWidget {
......@@ -20,7 +20,7 @@ class _MainTabScreenState extends State<MainTabScreen> {
HomeScreen(),
VoucherTabScreen(),
GameTabScreen(),
TransactionHistoryScreen(),
ShoppingTabScreen(),
PersonalScreen(),
];
......@@ -43,7 +43,7 @@ class _MainTabScreenState extends State<MainTabScreen> {
children: [
_buildTabItem(icon: Icons.home, label: 'Trang chủ', index: 0),
_buildTabItem(icon: Icons.star, label: 'Ưu đãi', index: 1),
_buildTabItem(icon: Icons.videogame_asset, label: 'Game', index: 2),
_buildTabItem(icon: null, label: 'Game', index: 2, gift: 'assets/images/ic_tabbar_game.gif'),
_buildTabItem(icon: Icons.shopping_cart, label: 'Mua sắm', index: 3),
_buildTabItem(icon: Icons.person, label: 'Cá nhân', index: 4),
],
......@@ -54,7 +54,7 @@ class _MainTabScreenState extends State<MainTabScreen> {
);
}
Widget _buildTabItem({required IconData icon, required String label, required int index}) {
Widget _buildTabItem({required IconData? icon, required String label, required int index, String? gift}) {
final isSelected = _currentIndex == index;
return Expanded(
child: GestureDetector(
......@@ -65,9 +65,18 @@ class _MainTabScreenState extends State<MainTabScreen> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon,
if (icon != null)
Icon(icon,
size: 28,
color: isSelected ? Colors.white : Colors.white70),
if (gift != null)
Image.asset(
gift,
width: 40,
height: 28,
fit: BoxFit.cover,
color: isSelected ? Colors.white : Colors.white70,
),
const SizedBox(height: 2),
Text(
label,
......
import 'package:json_annotation/json_annotation.dart';
part 'brand_model.g.dart';
@JsonSerializable()
class BrandModel {
@JsonKey(name: 'product_name')
final String? productName;
@JsonKey(name: 'product_price')
final String? productPrice;
@JsonKey(name: 'product_link')
final String? productLink;
final String? commision;
final String? logo;
@JsonKey(name: 'thumnail_link')
final String? thumnailLink;
@JsonKey(name: 'quantity_sold')
final String? quantitySold;
final String? direction;
BrandModel({
this.productName,
this.productPrice,
this.productLink,
this.commision,
this.logo,
this.thumnailLink,
this.quantitySold,
this.direction,
});
factory BrandModel.fromJson(Map<String, dynamic> json) => _$BrandModelFromJson(json);
Map<String, dynamic> toJson() => _$BrandModelToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'brand_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BrandModel _$BrandModelFromJson(Map<String, dynamic> json) => BrandModel(
productName: json['product_name'] as String?,
productPrice: json['product_price'] as String?,
productLink: json['product_link'] as String?,
commision: json['commision'] as String?,
logo: json['logo'] as String?,
thumnailLink: json['thumnail_link'] as String?,
quantitySold: json['quantity_sold'] as String?,
direction: json['direction'] as String?,
);
Map<String, dynamic> _$BrandModelToJson(BrandModel instance) =>
<String, dynamic>{
'product_name': instance.productName,
'product_price': instance.productPrice,
'product_link': instance.productLink,
'commision': instance.commision,
'logo': instance.logo,
'thumnail_link': instance.thumnailLink,
'quantity_sold': instance.quantitySold,
'direction': instance.direction,
};
import 'package:json_annotation/json_annotation.dart';
part 'product_brand_model.g.dart';
@JsonSerializable()
class ProductBrandModel {
@JsonKey(name: 'brand_id')
final String brandId;
@JsonKey(name: 'brand_name')
final String? brandName;
final String? commision;
final String? logo;
@JsonKey(name: 'brand_url')
final String? brandUrl;
@JsonKey(name: 'category_name')
final String? categoryName;
final String? direction;
ProductBrandModel({
required this.brandId,
this.brandName,
this.commision,
this.logo,
this.brandUrl,
this.categoryName,
this.direction,
});
factory ProductBrandModel.fromJson(Map<String, dynamic> json) => _$ProductBrandModelFromJson(json);
Map<String, dynamic> toJson() => _$ProductBrandModelToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'product_brand_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ProductBrandModel _$ProductBrandModelFromJson(Map<String, dynamic> json) =>
ProductBrandModel(
brandId: json['brand_id'] as String,
brandName: json['brand_name'] as String?,
commision: json['commision'] as String?,
logo: json['logo'] as String?,
brandUrl: json['brand_url'] as String?,
categoryName: json['category_name'] as String?,
direction: json['direction'] as String?,
);
Map<String, dynamic> _$ProductBrandModelToJson(ProductBrandModel instance) =>
<String, dynamic>{
'brand_id': instance.brandId,
'brand_name': instance.brandName,
'commision': instance.commision,
'logo': instance.logo,
'brand_url': instance.brandUrl,
'category_name': instance.categoryName,
'direction': instance.direction,
};
import 'package:flutter/material.dart';
class ShoppingScreen extends StatelessWidget {
const ShoppingScreen({super.key});
@override
Widget build(BuildContext context) {
return const Center(child: Text('Mua sắm'));
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import '../../resouce/base_color.dart';
import '../../widgets/custom_navigation_bar.dart';
class ShoppingTabScreen extends StatefulWidget {
const ShoppingTabScreen({super.key});
@override
State<ShoppingTabScreen> createState() => _ShoppingTabScreenState();
}
class _ShoppingTabScreenState extends State<ShoppingTabScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade50,
appBar: CustomNavigationBar(
title: "Mua sắm",
showBackButton: false,
rightButtons: [
IconButton(
icon: const Icon(Icons.info, color: Colors.white),
onPressed: () {
},
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.amber.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
const Text("Điểm hoàn:", style: TextStyle(fontSize: 18, fontWeight: FontWeight.normal)),
const SizedBox(width: 8),
Image.asset('assets/images/ic_point.png', width: 20, height: 20),
const SizedBox(width: 4),
const Text("0", style: TextStyle(fontSize: 20, color: BaseColor.primary400, fontWeight: FontWeight.bold)),
const Spacer(),
Icon(Icons.arrow_forward_ios, color: BaseColor.primary400, size: 16),
],
),
),
const SizedBox(height: 16),
SizedBox(
height: 130,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
_buildStepCard("assets/images/banner_tutorial_refund_point_step1.png"),
const SizedBox(width: 12),
_buildStepCard("assets/images/banner_tutorial_refund_point_step2.png"),
const SizedBox(width: 12),
_buildStepCard("assets/images/banner_tutorial_refund_point_step3.png"),
const SizedBox(width: 12),
_buildStepCard("assets/images/banner_tutorial_refund_point_step4.png"),
],
),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text("Thương Hiệu Hoàn Điểm", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
Text("Xem tất cả", style: TextStyle(color: BaseColor.primary400, fontSize: 14, fontWeight: FontWeight.w600)),
],
),
const SizedBox(height: 12),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
childAspectRatio: 3 / 3.2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
children: [
_buildBrandItem("Lazada", "30%", "assets/images/ic_pipi_06.png"),
_buildBrandItem("Newshop", "5,3%", "assets/images/ic_pipi_06.png"),
_buildBrandItem("Tiki", "0,78%", "assets/images/ic_pipi_06.png"),
_buildBrandItem("MyTour MyTour MyTour", "3,1%", "assets/images/ic_pipi_06.png"),
_buildBrandItem("Pierre Cardin", "10,2%", "assets/images/ic_pipi_06.png"),
_buildBrandItem("Adidas", "2,9%", "assets/images/ic_pipi_06.png"),
],
),
Text("Lĩnh Vực Hoàn Điểm", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
const SizedBox(height: 12),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 5,
offset: const Offset(0, 2),
)
],
),
child: GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
childAspectRatio: 3 / 3.2,
// crossAxisSpacing: 8,
children: [
_fieldCashBackItem("Lazada", "30%", "assets/images/ic_pipi_06.png"),
_fieldCashBackItem("Newshop", "5,3%", "assets/images/ic_pipi_06.png"),
_fieldCashBackItem("Tiki", "0,78%", "assets/images/ic_pipi_06.png"),
_fieldCashBackItem("MyTour MyTour MyTour", "3,1%", "assets/images/ic_pipi_06.png"),
_fieldCashBackItem("Pierre Cardin", "10,2%", "assets/images/ic_pipi_06.png"),
_fieldCashBackItem("Adidas", "2,9%", "assets/images/ic_pipi_06.png"),
],
),
),
],
),
),
);
}
Widget _buildStepCard(String imagePath) {
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.asset(imagePath, fit: BoxFit.cover, width: 250),
);
}
Widget _fieldCashBackItem(String name, String cashback, String logoPath) {
return LayoutBuilder(
builder: (context, constraints) {
final double imageWidth = constraints.maxWidth / 2;
return Container(
padding: const EdgeInsets.all(12),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: imageWidth,
height: imageWidth, // ✅ 1:1 ratio
child: Image.asset(logoPath, fit: BoxFit.contain),
),
const SizedBox(height: 4),
Text(
textAlign: TextAlign.center,
name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16, color: BaseColor.second500),
),
],
),
);
},
);
}
Widget _buildBrandItem(String name, String cashback, String logoPath) {
return LayoutBuilder(
builder: (context, constraints) {
final double imageWidth = constraints.maxWidth / 2;
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 5,
offset: const Offset(0, 2),
)
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: imageWidth,
height: imageWidth, // ✅ 1:1 ratio
child: Image.asset(logoPath, fit: BoxFit.contain),
),
const SizedBox(height: 4),
Text(
name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16),
),
const SizedBox(height: 4),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: const TextStyle(fontSize: 12),
children: [
const TextSpan(
text: "Hoàn đến: ",
style: TextStyle(color: Colors.grey),
),
TextSpan(
text: cashback,
style: const TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
);
},
);
}
}
import '../../base/restful_api_viewmodel.dart';
class ShoppingTabViewModel extends RestfulApiViewModel {
}
\ No newline at end of file
......@@ -95,7 +95,6 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState, ApiHel
},
bgColor: BaseColor.primary500,
textColor: Colors.white,
isPrimary: true,
),]
: [AlertButton(
text: "Cập nhật",
......@@ -104,7 +103,6 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState, ApiHel
},
bgColor: BaseColor.primary500,
textColor: Colors.white,
isPrimary: true,
),
AlertButton(
text: "Để sau",
......@@ -114,12 +112,11 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState, ApiHel
},
bgColor: Colors.white,
textColor: BaseColor.primary500,
isPrimary: false,
),];
final model = DataAlertModel(
background: "assets/images/ic_pipi_03.png",
localHeaderImage: "assets/images/ic_pipi_03.png",
title: data.updateTitle ?? "Cập nhật phiên bản mới",
content: data.updateMessage ?? "Cập nhật phiên bản mới",
description: data.updateMessage ?? "Cập nhật phiên bản mới",
buttons: buttons,
);
showAlert(data: model, showCloseButton: false, direction: ButtonsDirection.row);
......
......@@ -9,7 +9,6 @@ import '../../../resouce/base_color.dart';
import '../../../widgets/back_button.dart';
import '../../../widgets/custom_empty_widget.dart';
import '../../../widgets/custom_point_text_tag.dart';
import '../../../widgets/custom_price_tag.dart';
import '../../../widgets/dashed_line.dart';
import '../../../widgets/image_loader.dart';
import '../../../widgets/measure_size.dart';
......@@ -30,7 +29,6 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
late final int productId;
late final VoucherDetailViewModel _viewModel;
double _infoHeight = 0;
final _quantity = 1.obs;
@override
void initState() {
......@@ -410,15 +408,14 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
child: IconButton(
icon: const Icon(Icons.remove, color: Colors.black),
onPressed: () {
if (_quantity.value > 1) {
_quantity.value--;
// TODO: update state
if (_viewModel.quantity.value > 1) {
_viewModel.quantity.value--;
}
},
),
),
const SizedBox(width: 12),
Obx(() => Text('${_quantity.value}', style: const TextStyle(fontSize: 16))),
Obx(() => Text('${_viewModel.quantity.value}', style: const TextStyle(fontSize: 16))),
const SizedBox(width: 12),
Container(
decoration: BoxDecoration(
......@@ -429,8 +426,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
child: IconButton(
icon: const Icon(Icons.add, color: Colors.white),
onPressed: () {
_quantity.value++;
// TODO: update state
_viewModel.quantity.value++;
},
),
),
......@@ -442,7 +438,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
height: 48,
child: ElevatedButton(
onPressed: () {
// TODO: Handle mua ngay
_viewModel.verifyOrderProduct();
},
style: ElevatedButton.styleFrom(
backgroundColor: BaseColor.primary500,
......
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import '../../../base/restful_api_viewmodel.dart';
import '../../../configs/constants.dart';
import '../models/product_model.dart';
import '../models/product_store_model.dart';
......@@ -12,6 +13,7 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
var isLoading = false.obs;
var liked = false.obs;
void Function(String message)? onShowAlertError;
var quantity = 1.obs;
@override
void onInit() {
......@@ -63,4 +65,28 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
print("Error product stores: $error");
} finally {}
}
verifyOrderProduct() async {
final value = product.value;
var body = {
"product_id": productId,
"price": value?.amountToBePaid,
"quantity": quantity.value,
};
if (value?.previewFlashSale?.isFlashSalePrice == true) {
final flashSaleId = value?.previewFlashSale?.id;
if (flashSaleId != null) {
body["flash_sale_id"] = flashSaleId;
}
}
showLoading();
client.verifyOrderProduct(body).then((value) {
hideLoading();
if (!value.isSuccess) {
onShowAlertError?.call(value.errorMessage ?? Constants.commonError);
} else {
onShowAlertError?.call("Verify Order Product Success -> Go To Payment Detail");
}
});
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:json_annotation/json_annotation.dart';
import 'directional_screen.dart';
import 'package:mypoint_flutter_app/extensions/color_extension.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import '../../directional/directional_screen.dart';
import 'data_alert_model.dart';
part 'button_config_model.g.dart';
@JsonSerializable()
......@@ -10,16 +15,30 @@ class ButtonConfigModel {
final String? clickActionType;
@JsonKey(name: "click_action_param")
final String? clickActionParam;
final bool? hiden;
ButtonConfigModel({
this.text,
this.color,
this.clickActionType,
this.clickActionParam,
this.hiden,
});
AlertButton get alertButton {
final bgColor = color?.toColor() ?? Colors.white;
return AlertButton(
text: text ?? "",
textColor: bgColor.invert,
bgColor: bgColor,
onPressed: () {
if (directionScreen != null) {
directionScreen?.begin();
} else {
Get.back();
}
},
);
}
factory ButtonConfigModel.fromJson(Map<String, dynamic> json) => _$ButtonConfigModelFromJson(json);
Map<String, dynamic> toJson() => _$ButtonConfigModelToJson(this);
......
......@@ -12,7 +12,6 @@ ButtonConfigModel _$ButtonConfigModelFromJson(Map<String, dynamic> json) =>
color: json['color'] as String?,
clickActionType: json['click_action_type'] as String?,
clickActionParam: json['click_action_param'] as String?,
hiden: json['hiden'] as bool?,
);
Map<String, dynamic> _$ButtonConfigModelToJson(ButtonConfigModel instance) =>
......@@ -21,5 +20,4 @@ Map<String, dynamic> _$ButtonConfigModelToJson(ButtonConfigModel instance) =>
'color': instance.color,
'click_action_type': instance.clickActionType,
'click_action_param': instance.clickActionParam,
'hiden': instance.hiden,
};
import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:get/get.dart';
import '../../resouce/base_color.dart';
import '../image_loader.dart';
import 'data_alert_model.dart';
enum ButtonsDirection { row, column }
......@@ -10,7 +12,12 @@ class CustomAlertDialog extends StatelessWidget {
final ButtonsDirection direction;
final bool showCloseButton;
const CustomAlertDialog({super.key, required this.alertData, this.direction = ButtonsDirection.column, this.showCloseButton = true,});
const CustomAlertDialog({
super.key,
required this.alertData,
this.direction = ButtonsDirection.column,
this.showCloseButton = true,
});
@override
Widget build(BuildContext context) {
......@@ -20,22 +27,11 @@ class CustomAlertDialog extends StatelessWidget {
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(16), color: Colors.white),
child: Stack(
children: [Container(
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header Image
if (alertData.background != null)
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(alertData.background!),
// .network(
// alertData.background!,
// height: 120,
// width: 120,
// fit: BoxFit.cover,
// ),
),
_buildHeaderImage(),
const SizedBox(height: 2),
// Title
if (alertData.title != null)
......@@ -45,26 +41,23 @@ class CustomAlertDialog extends StatelessWidget {
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
// HTML Content
if (alertData.description != null)
HtmlWidget('''
<div style="text-align: center;">
${alertData.description!}
</div>
'''),
const SizedBox(height: 4),
if (alertData.content != null)
HtmlWidget(
Text(
alertData.content!,
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: BaseColor.primary500),
textAlign: TextAlign.center,
),
// Html(
// data: alertData.content!,
// style: {
// "body": Style(
// textAlign: TextAlign.center,
// fontSize: FontSize.medium,
// ),
// },
// ),
const SizedBox(height: 10),
// Buttons
_buildButtons(),
],
),
),
// Close Button (X) ở góc phải trên
if (showCloseButton)
Positioned(
......@@ -75,30 +68,47 @@ class CustomAlertDialog extends StatelessWidget {
child: const Icon(Icons.close, color: Colors.black, size: 24),
),
),
]
],
),
),
);
}
Widget _buildHeaderImage() {
if ((alertData.urlHeaderImage ?? "").isNotEmpty) {
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: loadNetworkImage(
url: alertData.urlHeaderImage,
fit: BoxFit.cover,
placeholderAsset: "assets/images/ic_pipi_06.png",
),
);
}
final localHeaderImage = (alertData.localHeaderImage ?? "");
final localImage = localHeaderImage.isNotEmpty ? localHeaderImage : "assets/images/ic_pipi_06.png";
return ClipRRect(borderRadius: BorderRadius.circular(12), child: Image.asset(localImage));
}
Widget _buildButtons() {
return direction == ButtonsDirection.column
? Column(
children:
alertData.buttons
?.map(
?.whereType<AlertButton>()
.map(
(btn) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: btn.bgColor,
backgroundColor: btn?.bgColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
minimumSize: const Size(double.infinity, 48),
),
onPressed: btn.onPressed,
onPressed: btn?.onPressed,
child: Text(
btn.text,
style: TextStyle(color: btn.textColor, fontSize: 14, fontWeight: FontWeight.bold),
btn?.text ?? "",
style: TextStyle(color: btn?.textColor, fontSize: 14, fontWeight: FontWeight.bold),
),
),
),
......@@ -110,20 +120,21 @@ class CustomAlertDialog extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:
alertData.buttons
?.map(
?.whereType<AlertButton>()
.map(
(btn) => Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: btn.bgColor,
backgroundColor: btn?.bgColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
minimumSize: const Size(100, 48),
),
onPressed: btn.onPressed,
onPressed: btn?.onPressed,
child: Text(
btn.text,
style: TextStyle(color: btn.textColor, fontSize: 14, fontWeight: FontWeight.bold),
btn?.text ?? "",
style: TextStyle(color: btn?.textColor, fontSize: 14, fontWeight: FontWeight.bold),
),
),
),
......
import 'dart:ui';
import 'package:flutter/material.dart';
import '../../resouce/base_color.dart';
class DataAlertModel {
final String? background;
final String? localHeaderImage;
final String? urlHeaderImage;
final String? title;
final String? description;
final String? content;
final List<AlertButton>? buttons;
final List<AlertButton?>? buttons;
DataAlertModel({
this.background,
this.localHeaderImage,
this.urlHeaderImage,
this.title,
this.description,
this.content,
this.buttons = const [],
});
......@@ -20,14 +23,12 @@ class AlertButton {
final String text;
final Color textColor;
final Color bgColor;
final bool isPrimary;
final VoidCallback onPressed;
AlertButton({
required this.text,
required this.textColor,
required this.bgColor,
required this.isPrimary,
required this.onPressed,
});
}
......
import '../../resouce/base_color.dart';
import 'button_config_model.dart';
import 'package:json_annotation/json_annotation.dart';
import 'data_alert_model.dart';
part 'popup_data_model.g.dart';
@JsonSerializable()
class PopupDataModel {
@JsonKey(name: "header_img")
final String? urlHeaderImg;
final String? title;
final String? description;
final String? value;
@JsonKey(name: "button_confirm")
final ButtonConfigModel? buttonConfirm;
@JsonKey(name: "button_cancel")
final ButtonConfigModel? buttonCancel;
@JsonKey(name: "local_img")
final String? localHeaderImg;
DataAlertModel get dataAlertModel {
return DataAlertModel(
urlHeaderImage: urlHeaderImg,
localHeaderImage: localHeaderImg,
title: title,
description: description,
buttons: [buttonConfirm?.alertButton, buttonCancel?.alertButton],
);
}
PopupDataModel({
this.urlHeaderImg,
this.title,
this.description,
this.value,
this.buttonConfirm,
this.buttonCancel,
this.localHeaderImg,
});
factory PopupDataModel.fromJson(Map<String, dynamic> json) => _$PopupDataModelFromJson(json);
Map<String, dynamic> toJson() => _$PopupDataModelToJson(this);
}
\ No newline at end of file
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'popup_data_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
PopupDataModel _$PopupDataModelFromJson(Map<String, dynamic> json) =>
PopupDataModel(
urlHeaderImg: json['header_img'] as String?,
title: json['title'] as String?,
description: json['description'] as String?,
value: json['value'] as String?,
buttonConfirm:
json['button_confirm'] == null
? null
: ButtonConfigModel.fromJson(
json['button_confirm'] as Map<String, dynamic>,
),
buttonCancel:
json['button_cancel'] == null
? null
: ButtonConfigModel.fromJson(
json['button_cancel'] as Map<String, dynamic>,
),
localHeaderImg: json['local_img'] as String?,
);
Map<String, dynamic> _$PopupDataModelToJson(PopupDataModel instance) =>
<String, dynamic>{
'header_img': instance.urlHeaderImg,
'title': instance.title,
'description': instance.description,
'value': instance.value,
'button_confirm': instance.buttonConfirm,
'button_cancel': instance.buttonCancel,
'local_img': instance.localHeaderImg,
};
......@@ -48,7 +48,8 @@ dependencies:
local_auth:
pin_code_fields:
intl: ^0.18.1
game_miniapp:
path: ../mini_app/game_miniapp
dev_dependencies:
flutter_test:
sdk: flutter
......
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