Commit efb4662c authored by DatHV's avatar DatHV
Browse files

update campaign 7day

parent 4c376d38
......@@ -65,7 +65,7 @@ class VoucherListItem extends StatelessWidget {
if (!product.inStock)
Positioned.fill(
child: Container(
color: Colors.black.withOpacity(0.5),
color: Colors.black.withOpacity(0.3),
alignment: Alignment.center,
child: const Text(
'Tạm hết',
......
......@@ -19,6 +19,7 @@ class _VoucherListScreenState extends State<VoucherListScreen> {
late final Map<String, dynamic> args;
late final bool enableSearch;
late final bool isHotProduct;
late final bool isFavorite;
late final VoucherListViewModel _viewModel;
@override
......@@ -27,12 +28,13 @@ class _VoucherListScreenState extends State<VoucherListScreen> {
args = Get.arguments ?? {};
enableSearch = args['enableSearch'] ?? false;
isHotProduct = args['isHotProduct'] ?? false;
_viewModel = Get.put(VoucherListViewModel(isHotProduct: isHotProduct));
isFavorite = args['favorite'] ?? false;
_viewModel = Get.put(VoucherListViewModel(isHotProduct: isHotProduct, isFavorite: isFavorite));
}
@override
Widget build(BuildContext context) {
final String title = isHotProduct ? 'Săn ưu đãi' : 'Tất cả ưu đãi';
final String title = isFavorite ? 'Yêu thích' : (isHotProduct ? 'Săn ưu đãi' : 'Tất cả ưu đãi');
return Scaffold(
appBar:
enableSearch
......@@ -69,21 +71,22 @@ class _VoucherListScreenState extends State<VoucherListScreen> {
);
}
return RefreshIndicator(
onRefresh: () => _viewModel.getProducts(reset: true),
onRefresh: () => _viewModel.loadData(reset: true),
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: _viewModel.products.length + (_viewModel.hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index >= _viewModel.products.length) {
_viewModel.getProducts(reset: false);
_viewModel.loadData(reset: false);
return const Center(
child: Padding(padding: EdgeInsets.all(16), child: CircularProgressIndicator()),
);
}
final product = _viewModel.products[index];
return GestureDetector(
onTap: () {
Get.toNamed(voucherDetailScreen, arguments: {"productId": product.id});
onTap: () async {
await Get.toNamed(voucherDetailScreen, arguments: {"productId": product.id});
_viewModel.loadData(reset: true);
},
child: VoucherListItem(product: product),
);
......
......@@ -6,8 +6,8 @@ import '../models/product_model.dart';
import '../models/product_type.dart';
class VoucherListViewModel extends RestfulApiViewModel {
VoucherListViewModel({required this.isHotProduct});
VoucherListViewModel({required this.isHotProduct, this.isFavorite = false});
final bool isFavorite;
final bool isHotProduct;
Timer? _debounce;
var products = <ProductModel>[].obs;
......@@ -24,7 +24,7 @@ class VoucherListViewModel extends RestfulApiViewModel {
@override
void onInit() {
super.onInit();
getProducts(reset: true);
loadData(reset: true);
}
@override
......@@ -38,11 +38,47 @@ class VoucherListViewModel extends RestfulApiViewModel {
_searchQuery = value;
_debounce?.cancel();
_debounce = Timer(const Duration(seconds: 1), () {
getProducts(reset: true);
loadData(reset: true);
});
}
Future<void> getProducts({bool reset = false}) async {
Future<void> loadData({bool reset = false}) async {
if (isFavorite) {
await _getFavoriteProducts(reset: reset);
} else {
await _getProducts(reset: reset);
}
}
Future<void> _getFavoriteProducts({bool reset = false}) async {
if (isLoading.value) return;
if (reset) {
_currentPage = 0;
_hasMore = true;
products.clear();
} else {
_currentPage = products.length;
}
if (!_hasMore) return;
final body = {"size": _pageSize, "index": _currentPage};
try {
isLoading.value = true;
isLoadMore.value = true;
final result = await client.productsCustomerLikes(body);
final fetchedData = result.data ?? [];
if (fetchedData.isEmpty || fetchedData.length < _pageSize) {
_hasMore = false;
}
products.addAll(fetchedData);
} catch (error) {
print("Error fetching products: $error");
} finally {
isLoading.value = false;
isLoadMore.value = false;
}
}
Future<void> _getProducts({bool reset = false}) async {
if (isLoading.value) return;
if (reset) {
_currentPage = 0;
......
......@@ -41,6 +41,7 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
});
return;
}
showLoading();
_controller =
WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
......@@ -48,12 +49,14 @@ class _BaseWebViewScreenState extends BaseState<BaseWebViewScreen> with BasicSta
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (_) async {
hideLoading();
final title = await _controller.getTitle();
setState(() {
_dynamicTitle = title;
});
},
onWebResourceError: (error) {
hideLoading();
if (error.description != 'about:blank') {
showAlertError(content: error.description);
}
......
......@@ -6,9 +6,12 @@ import '../screen/affiliate/affiliate_tab_screen.dart';
import '../screen/affiliate_brand_detail/affiliate_brand_detail_screen.dart';
import '../screen/affiliate_brand_detail/affiliate_brand_list_screen.dart';
import '../screen/affiliate_brand_detail/affiliate_category_grid_screen.dart';
import '../screen/campaign7day/campaign_7day_screen.dart';
import '../screen/contacts/contacts_list_screen.dart';
import '../screen/daily_checkin/daily_checkin_screen.dart';
import '../screen/data_network_service/data_network_service_screen.dart';
import '../screen/electric_payment/electric_payment_history_screen.dart';
import '../screen/electric_payment/electric_payment_screen.dart';
import '../screen/game/game_cards/game_card_screen.dart';
import '../screen/game/game_tab_screen.dart';
import '../screen/history_point_cashback/history_point_cashback_screen.dart';
......@@ -23,13 +26,17 @@ import '../screen/onboarding/onboarding_screen.dart';
import '../screen/order_menu/order_menu_screen.dart';
import '../screen/pageDetail/campaign_detail_screen.dart';
import '../screen/personal/personal_edit_screen.dart';
import '../screen/quiz_campaign/quiz_campaign_screen.dart';
import '../screen/register_campaign/register_form_input_screen.dart';
import '../screen/setting/setting_screen.dart';
import '../screen/splash/splash_screen.dart';
import '../screen/support/support_screen.dart';
import '../screen/topup/topup_screen.dart';
import '../screen/traffic_service/traffic_service_detail_screen.dart';
import '../screen/traffic_service/traffic_service_screen.dart';
import '../screen/transaction/history/transaction_history_detail_screen.dart';
import '../screen/transaction/transaction_detail_screen.dart';
import '../screen/transaction/transactions_history_screen.dart';
import '../screen/voucher/detail/voucher_detail_screen.dart';
import '../screen/voucher/my_voucher/my_product_list_widget.dart';
import '../screen/voucher/voucher_list/voucher_list_screen.dart';
......@@ -73,6 +80,13 @@ const affiliateCategoryGridScreen = '/affiliateCategoryGridScreen';
const inviteFriendCampaignScreen = '/inviteFriendCampaignScreen';
const contactsListScreen = '/contactsListScreen';
const dailyCheckInScreen = '/dailyCheckInScreen';
const transactionHistoryScreen = '/transactionHistoryScreen';
const electricPaymentScreen = '/electricPaymentScreen';
const electricPaymentHistoryScreen = '/electricPaymentHistoryScreen';
const trafficServiceScreen = '/trafficServiceScreen';
const trafficServiceDetailScreen = '/trafficServiceDetailScreen';
const campaignSevenDayScreen = '/campaignSevenDayScreen';
const surveyQuestionScreen = '/surveyQuestionScreen';
class RouterPage {
static List<GetPage> pages() {
......@@ -86,7 +100,13 @@ class RouterPage {
GetPage(name: splashScreen, page: () => SplashScreen()),
GetPage(name: onboardingScreen, page: () => OnboardingScreen()),
GetPage(name: loginScreen, page: () => LoginScreen()),
GetPage(name: mainScreen, page: () => MainTabScreen(), customTransition: NoSwipeBackTransition()),
GetPage(
name: mainScreen,
page: () => MainTabScreen(),
participatesInRootNavigator: true,
fullscreenDialog: true,
binding: BindingsBuilder(() {}),
),
GetPage(name: settingScreen, page: () => SettingScreen()),
GetPage(name: vouchersScreen, page: () => VoucherListScreen()),
GetPage(name: voucherDetailScreen, page: () => VoucherDetailScreen()),
......@@ -119,20 +139,13 @@ class RouterPage {
GetPage(name: inviteFriendCampaignScreen, page: () => InviteFriendCampaignScreen()),
GetPage(name: contactsListScreen, page: () => ContactsListScreen()),
GetPage(name: dailyCheckInScreen, page: () => DailyCheckInScreen()),
GetPage(name: transactionHistoryScreen, page: () => TransactionHistoryScreen()),
GetPage(name: electricPaymentScreen, page: () => ElectricPaymentScreen()),
GetPage(name: electricPaymentHistoryScreen, page: () => ElectricPaymentHistoryScreen()),
GetPage(name: trafficServiceScreen, page: () => TrafficServiceScreen()),
GetPage(name: trafficServiceDetailScreen, page: () => TrafficServiceDetailScreen()),
GetPage(name: campaignSevenDayScreen, page: () => Campaign7DayScreen()),
GetPage(name: surveyQuestionScreen, page: () => SurveyQuestionScreen()),
];
}
}
class NoSwipeBackTransition extends CustomTransition {
@override
Widget buildTransition(
BuildContext context,
Curve? curve,
Alignment? alignment,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return child;
}
}
\ No newline at end of file
......@@ -24,7 +24,7 @@ class ButtonConfigModel {
final bgColor = color?.toColor() ?? Colors.white;
return AlertButton(
text: text ?? "",
textColor: bgColor.invert,
textColor: bgColor.contrastTextColor,
bgColor: bgColor,
onPressed: () async {
DirectionalScreen? directional = DirectionalScreen.build(
......
This diff is collapsed.
......@@ -5,6 +5,9 @@ import 'package:get/get.dart';
class BottomSheetHelper {
static void showBottomSheetPopup({
required Widget child,
Color backgroundContainerColor = Colors.white,
double horizontalContainerPadding = 8.0,
double bottomContainerPadding = 16.0,
bool isDismissible = true,
}) {
showModalBottomSheet(
......@@ -12,11 +15,12 @@ class BottomSheetHelper {
isScrollControlled: true,
isDismissible: isDismissible,
backgroundColor: Colors.transparent,
barrierColor: Colors.black.withOpacity(0.5),
barrierColor: Colors.black.withOpacity(0.7),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
final bottom = MediaQuery.of(context).padding.bottom;
return Padding(
padding: MediaQuery.of(context).viewInsets.add(
const EdgeInsets.only(bottom: 0), // 👈 Safe area bottom
......@@ -24,11 +28,15 @@ class BottomSheetHelper {
child: Wrap(
children: [
Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
decoration: BoxDecoration(
color: backgroundContainerColor,
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
),
padding: EdgeInsets.only(
left: horizontalContainerPadding,
right: horizontalContainerPadding,
bottom: bottomContainerPadding,
),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: child,
),
SizedBox(height: 32,),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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