initial commit to gitea

This commit is contained in:
2022-03-10 00:47:26 -05:00
parent 808ffa3211
commit f504e213a0
93 changed files with 4394 additions and 1539 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -3,6 +3,8 @@ class Constants {
static const bool ENABLE_NATIVE_PAY = false;
static const bool isPreview = false;
static const int FONT_GOOGLE = 0xe800;
static const int FONT_ALEXA = 0xe801;
static const int FONT_APPLE = 0xe802;
@@ -36,7 +38,7 @@ class Constants {
static const int BLOG_PER_PAGE_MOBILE = 20;
static const int BLOG_PER_PAGE_DESKTOP = 30;
static const double BREADCRUMB_HEIGHT = 38;
static const double BREADCRUMB_HEIGHT = 42;
static const int HOT_SALE_ID = -1;
static const int FEATURED_PRODUCT_ID = -2;
@@ -64,4 +66,9 @@ class Constants {
static const String PAYMENT_STATUS_UNPAID = 'UNPAID';
static const String PAYMENT_STATUS_PAID = 'PAID';
static const String PAYMENT_STATUS_PARTIALPAID = 'PARTIALPAID';
static const double PRODUCT_ITEM_HEIGHT_H = 180;
static const double PRODUCT_ITEM_HEIGHT_V = 278;
static const String WEB_MINISTORE_SERVICE = 'web-ministore-service';
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../models/category_products.dart';
import '../models/business.dart';
import '../models/comment.dart';
@@ -120,4 +121,24 @@ class GetCurrentPositionSuccess {
class GetCurrentPositionFailed {
Exception exception;
GetCurrentPositionFailed(this.exception);
}
class ShopPageScrollUpdated {
double offset;
ShopPageScrollUpdated(this.offset);
}
class GetCategoryProducts {
dynamic data;
GetCategoryProducts(this.data);
}
class MoreCategoryProducts {
List<CategoryProducts> data;
MoreCategoryProducts(this.data);
}
class CategoryChangeEvent {
int categoryId;
CategoryChangeEvent(this.categoryId);
}

View File

@@ -35,53 +35,57 @@ class MessageLookup extends MessageLookupByLibrary {
static m7(discount) => "-\$${discount}";
static m8(oss) => "Download at ${oss}";
static m8(domain) => "${domain} (available)";
static m9(expirationDate) => "Expires on ${expirationDate}";
static m9(domain) => "${domain} (unavailable)";
static m10(mon, yer) => "Exp: ${mon}/${yer}";
static m10(oss) => "Download at ${oss}";
static m11(name, rate) => "${name}(${rate}%)";
static m11(expirationDate) => "Expires on ${expirationDate}";
static m12(num) => "${num} follow-ups";
static m12(mon, yer) => "Exp: ${mon}/${yer}";
static m13(second) => "Retry after ${second}s";
static m13(name, rate) => "${name}(${rate}%)";
static m14(hours) => "${Intl.plural(hours, one: '1 hr', other: '${hours} hrs')}";
static m14(num) => "${num} follow-ups";
static m15(minamount) => "\$${minamount}+";
static m15(second) => "Retry after ${second}s";
static m16(shipfee) => "Delivery \$${shipfee}+";
static m16(hours) => "${Intl.plural(hours, one: '1 hr', other: '${hours} hrs')}";
static m17(minutes) => "${Intl.plural(minutes, one: '1 min', other: '${minutes} mins')}";
static m17(minamount) => "\$${minamount}+";
static m18(minprice) => "${minprice} more";
static m18(shipfee) => "Delivery \$${shipfee}+";
static m19(amount) => "Pay \$${amount} now";
static m19(minutes) => "${Intl.plural(minutes, one: '1 min', other: '${minutes} mins')}";
static m20(method) => "Pay with ${method}";
static m20(minprice) => "${minprice} more";
static m21(mobile) => "Payment verification code has been sent to your mobile phone ${mobile}. Please enter the verification code below.";
static m21(amount) => "Pay \$${amount} now";
static m22(discount) => "${discount}%off";
static m22(method) => "Pay with ${method}";
static m23(amount, discount) => "-\$${amount}(${discount}%off)";
static m23(p1, p2) => "Payment verification code has been sent to your ${p1} ${p2}. Please enter the verification code below.";
static m24(optionName) => "Please choice ${optionName}.";
static m24(discount) => "${discount}%off";
static m25(sold_qty) => " ${sold_qty} sold/mo";
static m25(amount, discount) => "-\$${amount}(${discount}%off)";
static m26(subtotal) => "Subtotal: ${subtotal}";
static m26(optionName) => "Please choice ${optionName}.";
static m27(num) => "Table#: ${num}";
static m27(sold_qty) => " ${sold_qty} sold/mo";
static m28(num) => "Ticket #${num}";
static m28(subtotal) => "Subtotal: ${subtotal}";
static m29(time) => "Today ${time}";
static m29(num) => "Table#: ${num}";
static m30(time) => "Tomorrow ${time}";
static m30(num) => "Ticket #${num}";
static m31(weight) => "Weight: ${weight}";
static m31(time) => "Today ${time}";
static m32(time) => "Tomorrow ${time}";
static m33(weight) => "Weight: ${weight}";
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
@@ -130,6 +134,7 @@ class MessageLookup extends MessageLookupByLibrary {
"change_nickname" : MessageLookupByLibrary.simpleMessage("Change nickname"),
"change_password" : MessageLookupByLibrary.simpleMessage("Change password"),
"change_password_desc" : MessageLookupByLibrary.simpleMessage("Please enter the old password and your desired new password."),
"check_domain_name" : MessageLookupByLibrary.simpleMessage("Check availability"),
"check_option_is_optional" : MessageLookupByLibrary.simpleMessage("Optional. You can tap Next without selection."),
"check_option_is_required" : MessageLookupByLibrary.simpleMessage("Option is required. Select at lease an option then tap Next."),
"check_option_select_token" : m3,
@@ -152,6 +157,7 @@ class MessageLookup extends MessageLookupByLibrary {
"contact_us" : MessageLookupByLibrary.simpleMessage("Contact us"),
"copy" : MessageLookupByLibrary.simpleMessage("Copy"),
"coupons" : MessageLookupByLibrary.simpleMessage("Coupons"),
"create_a_online_store" : MessageLookupByLibrary.simpleMessage("Open an online store"),
"credit_card" : MessageLookupByLibrary.simpleMessage("Credit card"),
"credit_coupon" : MessageLookupByLibrary.simpleMessage("Credit/Coupon"),
"credit_debit_card" : MessageLookupByLibrary.simpleMessage("Credit or debit card"),
@@ -174,9 +180,13 @@ class MessageLookup extends MessageLookupByLibrary {
"discount_amount_token" : m7,
"document_langage" : MessageLookupByLibrary.simpleMessage("Document language"),
"document_type" : MessageLookupByLibrary.simpleMessage("Document type"),
"domain_available_token" : m8,
"domain_name" : MessageLookupByLibrary.simpleMessage("Domain name"),
"domain_unavailable_token" : m9,
"domains_separated_comma" : MessageLookupByLibrary.simpleMessage("Domains separated by comma"),
"dont_use" : MessageLookupByLibrary.simpleMessage("Do not redeem"),
"download" : MessageLookupByLibrary.simpleMessage("Download"),
"download_with_token" : m8,
"download_with_token" : m10,
"downloads" : MessageLookupByLibrary.simpleMessage("Downloads"),
"edit_address" : MessageLookupByLibrary.simpleMessage("Edit address"),
"email" : MessageLookupByLibrary.simpleMessage("Email"),
@@ -190,22 +200,24 @@ class MessageLookup extends MessageLookupByLibrary {
"english" : MessageLookupByLibrary.simpleMessage("English"),
"enter_coupon_code" : MessageLookupByLibrary.simpleMessage("Enter coupon code"),
"enter_delivery_address" : MessageLookupByLibrary.simpleMessage("Enter delivery address"),
"enter_desired_domain" : MessageLookupByLibrary.simpleMessage("Your desired domain name"),
"enter_keyword" : MessageLookupByLibrary.simpleMessage("Enter keyword"),
"enter_mobile_or_email" : MessageLookupByLibrary.simpleMessage("Enter mobile or email"),
"enter_new_nickname" : MessageLookupByLibrary.simpleMessage("Enter new nickname"),
"enter_product_keyword" : MessageLookupByLibrary.simpleMessage("Enter product keyword"),
"error" : MessageLookupByLibrary.simpleMessage("Error"),
"error_read_file" : MessageLookupByLibrary.simpleMessage("Error occurred while reading the file."),
"expiration_date" : MessageLookupByLibrary.simpleMessage("Expiration date"),
"expiration_date_token" : m9,
"expire_token" : m10,
"expiration_date_token" : m11,
"expire_token" : m12,
"expired_at" : MessageLookupByLibrary.simpleMessage("Expired at"),
"extra_fee_token" : m11,
"extra_fee_token" : m13,
"fax" : MessageLookupByLibrary.simpleMessage("Fax"),
"feature_not_available_web" : MessageLookupByLibrary.simpleMessage("This feature is not available on the web. Please install the App version."),
"featured_product" : MessageLookupByLibrary.simpleMessage("Featured"),
"finish" : MessageLookupByLibrary.simpleMessage("Finish"),
"follow_ups" : MessageLookupByLibrary.simpleMessage("Follow ups"),
"followups_token" : m12,
"followups_token" : m14,
"forgot_password" : MessageLookupByLibrary.simpleMessage("Forgot password"),
"forgot_password_description" : MessageLookupByLibrary.simpleMessage("Enter the Email or mobile number you used when registering, and then click the \'Get code\' button to get the validation code."),
"forgot_password_question" : MessageLookupByLibrary.simpleMessage("Forgot password?"),
@@ -217,7 +229,7 @@ class MessageLookup extends MessageLookupByLibrary {
"general_coupon" : MessageLookupByLibrary.simpleMessage("General coupon"),
"get_code" : MessageLookupByLibrary.simpleMessage("Get code"),
"get_code_again" : MessageLookupByLibrary.simpleMessage("Get code again"),
"get_code_token" : m13,
"get_code_token" : m15,
"get_coupon" : MessageLookupByLibrary.simpleMessage("Get coupon"),
"get_picture" : MessageLookupByLibrary.simpleMessage("Get picture"),
"get_picture_from" : MessageLookupByLibrary.simpleMessage("Get picture from..."),
@@ -226,7 +238,7 @@ class MessageLookup extends MessageLookupByLibrary {
"group_number_can_be_found" : MessageLookupByLibrary.simpleMessage("Group number can be found..."),
"home" : MessageLookupByLibrary.simpleMessage("Home"),
"hot_sale" : MessageLookupByLibrary.simpleMessage("Hot sale"),
"hour_token" : m14,
"hour_token" : m16,
"igoshow" : MessageLookupByLibrary.simpleMessage("iGoShow"),
"includes" : MessageLookupByLibrary.simpleMessage("Includes"),
"information" : MessageLookupByLibrary.simpleMessage("Information"),
@@ -245,10 +257,11 @@ class MessageLookup extends MessageLookupByLibrary {
"logout" : MessageLookupByLibrary.simpleMessage("Logout"),
"main_content_1" : MessageLookupByLibrary.simpleMessage("Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products."),
"me" : MessageLookupByLibrary.simpleMessage("Me"),
"min_order_amount_token" : m15,
"min_shipping_fee" : m16,
"min_order_amount_token" : m17,
"min_shipping_fee" : m18,
"minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"),
"minute_token" : m17,
"minute_token" : m19,
"mobile" : MessageLookupByLibrary.simpleMessage("mobile"),
"mobile_email_username" : MessageLookupByLibrary.simpleMessage("Mobile, Email or MiniOffice username"),
"mobile_is_required" : MessageLookupByLibrary.simpleMessage("Mobile is required"),
"mobile_number" : MessageLookupByLibrary.simpleMessage("Mobile number"),
@@ -293,6 +306,7 @@ class MessageLookup extends MessageLookupByLibrary {
"ok" : MessageLookupByLibrary.simpleMessage("OK"),
"old_password" : MessageLookupByLibrary.simpleMessage("Old password"),
"online_payment" : MessageLookupByLibrary.simpleMessage("Online payment"),
"open_online_store" : MessageLookupByLibrary.simpleMessage("Open an online store"),
"optional_information" : MessageLookupByLibrary.simpleMessage("Optional Info."),
"order_acceipt" : MessageLookupByLibrary.simpleMessage("Accept"),
"order_again" : MessageLookupByLibrary.simpleMessage("Order again"),
@@ -302,7 +316,7 @@ class MessageLookup extends MessageLookupByLibrary {
"order_detail" : MessageLookupByLibrary.simpleMessage("Order detail"),
"order_fulfillment" : MessageLookupByLibrary.simpleMessage("Order fulfillment"),
"order_info" : MessageLookupByLibrary.simpleMessage("Order info."),
"order_more" : m18,
"order_more" : m20,
"order_number" : MessageLookupByLibrary.simpleMessage("Order No."),
"order_number_copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("Order number copied to clipboard"),
"order_processing" : MessageLookupByLibrary.simpleMessage("Processing"),
@@ -317,30 +331,31 @@ class MessageLookup extends MessageLookupByLibrary {
"password_is_required" : MessageLookupByLibrary.simpleMessage("Password is required."),
"pay" : MessageLookupByLibrary.simpleMessage("Pay"),
"pay_after_meal" : MessageLookupByLibrary.simpleMessage("Pay after meal"),
"pay_amount_token" : m19,
"pay_amount_token" : m21,
"pay_later" : MessageLookupByLibrary.simpleMessage("Pay later"),
"pay_now" : MessageLookupByLibrary.simpleMessage("Pay now"),
"pay_on_deliery" : MessageLookupByLibrary.simpleMessage("Pay on delivery"),
"pay_on_deliery_pickup" : MessageLookupByLibrary.simpleMessage("Pay on delivery or pickup"),
"pay_with" : MessageLookupByLibrary.simpleMessage("Pay with"),
"pay_with_existing_cards" : MessageLookupByLibrary.simpleMessage("Pay with existing cards"),
"pay_with_token" : m20,
"pay_with_token" : m22,
"payment_amount" : MessageLookupByLibrary.simpleMessage("Payment amount"),
"payment_method" : MessageLookupByLibrary.simpleMessage("Payment method"),
"payment_method_not_set" : MessageLookupByLibrary.simpleMessage("No payment method specified. Please pay on delivery or pickup."),
"payment_status" : MessageLookupByLibrary.simpleMessage("Payment status"),
"payment_verification" : MessageLookupByLibrary.simpleMessage("Payment verification"),
"payment_verification_sent" : m21,
"payment_verification_sent" : m23,
"paypal" : MessageLookupByLibrary.simpleMessage("Paypal"),
"pending" : MessageLookupByLibrary.simpleMessage("Pending"),
"percent_discount" : MessageLookupByLibrary.simpleMessage("%OFF"),
"percentage_discount_token" : m22,
"percentage_discount_token2" : m23,
"percentage_discount_token" : m24,
"percentage_discount_token2" : m25,
"pick_a_coupon" : MessageLookupByLibrary.simpleMessage("Pick a coupon"),
"pickup" : MessageLookupByLibrary.simpleMessage("Pickup"),
"pickup_address" : MessageLookupByLibrary.simpleMessage("Pickup address"),
"pickup_at" : MessageLookupByLibrary.simpleMessage("Please pickup at"),
"pickup_discount" : MessageLookupByLibrary.simpleMessage("Pickup discount"),
"place_order_now" : MessageLookupByLibrary.simpleMessage("Place order now"),
"please_enter_coupon_code" : MessageLookupByLibrary.simpleMessage("Please enter a coupon code."),
"please_enter_group_number" : MessageLookupByLibrary.simpleMessage("Please enter your group number."),
"please_login" : MessageLookupByLibrary.simpleMessage("Please login"),
@@ -364,7 +379,7 @@ class MessageLookup extends MessageLookupByLibrary {
"quick_input" : MessageLookupByLibrary.simpleMessage("Quick input"),
"radio_option_is_optional" : MessageLookupByLibrary.simpleMessage("Optional. You can tap Next without selection."),
"radio_option_is_required" : MessageLookupByLibrary.simpleMessage("Option is required. Select an option then tap Next."),
"radio_option_select_token" : m24,
"radio_option_select_token" : m26,
"recalculating" : MessageLookupByLibrary.simpleMessage("Recalculating..."),
"red_coupon" : MessageLookupByLibrary.simpleMessage("Coupon"),
"redeem_coupon" : MessageLookupByLibrary.simpleMessage("Redeem"),
@@ -372,6 +387,7 @@ class MessageLookup extends MessageLookupByLibrary {
"registration" : MessageLookupByLibrary.simpleMessage("Registration"),
"release_to_load_more" : MessageLookupByLibrary.simpleMessage("Release to load more"),
"renew_license" : MessageLookupByLibrary.simpleMessage("Renew license"),
"renew_service_now" : MessageLookupByLibrary.simpleMessage("Renew service now"),
"renewal_fee" : MessageLookupByLibrary.simpleMessage("Renewal fee"),
"reply" : MessageLookupByLibrary.simpleMessage("Reply"),
"reset_password" : MessageLookupByLibrary.simpleMessage("Reset password"),
@@ -384,12 +400,14 @@ class MessageLookup extends MessageLookupByLibrary {
"saturday" : MessageLookupByLibrary.simpleMessage("Saturday"),
"save" : MessageLookupByLibrary.simpleMessage("Save"),
"schedule_delivery" : MessageLookupByLibrary.simpleMessage("Schedule delivery"),
"search" : MessageLookupByLibrary.simpleMessage("Search"),
"search_place" : MessageLookupByLibrary.simpleMessage("Search place"),
"search_product" : MessageLookupByLibrary.simpleMessage("Search product"),
"search_products" : MessageLookupByLibrary.simpleMessage("Search products"),
"select" : MessageLookupByLibrary.simpleMessage("Select"),
"select_a_payment_method" : MessageLookupByLibrary.simpleMessage("Select a payment method"),
"select_a_plan" : MessageLookupByLibrary.simpleMessage("Select a plan"),
"select_a_store" : MessageLookupByLibrary.simpleMessage("Select a store"),
"select_canada_post_shipping_rate" : MessageLookupByLibrary.simpleMessage("Please select Canada Post shipping rate."),
"select_delivery_time" : MessageLookupByLibrary.simpleMessage("Select delivery time"),
"select_document_lanuage" : MessageLookupByLibrary.simpleMessage("Select a language"),
@@ -404,7 +422,7 @@ class MessageLookup extends MessageLookupByLibrary {
"shop" : MessageLookupByLibrary.simpleMessage("Shop"),
"show_less" : MessageLookupByLibrary.simpleMessage("Show less"),
"show_more" : MessageLookupByLibrary.simpleMessage("Show more"),
"sold_per_month_token" : m25,
"sold_per_month_token" : m27,
"specification" : MessageLookupByLibrary.simpleMessage("Specification"),
"store" : MessageLookupByLibrary.simpleMessage("Store"),
"store_closed" : MessageLookupByLibrary.simpleMessage("Store closed"),
@@ -420,13 +438,13 @@ class MessageLookup extends MessageLookupByLibrary {
"submitting" : MessageLookupByLibrary.simpleMessage("Submitting..."),
"submitting_please_wait" : MessageLookupByLibrary.simpleMessage("Submitting, please wait..."),
"subtotal" : MessageLookupByLibrary.simpleMessage("Subtotal"),
"subtotal_token" : m26,
"subtotal_token" : m28,
"success" : MessageLookupByLibrary.simpleMessage("Success"),
"sun" : MessageLookupByLibrary.simpleMessage("Sun"),
"sunday" : MessageLookupByLibrary.simpleMessage("Sunday"),
"support" : MessageLookupByLibrary.simpleMessage("Support"),
"support_ticket" : MessageLookupByLibrary.simpleMessage("Support ticket"),
"table_token" : m27,
"table_token" : m29,
"tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("Tap back again to exit"),
"tax" : MessageLookupByLibrary.simpleMessage("Tax"),
"thank_you_for_your_comment" : MessageLookupByLibrary.simpleMessage("Thank you for your comment."),
@@ -439,12 +457,12 @@ class MessageLookup extends MessageLookupByLibrary {
"thu" : MessageLookupByLibrary.simpleMessage("Thu"),
"thursday" : MessageLookupByLibrary.simpleMessage("Thursday"),
"ticket_created_success" : MessageLookupByLibrary.simpleMessage("Ticket has been created successfully."),
"ticket_number_token" : m28,
"ticket_number_token" : m30,
"today" : MessageLookupByLibrary.simpleMessage("Today"),
"today_with_time" : m29,
"today_with_time" : m31,
"toll_free" : MessageLookupByLibrary.simpleMessage("Toll free: "),
"tomorrow" : MessageLookupByLibrary.simpleMessage("Tomorrow"),
"tomorrow_with_time" : m30,
"tomorrow_with_time" : m32,
"total" : MessageLookupByLibrary.simpleMessage("Total"),
"tue" : MessageLookupByLibrary.simpleMessage("Tue"),
"tuesday" : MessageLookupByLibrary.simpleMessage("Tuesday"),
@@ -469,7 +487,7 @@ class MessageLookup extends MessageLookupByLibrary {
"wechatpay" : MessageLookupByLibrary.simpleMessage("Wechat pay"),
"wed" : MessageLookupByLibrary.simpleMessage("Wed"),
"wednesday" : MessageLookupByLibrary.simpleMessage("Wednesday"),
"weight_token" : m31,
"weight_token" : m33,
"wiki" : MessageLookupByLibrary.simpleMessage("Wiki"),
"wrong_payment_verification_code" : MessageLookupByLibrary.simpleMessage("Wrong payment verification code. Please check and enter again."),
"yes" : MessageLookupByLibrary.simpleMessage("Yes"),

View File

@@ -35,53 +35,57 @@ class MessageLookup extends MessageLookupByLibrary {
static m7(discount) => "-\$${discount}";
static m8(oss) => "${oss}下载";
static m8(domain) => "${domain} (可用)";
static m9(expirationDate) => "${expirationDate}到期";
static m9(domain) => "${domain} (不可用)";
static m10(mon, yer) => "到期:${mon}/${yer}";
static m10(oss) => "${oss}下载";
static m11(name, rate) => "${name}(${rate}%)";
static m11(expirationDate) => "${expirationDate}到期";
static m12(num) => "${num}条回复";
static m12(mon, yer) => "到期:${mon}/${yer}";
static m13(second) => "${second}秒后重试";
static m13(name, rate) => "${name}(${rate}%)";
static m14(hours) => "${Intl.plural(hours, one: '1小时', other: '${hours}小时')}";
static m14(num) => "${num}条回复";
static m15(minamount) => "\$${minamount}起送";
static m15(second) => "${second}秒后重试";
static m16(shipfee) => "配送费\$${shipfee}";
static m16(hours) => "${Intl.plural(hours, one: '1小时', other: '${hours}小时')}";
static m17(minutes) => "${Intl.plural(minutes, one: '1分钟', other: '${minutes}分钟')}";
static m17(minamount) => "\$${minamount}起送";
static m18(minprice) => "还差${minprice}";
static m18(shipfee) => "配送费\$${shipfee}";
static m19(amount) => "马上付款 \$${amount}";
static m19(minutes) => "${Intl.plural(minutes, one: '1分钟', other: '${minutes}分钟')}";
static m20(method) => "使用${method}付款";
static m20(minprice) => "还差${minprice}起送";
static m21(mobile) => "付款码已经发送到您的手机${mobile}。请在下面输入付款码。";
static m21(amount) => "马上付款 \$${amount}";
static m22(discount) => "${discount}%折扣";
static m22(method) => "使用${method}付款";
static m23(amount, discount) => "-\$${amount}(${discount}%折扣)";
static m23(p1, p2) => "付款码已经发送到您的${p1}${p2}。请在下面输入付款码。";
static m24(optionName) => "请选择${optionName}";
static m24(discount) => "${discount}%折扣";
static m25(sold_qty) => " 月售${sold_qty}";
static m25(amount, discount) => "-\$${amount}(${discount}%折扣)";
static m26(subtotal) => "小计:${subtotal}";
static m26(optionName) => "请选择${optionName}";
static m27(num) => "桌号:${num}";
static m27(sold_qty) => " 月售${sold_qty}";
static m28(num) => "票号 #${num}";
static m28(subtotal) => "小计:${subtotal}";
static m29(time) => "今天${time}";
static m29(num) => "桌号:${num}";
static m30(time) => "明天${time}";
static m30(num) => "票号 #${num}";
static m31(weight) => "重量:${weight}";
static m31(time) => "今天${time}";
static m32(time) => "明天${time}";
static m33(weight) => "重量:${weight}";
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
@@ -129,6 +133,7 @@ class MessageLookup extends MessageLookupByLibrary {
"change_nickname" : MessageLookupByLibrary.simpleMessage("修改昵称"),
"change_password" : MessageLookupByLibrary.simpleMessage("修改密码"),
"change_password_desc" : MessageLookupByLibrary.simpleMessage("请输入旧密码和希望的新密码。"),
"check_domain_name" : MessageLookupByLibrary.simpleMessage("检查是否可用"),
"check_option_is_optional" : MessageLookupByLibrary.simpleMessage("可选选项。如果不选择可以直接点下一步。"),
"check_option_is_required" : MessageLookupByLibrary.simpleMessage("选项必选。选择至少一项再点击下一步。"),
"check_option_select_token" : m3,
@@ -150,6 +155,7 @@ class MessageLookup extends MessageLookupByLibrary {
"contact_us" : MessageLookupByLibrary.simpleMessage("联系我们"),
"copy" : MessageLookupByLibrary.simpleMessage("复制"),
"coupons" : MessageLookupByLibrary.simpleMessage("优惠券"),
"create_a_online_store" : MessageLookupByLibrary.simpleMessage("开网店"),
"credit_card" : MessageLookupByLibrary.simpleMessage("信用卡"),
"credit_coupon" : MessageLookupByLibrary.simpleMessage("红包/抵用券"),
"credit_debit_card" : MessageLookupByLibrary.simpleMessage("信用卡或银行卡"),
@@ -172,9 +178,13 @@ class MessageLookup extends MessageLookupByLibrary {
"discount_amount_token" : m7,
"document_langage" : MessageLookupByLibrary.simpleMessage("文档语言"),
"document_type" : MessageLookupByLibrary.simpleMessage("文件类型"),
"domain_available_token" : m8,
"domain_name" : MessageLookupByLibrary.simpleMessage("域名"),
"domain_unavailable_token" : m9,
"domains_separated_comma" : MessageLookupByLibrary.simpleMessage("逗号分开多个域名"),
"dont_use" : MessageLookupByLibrary.simpleMessage("不使用"),
"download" : MessageLookupByLibrary.simpleMessage("下载"),
"download_with_token" : m8,
"download_with_token" : m10,
"downloads" : MessageLookupByLibrary.simpleMessage("下载"),
"edit_address" : MessageLookupByLibrary.simpleMessage("修改地址"),
"email" : MessageLookupByLibrary.simpleMessage("电子邮箱"),
@@ -188,22 +198,24 @@ class MessageLookup extends MessageLookupByLibrary {
"english" : MessageLookupByLibrary.simpleMessage("英文"),
"enter_coupon_code" : MessageLookupByLibrary.simpleMessage("输入红包号码"),
"enter_delivery_address" : MessageLookupByLibrary.simpleMessage("输入送货地址"),
"enter_desired_domain" : MessageLookupByLibrary.simpleMessage("您想要的域名"),
"enter_keyword" : MessageLookupByLibrary.simpleMessage("输入关键字"),
"enter_mobile_or_email" : MessageLookupByLibrary.simpleMessage("输入手机号码或电子邮箱地址"),
"enter_new_nickname" : MessageLookupByLibrary.simpleMessage("输入新昵称"),
"enter_product_keyword" : MessageLookupByLibrary.simpleMessage("输入产品关键字"),
"error" : MessageLookupByLibrary.simpleMessage("错误"),
"error_read_file" : MessageLookupByLibrary.simpleMessage("读取文件过程中出错。"),
"expiration_date" : MessageLookupByLibrary.simpleMessage("到期日期"),
"expiration_date_token" : m9,
"expire_token" : m10,
"expiration_date_token" : m11,
"expire_token" : m12,
"expired_at" : MessageLookupByLibrary.simpleMessage("到期日期"),
"extra_fee_token" : m11,
"extra_fee_token" : m13,
"fax" : MessageLookupByLibrary.simpleMessage("传真"),
"feature_not_available_web" : MessageLookupByLibrary.simpleMessage("该功能在网页版上不能用。请下载App版本。"),
"featured_product" : MessageLookupByLibrary.simpleMessage("特色产品"),
"finish" : MessageLookupByLibrary.simpleMessage("完成"),
"follow_ups" : MessageLookupByLibrary.simpleMessage("跟进"),
"followups_token" : m12,
"followups_token" : m14,
"forgot_password" : MessageLookupByLibrary.simpleMessage("忘记密码"),
"forgot_password_description" : MessageLookupByLibrary.simpleMessage("输入您注册时用的Email或手机号码然后点击获取验证码 按钮。"),
"forgot_password_question" : MessageLookupByLibrary.simpleMessage("忘记密码?"),
@@ -215,7 +227,7 @@ class MessageLookup extends MessageLookupByLibrary {
"general_coupon" : MessageLookupByLibrary.simpleMessage("通用优惠券"),
"get_code" : MessageLookupByLibrary.simpleMessage("获取验证码"),
"get_code_again" : MessageLookupByLibrary.simpleMessage("重新获取验证码"),
"get_code_token" : m13,
"get_code_token" : m15,
"get_coupon" : MessageLookupByLibrary.simpleMessage("获取红包"),
"get_picture" : MessageLookupByLibrary.simpleMessage("获取图片"),
"get_picture_from" : MessageLookupByLibrary.simpleMessage("从...获取图片"),
@@ -224,7 +236,7 @@ class MessageLookup extends MessageLookupByLibrary {
"group_number_can_be_found" : MessageLookupByLibrary.simpleMessage("按如下图找到集团号码..."),
"home" : MessageLookupByLibrary.simpleMessage("首页"),
"hot_sale" : MessageLookupByLibrary.simpleMessage("热卖"),
"hour_token" : m14,
"hour_token" : m16,
"igoshow" : MessageLookupByLibrary.simpleMessage("iGoShow"),
"includes" : MessageLookupByLibrary.simpleMessage("包含"),
"information" : MessageLookupByLibrary.simpleMessage("信息"),
@@ -243,10 +255,11 @@ class MessageLookup extends MessageLookupByLibrary {
"logout" : MessageLookupByLibrary.simpleMessage("登出"),
"main_content_1" : MessageLookupByLibrary.simpleMessage("自从1999年来我们一直致力于开发完整的强大的销售系统帮助了上千小企业平滑的处理销售业务。当前我们有两个主要的产品。"),
"me" : MessageLookupByLibrary.simpleMessage("我的"),
"min_order_amount_token" : m15,
"min_shipping_fee" : m16,
"min_order_amount_token" : m17,
"min_shipping_fee" : m18,
"minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"),
"minute_token" : m17,
"minute_token" : m19,
"mobile" : MessageLookupByLibrary.simpleMessage("手机"),
"mobile_email_username" : MessageLookupByLibrary.simpleMessage("手机号码Email或MiniOffice用户名"),
"mobile_is_required" : MessageLookupByLibrary.simpleMessage("手机号码必填"),
"mobile_number" : MessageLookupByLibrary.simpleMessage("手机号码"),
@@ -290,6 +303,7 @@ class MessageLookup extends MessageLookupByLibrary {
"ok" : MessageLookupByLibrary.simpleMessage("确定"),
"old_password" : MessageLookupByLibrary.simpleMessage("旧密码"),
"online_payment" : MessageLookupByLibrary.simpleMessage("在线付款"),
"open_online_store" : MessageLookupByLibrary.simpleMessage("开网店"),
"optional_information" : MessageLookupByLibrary.simpleMessage("可选填信息"),
"order_acceipt" : MessageLookupByLibrary.simpleMessage("已接单"),
"order_again" : MessageLookupByLibrary.simpleMessage("再来一单"),
@@ -299,7 +313,7 @@ class MessageLookup extends MessageLookupByLibrary {
"order_detail" : MessageLookupByLibrary.simpleMessage("订单详情"),
"order_fulfillment" : MessageLookupByLibrary.simpleMessage("订单完成度"),
"order_info" : MessageLookupByLibrary.simpleMessage("订单信息"),
"order_more" : m18,
"order_more" : m20,
"order_number" : MessageLookupByLibrary.simpleMessage("订单号码"),
"order_number_copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("订单号码复制到剪切板"),
"order_processing" : MessageLookupByLibrary.simpleMessage("准备中"),
@@ -314,30 +328,31 @@ class MessageLookup extends MessageLookupByLibrary {
"password_is_required" : MessageLookupByLibrary.simpleMessage("密码必填。"),
"pay" : MessageLookupByLibrary.simpleMessage("付款"),
"pay_after_meal" : MessageLookupByLibrary.simpleMessage("餐后付款"),
"pay_amount_token" : m19,
"pay_amount_token" : m21,
"pay_later" : MessageLookupByLibrary.simpleMessage("稍后付款"),
"pay_now" : MessageLookupByLibrary.simpleMessage("去支付"),
"pay_on_deliery" : MessageLookupByLibrary.simpleMessage("到货付款"),
"pay_on_deliery_pickup" : MessageLookupByLibrary.simpleMessage("自提或到货付款"),
"pay_with" : MessageLookupByLibrary.simpleMessage("使用"),
"pay_with_existing_cards" : MessageLookupByLibrary.simpleMessage("用现有的卡付款"),
"pay_with_token" : m20,
"pay_with_token" : m22,
"payment_amount" : MessageLookupByLibrary.simpleMessage("付款金额"),
"payment_method" : MessageLookupByLibrary.simpleMessage("付款方式"),
"payment_method_not_set" : MessageLookupByLibrary.simpleMessage("没有指定付款方式,请货到付款或自提付款。"),
"payment_status" : MessageLookupByLibrary.simpleMessage("付款状态"),
"payment_verification" : MessageLookupByLibrary.simpleMessage("付款验证"),
"payment_verification_sent" : m21,
"payment_verification_sent" : m23,
"paypal" : MessageLookupByLibrary.simpleMessage("Paypal"),
"pending" : MessageLookupByLibrary.simpleMessage("待接单"),
"percent_discount" : MessageLookupByLibrary.simpleMessage("%折扣"),
"percentage_discount_token" : m22,
"percentage_discount_token2" : m23,
"percentage_discount_token" : m24,
"percentage_discount_token2" : m25,
"pick_a_coupon" : MessageLookupByLibrary.simpleMessage("使用红包"),
"pickup" : MessageLookupByLibrary.simpleMessage("到店自提"),
"pickup_address" : MessageLookupByLibrary.simpleMessage("自提地址"),
"pickup_at" : MessageLookupByLibrary.simpleMessage("自提地址"),
"pickup_discount" : MessageLookupByLibrary.simpleMessage("自提折扣"),
"place_order_now" : MessageLookupByLibrary.simpleMessage("马上下单"),
"please_enter_coupon_code" : MessageLookupByLibrary.simpleMessage("请输入红包号码。"),
"please_enter_group_number" : MessageLookupByLibrary.simpleMessage("请输入您的集团号码。"),
"please_login" : MessageLookupByLibrary.simpleMessage("请登陆"),
@@ -361,7 +376,7 @@ class MessageLookup extends MessageLookupByLibrary {
"quick_input" : MessageLookupByLibrary.simpleMessage("快速输入"),
"radio_option_is_optional" : MessageLookupByLibrary.simpleMessage("可选选项。如果不选择可以直接点下一步。"),
"radio_option_is_required" : MessageLookupByLibrary.simpleMessage("选项必选。选择一个选项后点下一步。"),
"radio_option_select_token" : m24,
"radio_option_select_token" : m26,
"recalculating" : MessageLookupByLibrary.simpleMessage("运算中..."),
"red_coupon" : MessageLookupByLibrary.simpleMessage("红包"),
"redeem_coupon" : MessageLookupByLibrary.simpleMessage("去使用"),
@@ -369,6 +384,7 @@ class MessageLookup extends MessageLookupByLibrary {
"registration" : MessageLookupByLibrary.simpleMessage("注册"),
"release_to_load_more" : MessageLookupByLibrary.simpleMessage("松开载入"),
"renew_license" : MessageLookupByLibrary.simpleMessage("证书续期"),
"renew_service_now" : MessageLookupByLibrary.simpleMessage("马上续期"),
"renewal_fee" : MessageLookupByLibrary.simpleMessage("续订费用"),
"reply" : MessageLookupByLibrary.simpleMessage("回复"),
"reset_password" : MessageLookupByLibrary.simpleMessage("重置密码"),
@@ -381,12 +397,14 @@ class MessageLookup extends MessageLookupByLibrary {
"saturday" : MessageLookupByLibrary.simpleMessage("星期六"),
"save" : MessageLookupByLibrary.simpleMessage("保存"),
"schedule_delivery" : MessageLookupByLibrary.simpleMessage("预约送货时间"),
"search" : MessageLookupByLibrary.simpleMessage("搜索"),
"search_place" : MessageLookupByLibrary.simpleMessage("搜索地址"),
"search_product" : MessageLookupByLibrary.simpleMessage("搜索产品"),
"search_products" : MessageLookupByLibrary.simpleMessage("搜索产品"),
"select" : MessageLookupByLibrary.simpleMessage("选取"),
"select_a_payment_method" : MessageLookupByLibrary.simpleMessage("选择付款方式"),
"select_a_plan" : MessageLookupByLibrary.simpleMessage("选择一个计划"),
"select_a_store" : MessageLookupByLibrary.simpleMessage("选择一个店子"),
"select_canada_post_shipping_rate" : MessageLookupByLibrary.simpleMessage("请选择加拿大邮政运费。"),
"select_delivery_time" : MessageLookupByLibrary.simpleMessage("选择配送时间"),
"select_document_lanuage" : MessageLookupByLibrary.simpleMessage("选择一种语言"),
@@ -401,7 +419,7 @@ class MessageLookup extends MessageLookupByLibrary {
"shop" : MessageLookupByLibrary.simpleMessage("线上购买"),
"show_less" : MessageLookupByLibrary.simpleMessage("显示更少"),
"show_more" : MessageLookupByLibrary.simpleMessage("显示更多"),
"sold_per_month_token" : m25,
"sold_per_month_token" : m27,
"specification" : MessageLookupByLibrary.simpleMessage("规格"),
"store" : MessageLookupByLibrary.simpleMessage("店家"),
"store_closed" : MessageLookupByLibrary.simpleMessage("商店已关"),
@@ -417,13 +435,13 @@ class MessageLookup extends MessageLookupByLibrary {
"submitting" : MessageLookupByLibrary.simpleMessage("提交中..."),
"submitting_please_wait" : MessageLookupByLibrary.simpleMessage("提交中,清稍候..."),
"subtotal" : MessageLookupByLibrary.simpleMessage("小计"),
"subtotal_token" : m26,
"subtotal_token" : m28,
"success" : MessageLookupByLibrary.simpleMessage("成功"),
"sun" : MessageLookupByLibrary.simpleMessage("周日"),
"sunday" : MessageLookupByLibrary.simpleMessage("星期日"),
"support" : MessageLookupByLibrary.simpleMessage("技术支持"),
"support_ticket" : MessageLookupByLibrary.simpleMessage("客户提问"),
"table_token" : m27,
"table_token" : m29,
"tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("再次点击返回退出"),
"tax" : MessageLookupByLibrary.simpleMessage("税费"),
"thank_you_for_your_comment" : MessageLookupByLibrary.simpleMessage("谢谢您的评价。"),
@@ -435,12 +453,12 @@ class MessageLookup extends MessageLookupByLibrary {
"thu" : MessageLookupByLibrary.simpleMessage("周四"),
"thursday" : MessageLookupByLibrary.simpleMessage("星期四"),
"ticket_created_success" : MessageLookupByLibrary.simpleMessage("支持票成功创建。"),
"ticket_number_token" : m28,
"ticket_number_token" : m30,
"today" : MessageLookupByLibrary.simpleMessage("今天"),
"today_with_time" : m29,
"today_with_time" : m31,
"toll_free" : MessageLookupByLibrary.simpleMessage("无费号码:"),
"tomorrow" : MessageLookupByLibrary.simpleMessage("明天"),
"tomorrow_with_time" : m30,
"tomorrow_with_time" : m32,
"total" : MessageLookupByLibrary.simpleMessage("总计"),
"tue" : MessageLookupByLibrary.simpleMessage("周二"),
"tuesday" : MessageLookupByLibrary.simpleMessage("星期二"),
@@ -465,7 +483,7 @@ class MessageLookup extends MessageLookupByLibrary {
"wechatpay" : MessageLookupByLibrary.simpleMessage("微信支付"),
"wed" : MessageLookupByLibrary.simpleMessage("周三"),
"wednesday" : MessageLookupByLibrary.simpleMessage("星期三"),
"weight_token" : m31,
"weight_token" : m33,
"wiki" : MessageLookupByLibrary.simpleMessage("维基"),
"wrong_payment_verification_code" : MessageLookupByLibrary.simpleMessage("错误的付款码,请查证后再输入。"),
"yes" : MessageLookupByLibrary.simpleMessage("是的"),

View File

@@ -3439,13 +3439,13 @@ class S {
);
}
/// `Payment verification code has been sent to your mobile phone {mobile}. Please enter the verification code below.`
String payment_verification_sent(Object mobile) {
/// `Payment verification code has been sent to your {p1} {p2}. Please enter the verification code below.`
String payment_verification_sent(Object p1, Object p2) {
return Intl.message(
'Payment verification code has been sent to your mobile phone $mobile. Please enter the verification code below.',
'Payment verification code has been sent to your $p1 $p2. Please enter the verification code below.',
name: 'payment_verification_sent',
desc: '',
args: [mobile],
args: [p1, p2],
);
}
@@ -3978,6 +3978,146 @@ class S {
args: [],
);
}
/// `Enter keyword`
String get enter_keyword {
return Intl.message(
'Enter keyword',
name: 'enter_keyword',
desc: '',
args: [],
);
}
/// `Search`
String get search {
return Intl.message(
'Search',
name: 'search',
desc: '',
args: [],
);
}
/// `Open an online store`
String get create_a_online_store {
return Intl.message(
'Open an online store',
name: 'create_a_online_store',
desc: '',
args: [],
);
}
/// `Open an online store`
String get open_online_store {
return Intl.message(
'Open an online store',
name: 'open_online_store',
desc: '',
args: [],
);
}
/// `Select a store`
String get select_a_store {
return Intl.message(
'Select a store',
name: 'select_a_store',
desc: '',
args: [],
);
}
/// `Domain name`
String get domain_name {
return Intl.message(
'Domain name',
name: 'domain_name',
desc: '',
args: [],
);
}
/// `Your desired domain name`
String get enter_desired_domain {
return Intl.message(
'Your desired domain name',
name: 'enter_desired_domain',
desc: '',
args: [],
);
}
/// `Check availability`
String get check_domain_name {
return Intl.message(
'Check availability',
name: 'check_domain_name',
desc: '',
args: [],
);
}
/// `Domains separated by comma`
String get domains_separated_comma {
return Intl.message(
'Domains separated by comma',
name: 'domains_separated_comma',
desc: '',
args: [],
);
}
/// `{domain} (available)`
String domain_available_token(Object domain) {
return Intl.message(
'$domain (available)',
name: 'domain_available_token',
desc: '',
args: [domain],
);
}
/// `{domain} (unavailable)`
String domain_unavailable_token(Object domain) {
return Intl.message(
'$domain (unavailable)',
name: 'domain_unavailable_token',
desc: '',
args: [domain],
);
}
/// `Place order now`
String get place_order_now {
return Intl.message(
'Place order now',
name: 'place_order_now',
desc: '',
args: [],
);
}
/// `mobile`
String get mobile {
return Intl.message(
'mobile',
name: 'mobile',
desc: '',
args: [],
);
}
/// `Renew service now`
String get renew_service_now {
return Intl.message(
'Renew service now',
name: 'renew_service_now',
desc: '',
args: [],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@@ -339,7 +339,7 @@
"confirmation": "Confirmation",
"are_you_sure_to_remove_the_card": "Are you srue you want to remove the credit card?",
"payment_verification": "Payment verification",
"payment_verification_sent": "Payment verification code has been sent to your mobile phone {mobile}. Please enter the verification code below.",
"payment_verification_sent": "Payment verification code has been sent to your {p1} {p2}. Please enter the verification code below.",
"wrong_payment_verification_code": "Wrong payment verification code. Please check and enter again.",
"pay_with": "Pay with",
"pay_with_token": "Pay with {method}",
@@ -392,5 +392,19 @@
"your_group": "Your group",
"current_plan": "Current plan",
"select_a_plan": "Select a plan",
"price": "Price"
"price": "Price",
"enter_keyword": "Enter keyword",
"search": "Search",
"create_a_online_store": "Open an online store",
"open_online_store": "Open an online store",
"select_a_store": "Select a store",
"domain_name": "Domain name",
"enter_desired_domain": "Your desired domain name",
"check_domain_name": "Check availability",
"domains_separated_comma": "Domains separated by comma",
"domain_available_token": "{domain} (available)",
"domain_unavailable_token": "{domain} (unavailable)",
"place_order_now": "Place order now",
"mobile": "mobile",
"renew_service_now": "Renew service now"
}

View File

@@ -334,7 +334,7 @@
"confirmation": "请确定",
"are_you_sure_to_remove_the_card": "您确定要移除该信用卡吗?",
"payment_verification": "付款验证",
"payment_verification_sent": "付款码已经发送到您的手机{mobile}。请在下面输入付款码。",
"payment_verification_sent": "付款码已经发送到您的{p1}{p2}。请在下面输入付款码。",
"wrong_payment_verification_code": "错误的付款码,请查证后再输入。",
"pay_with": "使用",
"pay_with_token": "使用{method}付款",
@@ -388,5 +388,19 @@
"current_plan": "当前计划",
"select_a_plan": "选择一个计划",
"price": "价格",
"no_ticket_yet": "还没有支持票。 如果您有任何疑问/问题,请点击上方的加号图标以创建支持票。"
"no_ticket_yet": "还没有支持票。 如果您有任何疑问/问题,请点击上方的加号图标以创建支持票。",
"enter_keyword": "输入关键字",
"search": "搜索",
"create_a_online_store": "开网店",
"open_online_store": "开网店",
"select_a_store": "选择一个店子",
"domain_name": "域名",
"enter_desired_domain": "您想要的域名",
"check_domain_name": "检查是否可用",
"domains_separated_comma": "逗号分开多个域名",
"domain_available_token": "{domain} (可用)",
"domain_unavailable_token": "{domain} (不可用)",
"place_order_now": "马上下单",
"mobile": "手机",
"renew_service_now": "马上续期"
}

View File

@@ -10,6 +10,7 @@ import 'package:flutter_wisetronic/pages/buy_service.dart';
import 'package:geolocator/geolocator.dart' as geolocator;
import 'package:url_strategy/url_strategy.dart';
import 'models/located_address.dart';
import 'pages/create_online_store_1.dart';
import 'pages/me.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:splashscreen/splashscreen.dart';
@@ -28,6 +29,7 @@ import 'store/store.dart';
import 'utils/configure_nonweb.dart' if (dart.library.html) 'utils/configure_web.dart';
import 'utils/http_util.dart';
import 'utils/util_io.dart' if (dart.library.html) 'utils/util_web.dart';
import 'utils/utils.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
@@ -42,6 +44,7 @@ class MyApp extends StatelessWidget {
MyApp() {
Routes.configure();
Utils().init();
Util().init();
// getCurrentPosition();
}
@@ -142,16 +145,42 @@ class MyApp extends StatelessWidget {
builder: (BuildContext context) => Me()
);
}
if (pathElements[1] == 'service-policy') {
return MaterialPageRoute(
builder: (BuildContext context) =>
PlainPage(
'service-policy',
businessId: 310,
),
);
}
if (pathElements[1] == 'privacy-policy') {
return MaterialPageRoute(
builder: (BuildContext context) =>
PlainPage(
'privacy-policy',
// businessId: Constants.BUSINESS_ID,
businessId: 310,
),
);
}
if (pathElements[1] == 'return-policy') {
return MaterialPageRoute(
builder: (BuildContext context) =>
PlainPage(
'return-policy',
businessId: 310,
),
);
}
if (pathElements[1] == 'end-user-license-agreement') {
return MaterialPageRoute(
builder: (BuildContext context) =>
PlainPage(
'end-user-license-agreement',
businessId: 310,
),
);
}
if (pathElements[1] == 'renew-minioffice') {
return MaterialPageRoute(builder: (BuildContext context) =>
RenewMiniOffice(int.parse(pathElements[2]))
@@ -162,6 +191,11 @@ class MyApp extends StatelessWidget {
BuyService(int.parse(pathElements[2]), pathElements[3])
);
}
if (pathElements[1] == 'contact-stores') {
return MaterialPageRoute(builder: (BuildContext context) =>
CreateOnlineStore1()
);
}
return MaterialPageRoute(
builder: (BuildContext context) =>
Home(title: Constants.APP_TITLE,),

22
lib/models/group.dart Normal file
View File

@@ -0,0 +1,22 @@
import 'dart:convert';
class Group {
int id;
String name;
Group.fromJson(Map<String, dynamic> json) :
id = json['id'],
name = json['name'];
Map<String, dynamic> toJson() => {
'id': id,
'name': name
};
@override
String toString() {
return json.encode(this);
}
}

View File

@@ -14,6 +14,7 @@ class Product {
String description;
String detailDescription;
String imagePath;
String secondImagePath;
double monthSales;
int rate;
double leftNum;
@@ -30,26 +31,28 @@ class Product {
this.price = price;
this.description = description;
this.imagePath = imagePath;
this.secondImagePath = secondImagePath;
this.productAttributes = productAttributes;
}
Product.fromJson(Map<String, dynamic> json)
: id = json['id'],
businessId = json['business_id'],
categoryId = json['category_id'],
name = json['name'],
price = double.parse(json['price'].toString()),
regularPrice = double.parse(json['regular_price'].toString()),
description = json['description'],
detailDescription = json['detail_description'],
imagePath = json['image_path'],
monthSales = json['month_sales'] != null ? double.parse(json['month_sales'].toString()) : 0.0,
rate = json['rate'],
leftNum = json['left_num'] != null ? double.parse(json['left_num'].toString()) : 0.0,
productAttributes = json['productattributes'] != null ? (json['productattributes'] as List).map((i) => ProductAttribute.fromJson(i)).toList() : [],
nonInventory = json['non_inventory'],
extraData = json['extra_data'],
subproducts = json['subproducts'] != null ? (json['subproducts'] as List).map((e) => Subproduct.fromJson(e)).toList() : [];
: id = json['id'],
businessId = json['business_id'],
categoryId = json['category_id'],
name = json['name'],
price = double.parse(json['price'].toString()),
regularPrice = double.parse(json['regular_price'].toString()),
description = json['description'],
detailDescription = json['detail_description'],
imagePath = json['image_path'],
secondImagePath = json['second_image_path'],
monthSales = json['month_sales'] != null ? double.parse(json['month_sales'].toString()) : 0.0,
rate = json['rate'],
leftNum = json['left_num'] != null ? double.parse(json['left_num'].toString()) : 0.0,
productAttributes = json['productattributes'] != null ? (json['productattributes'] as List).map((i) => ProductAttribute.fromJson(i)).toList() : [],
nonInventory = json['non_inventory'],
extraData = json['extra_data'],
subproducts = json['subproducts'] != null ? (json['subproducts'] as List).map((e) => Subproduct.fromJson(e)).toList() : [];
Map<String, dynamic> toJson() => {
'id': id,
@@ -61,6 +64,7 @@ class Product {
'description': description,
'detail_description': detailDescription,
'image_path': imagePath,
'second_image_path': secondImagePath,
'month_sales': monthSales,
'rate': rate,
'left_num': leftNum,

View File

@@ -19,8 +19,10 @@ import '../widgets/mobile/mobile_renew_license.dart';
class BuyService extends StatefulWidget {
final int gid;
final String serviceName;
final String domain;
final int sid;
const BuyService(this.gid, this.serviceName, {Key key}) :
const BuyService(this.gid, this.serviceName, {Key key, this.domain, this.sid = 0}) :
super(key: key);
@override
@@ -66,8 +68,13 @@ class BuyServiceState extends State<BuyService> {
HttpUtil.httpGet(
'v1/get-buy-service-info/${widget.serviceName}/${widget.gid}',
businessId: Constants.BUSINESS_ID,
queryParameters: {
'store_id': '${widget.sid}',
}
).then((value) {
data = value;
data['domain'] = widget.domain;
print('data: $data');
setState(() {});
}).onError((error, stackTrace) {
Utils.showMessageDialog(context, error);

View File

@@ -22,7 +22,7 @@ class ChangeMobileOrEmail extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: isMobile ? S.of(context).change_mobile : S.of(context).change_email,
back: true,
breadCrumbs: [

View File

@@ -20,7 +20,7 @@ class ChangePassword extends StatelessWidget {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).change_password,
back: true,
breadCrumbs: [

View File

@@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/store/actions.dart';
import 'package:flutter_wisetronic/store/store.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../constants.dart';
import '../routes.dart';
import '../widgets/desktop/create_online_store_1.dart' as desktop;
import '../widgets/mobile/create_online_store_1.dart' as mobile;
class CreateOnlineStore1 extends StatefulWidget {
const CreateOnlineStore1({Key key}) :
super(key: key);
@override
State<StatefulWidget> createState() => CreateOnlineStore1State();
}
class CreateOnlineStore1State extends State<CreateOnlineStore1> {
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
if (store.state.user == null) {
store.dispatch(UpdateRedirectRoute('/contact-stores'));
Routes.router.navigateTo(context, '/login', replace: true);
return;
}
});
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
ScreenTypeLayout(
mobile: mobile.CreateOnlineStore1(Constants.BUSINESS_ID),
tablet: desktop.CreateOnlineStore1(Constants.BUSINESS_ID),
desktop: desktop.CreateOnlineStore1(Constants.BUSINESS_ID),
),
);
}
@override
void initState() {
super.initState();
}
}

View File

@@ -50,7 +50,7 @@ class DownloadState extends State<Download> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).download,
back: true,
breadCrumbs: [BreadCrumb(S.of(context).downloads, null)],

View File

@@ -19,7 +19,7 @@ class ForgotPassword extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).forgot_password,
back: true,
breadCrumbs: [

View File

@@ -70,7 +70,7 @@ class HomeState extends State<Home> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(),
appBar: MiniNavigationBar(),
drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null,
body: DoubleBackToCloseAppWrapper(
child: ScreenTypeLayout(

View File

@@ -46,7 +46,7 @@ class IGoShowLearnMoreState extends State<IGoShowLearnMore> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).igoshow,
back: true,
breadCrumbs: [

View File

@@ -41,7 +41,7 @@ class LoginState extends State<Login> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).login,
back: true,
breadCrumbs: [

View File

@@ -42,7 +42,7 @@ class MeState extends State<Me> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: sizingInformation.isMobile? null : NavigationBar(
appBar: sizingInformation.isMobile? null : MiniNavigationBar(
title: S.of(context).me,
back: true,
breadCrumbs: [

View File

@@ -47,7 +47,7 @@ class MiniPosLearnMoreState extends State<MiniPosLearnMore> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).minipos,
back: true,
breadCrumbs: [

View File

@@ -43,7 +43,7 @@ class NewTicketState extends State<NewTicket> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).new_ticket,
back: true,
breadCrumbs: [

View File

@@ -19,7 +19,7 @@ class NewUser extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).registration,
back: true,
breadCrumbs: [

View File

@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/models/business.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../widgets/desktop/product_search.dart' as desktop;
import '../widgets/mobile/product_search.dart' as mobile;
class ProductSearch extends StatelessWidget {
final Business business;
const ProductSearch(this.business, {Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
ScreenTypeLayout(
mobile: mobile.ProductSearch(business),
tablet: desktop.ProductSearch(business),
desktop: desktop.ProductSearch(business),
),
);
}
}

View File

@@ -21,7 +21,7 @@ class ResetPassword extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).reset_password,
back: true,
breadCrumbs: [

View File

@@ -21,7 +21,7 @@ class SetPassword extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).set_password,
back: true,
breadCrumbs: [

View File

@@ -1,55 +1,44 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/events/eventbus.dart';
import 'package:flutter_wisetronic/events/events.dart';
import 'package:flutter_wisetronic/generated/l10n.dart';
import 'package:flutter_wisetronic/models/cart_info.dart';
import 'package:flutter_wisetronic/models/cart_line_item.dart';
import 'package:flutter_wisetronic/models/product.dart';
import 'package:flutter_wisetronic/utils/utils.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../constants.dart';
import '../store/actions.dart';
import '../store/store.dart';
import '../widgets/desktop/desktop_shop.dart';
import '../widgets/mobile/mobile_shop.dart';
import '../../utils/utils.dart';
import '../widgets/desktop/shop.dart' as desktop;
import '../widgets/mobile/shop.dart' as mobile;
class Shop extends StatefulWidget {
final int businessId;
const Shop({this.businessId = Constants.BUSINESS_ID, Key key}) :
super(key: key);
const Shop({this.businessId, Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => ShopState();
}
class ShopState extends State<Shop> {
StreamSubscription onProductWillAddToCartSubscription;
StreamSubscription onProductWillRemoveFromCartSubscription;
@override
Widget build(BuildContext context) {
store.dispatch(UpdateContext(context));
int _businessId =
widget.businessId == null ? Utils.getBusinessId() : widget.businessId;
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
ScreenTypeLayout(
mobile: MobileShop(businessId: widget.businessId,),
tablet: DesktopShop(businessId: widget.businessId,),
desktop: DesktopShop(businessId: widget.businessId,),
),
builder: (context, sizingInformation) => ScreenTypeLayout(
mobile: mobile.Shop(
businessId: _businessId,
),
tablet: desktop.Shop(
businessId: _businessId,
),
desktop: desktop.Shop(
businessId: _businessId,
),
),
);
}
@override
void dispose() {
onProductWillAddToCartSubscription?.cancel();
onProductWillRemoveFromCartSubscription?.cancel();
super.dispose();
print("shop parent dispose");
}
@@ -57,137 +46,5 @@ class ShopState extends State<Shop> {
@override
void initState() {
super.initState();
onProductWillAddToCartSubscription =
eventBus.on<OnProductWillAddToCart>().listen((event) {
if (mounted) {
CartInfo cartInfo =
Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
if (cartInfo == null || cartInfo.productList.length == 0) {
cartInfo = CartInfo();
cartInfo.id = 0;
cartInfo.amountPaid = 0.0;
cartInfo.businessInfo = event.business;
cartInfo.extraFeeList = [];
cartInfo.discountList = [];
CartLineItem lineItem = Utils.newCartLineItem(
id: 0,
price: event.price,
product: event.product,
name: event.product.name,
description: event.description,
quantity: 1.0);
cartInfo.productList = [lineItem];
Utils.addSubproductToCard(cartInfo, lineItem);
store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
} else {
if (event.product.productAttributes.length > 0) {
CartLineItem lineItem = Utils.newCartLineItem(
id: 0,
price: event.price,
product: event.product,
name: event.product.name,
description: event.description,
quantity: 1.0);
cartInfo.productList.add(lineItem);
Utils.addSubproductToCard(cartInfo, lineItem);
store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
} else {
int found = -1;
for (var i = 0; i < cartInfo.productList.length; i++) {
if (event.product.id == cartInfo.productList[i].product.id) {
found = i;
break;
}
}
if (found == -1) {
CartLineItem lineItem = Utils.newCartLineItem(
id: 0,
price: event.price,
product: event.product,
name: event.product.name,
description: event.description,
quantity: 1.0);
cartInfo.productList.add(lineItem);
Utils.addSubproductToCard(cartInfo, lineItem);
store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
} else {
if (cartInfo.productList[found].quantity + 1.0 >
event.product.leftNum) {
Fluttertoast.showToast(
msg: S.of(context).product_insufficient,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white);
} else {
cartInfo.productList[found].quantity += 1;
Utils.addSubproductQty(cartInfo, cartInfo.productList[found]);
store.dispatch(new UpdateCartInfo(
Utils.addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
}
}
}
}
}
});
onProductWillRemoveFromCartSubscription =
eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
if (mounted) {
CartInfo cartInfo =
Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
if (cartInfo != null) {
if (cartInfo.productList.length > 0) {
if (event.productListIndex != -1) {
if (cartInfo.productList[event.productListIndex].quantity <= 1) {
String uuid = cartInfo.productList[event.productListIndex].uuid;
cartInfo.productList.removeAt(event.productListIndex);
Utils.removeSubproduct(cartInfo, uuid);
} else {
cartInfo.productList[event.productListIndex].quantity -= 1;
Utils.addSubproductQty(cartInfo, cartInfo.productList[event.productListIndex], remove: true);
}
} else {
int productListIndex = -1;
for (var i = 0; i < cartInfo.productList.length; i++) {
if (cartInfo.productList[i].product.id == event.product.id) {
productListIndex = i;
break;
}
}
if (productListIndex != -1) {
if (cartInfo.productList[productListIndex].quantity <= 1) {
String uuid = cartInfo.productList[productListIndex].uuid;
cartInfo.productList.removeAt(productListIndex);
Utils.removeSubproduct(cartInfo, uuid);
} else {
cartInfo.productList[productListIndex].quantity -= 1;
Utils.addSubproductQty(cartInfo, cartInfo.productList[productListIndex], remove: true);
}
}
}
}
if (cartInfo.productList.length <= 0) {
store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList(
store.state.cartInfos, cartInfo)));
} else {
store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
}
eventBus.fire(new OnCartInfoUpdated());
}
}
});
}
}

View File

@@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/widgets/desktop/desktop_store_product_search.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../constants.dart';
import '../generated/l10n.dart';
import '../models/business.dart';
import '../widgets/desktop/desktop_store_product_search.dart';
import '../widgets/general/bottom_nav.dart';
import '../widgets/general/breadcrumbs.dart';
import '../widgets/general/navigationbar.dart';
@@ -22,7 +22,7 @@ class StoreProductSearch extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).search_product,
back: true,
breadCrumbs: [

View File

@@ -1,66 +0,0 @@
import 'package:flutter/material.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../constants.dart';
import '../events/eventbus.dart';
import '../events/events.dart';
import '../generated/l10n.dart';
import '../widgets/desktop/desktop_tutorials.dart';
import '../widgets/general/bottom_nav.dart';
import '../widgets/general/breadcrumbs.dart';
import '../widgets/general/navigationbar.dart';
import '../widgets/mobile/MobileBottomNav.dart';
import '../widgets/mobile/mobile_navigation_drawer.dart';
import '../widgets/mobile/mobile_tutorials.dart';
class Tutorials extends StatefulWidget {
const Tutorials({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return TutorialsState();
}
}
class TutorialsState extends State<Tutorials> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
title: S.of(context).tutorials,
back: true,
breadCrumbs: [BreadCrumb(S.of(context).tutorials, null)],
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
),
drawer: null,
body: ScreenTypeLayout(
mobile: MobileTutorials(),
tablet: DesktopTutorials(),
desktop: DesktopTutorials(),
),
bottomNavigationBar: ScreenTypeLayout(
mobile: MobileBottomNav(currentIndex: 0,),
tablet: BottomNav(),
desktop: BottomNav(),
),
),
);
}
@override
void initState() {
super.initState();
eventBus.on<OpenDrawer>().listen((event) {
if (mounted) {
_scaffoldKey.currentState.openDrawer();
}
});
}
}

View File

@@ -20,7 +20,7 @@ class UserProfile extends StatelessWidget {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).profile,
back: true,
breadCrumbs: [

View File

@@ -42,7 +42,7 @@ class ViewBlogState extends State<ViewBlog> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).view_blog,
back: true,
breadCrumbs: [

View File

@@ -42,7 +42,7 @@ class ViewTicketState extends State<ViewTicket> {
builder: (context, sizingInformation) =>
Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).view_ticket,
back: true,
breadCrumbs: [

View File

@@ -1,19 +1,16 @@
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/pages/buy_service.dart';
import 'package:flutter_wisetronic/pages/contact_us.dart';
import 'package:flutter_wisetronic/pages/plain_page.dart';
import 'package:flutter_wisetronic/pages/renew_license.dart';
import 'package:flutter_wisetronic/pages/renew_minioffice.dart';
import 'package:flutter_wisetronic/store/store.dart';
import 'constants.dart';
import 'pages/blog.dart';
import 'pages/buy_service.dart';
import 'pages/change_mobile_or_email.dart';
import 'pages/change_password.dart';
import 'pages/checkout.dart';
import 'pages/contact_us.dart';
import 'pages/coupons.dart';
import 'pages/create_online_store_1.dart';
import 'pages/download.dart';
import 'pages/forgot_password.dart';
import 'pages/home.dart';
@@ -30,11 +27,13 @@ import 'pages/new_user.dart';
import 'pages/order_detail.dart';
import 'pages/orders.dart';
import 'pages/pay_now.dart';
import 'pages/plain_page.dart';
import 'pages/renew_license.dart';
import 'pages/renew_minioffice.dart';
import 'pages/reset_password.dart';
import 'pages/search_place.dart';
import 'pages/set_password.dart';
import 'pages/shop.dart';
import 'pages/tutorials.dart';
import 'pages/user_profile.dart';
import 'pages/view_blog.dart';
import 'pages/view_ticket.dart';
@@ -68,12 +67,6 @@ class Routes {
}),
transitionType: TransitionType.inFromRight
);
router.define('/tutorials', handler: new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return Tutorials();
}),
transitionType: TransitionType.inFromRight
);
router.define('/login', handler: new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return Login();
@@ -279,5 +272,10 @@ class Routes {
return BuyService(int.parse(params['gid'][0]), params['servicename'][0]);
}
));
router.define('/contact-stores', handler: new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return CreateOnlineStore1();
}
));
}
}

View File

@@ -58,7 +58,7 @@ class HttpUtil {
localHeaders['Http-Signature'] = generateSignature(url);
}
localHeaders['Http-Business-Id'] = businessId.toString();
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
Box box = await Utils.getBox();
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
localHeaders['Http-App-Key'] = platformName;
@@ -81,7 +81,7 @@ class HttpUtil {
onReceiveProgress: receiveProgress,
).timeout(const Duration(seconds: 30));
// print(response.data);
// print('response data: ${response.data}');
// Utils.jsonPrettyPrint(response.data);
int statusCode = response.statusCode;
@@ -115,7 +115,7 @@ class HttpUtil {
if (!url.startsWith('http')) {
localHeaders['Http-Signature'] = generateSignature(url);
}
localHeaders['Http-Business-Id'] = businessId.toString();
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
Box box = await Utils.getBox();
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
localHeaders['Http-App-Key'] = platformName;
@@ -189,7 +189,7 @@ class HttpUtil {
localHeaders['Http-Signature'] = generateSignature(url);
}
localHeaders['Http-Business-Id'] = businessId.toString();
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
Box box = await Utils.getBox();
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
localHeaders['Http-App-Key'] = platformName;
@@ -254,7 +254,7 @@ class HttpUtil {
localHeaders['Http-Signature'] = generateSignature(url);
}
localHeaders['Http-Business-Id'] = businessId.toString();
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
Box box = await Utils.getBox();
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
localHeaders['Http-App-Key'] = platformName;
@@ -319,7 +319,7 @@ class HttpUtil {
localHeaders['Http-Signature'] = generateSignature(url);
}
localHeaders['Http-Business-Id'] = businessId.toString();
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
Box box = await Utils.getBox();
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
localHeaders['Http-App-Key'] = platformName;

View File

@@ -1,39 +0,0 @@
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
class IFrameWeb extends StatefulWidget {
final String width;
final String height;
final String src;
const IFrameWeb({this.width, this.height, this.src});
@override
State<StatefulWidget> createState() {
return IFrameWebState();
}
}
class IFrameWebState extends State<IFrameWeb> {
final IFrameElement _iframeElement = IFrameElement();
@override
Widget build(BuildContext context) {
_iframeElement.height = widget.height;
_iframeElement.width = widget.width;
_iframeElement.src = widget.src;
_iframeElement.style.border = 'none';
ui.platformViewRegistry.registerViewFactory(
'iframeElement',
(int viewId) => _iframeElement,
);
return HtmlElementView(
key: UniqueKey(),
viewType: 'iframeElement',
);
}
}

View File

@@ -57,7 +57,7 @@ class Util {
);
},
errorBuilder: (BuildContext context, Object object, StackTrace stackTrace) {
print(stackTrace);
print('StackTrace: $stackTrace');
if (errorWidget != null) {
return errorWidget(context, null, null);
}

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:dio/dio.dart';
@@ -36,6 +37,142 @@ typedef void OnOk();
typedef void OnLoadImageError();
class Utils {
static StreamSubscription onProductWillAddToCartSubscription;
static StreamSubscription onProductWillRemoveFromCartSubscription;
init() async {
onProductWillAddToCartSubscription =
eventBus.on<OnProductWillAddToCart>().listen((event) {
CartInfo cartInfo =
getCartInfoByBusiness(store.state.cartInfos, event.business);
if (cartInfo == null || cartInfo.productList.length == 0) {
cartInfo = CartInfo();
cartInfo.id = 0;
cartInfo.amountPaid = 0.0;
cartInfo.businessInfo = event.business;
cartInfo.extraFeeList = [];
cartInfo.discountList = [];
CartLineItem lineItem = newCartLineItem(
id: 0,
price: event.price,
product: event.product,
name: event.product.name,
description: event.description,
quantity: 1.0);
cartInfo.productList = [lineItem];
addSubproductToCard(cartInfo, lineItem);
store.dispatch(new UpdateCartInfo(addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
print('#1');
} else {
if (event.product.productAttributes.length > 0) {
CartLineItem lineItem = newCartLineItem(
id: 0,
price: event.price,
product: event.product,
name: event.product.name,
description: event.description,
quantity: 1.0);
cartInfo.productList.add(lineItem);
addSubproductToCard(cartInfo, lineItem);
store.dispatch(new UpdateCartInfo(addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
print('#2');
eventBus.fire(new OnCartInfoUpdated());
} else {
int found = -1;
for (var i = 0; i < cartInfo.productList.length; i++) {
if (event.product.id == cartInfo.productList[i].product.id) {
found = i;
break;
}
}
if (found == -1) {
CartLineItem lineItem = newCartLineItem(
id: 0,
price: event.price,
product: event.product,
name: event.product.name,
description: event.description,
quantity: 1.0);
cartInfo.productList.add(lineItem);
addSubproductToCard(cartInfo, lineItem);
store.dispatch(new UpdateCartInfo(addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
print('#3');
eventBus.fire(new OnCartInfoUpdated());
} else {
if (cartInfo.productList[found].quantity + 1.0 >
event.product.leftNum) {
// Fluttertoast.showToast(
// msg: S.of(context).product_insufficient,
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
// backgroundColor: Colors.red,
// textColor: Colors.white);
} else {
cartInfo.productList[found].quantity += 1;
addSubproductQty(cartInfo, cartInfo.productList[found]);
store.dispatch(new UpdateCartInfo(
addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
print('#4');
eventBus.fire(new OnCartInfoUpdated());
}
}
}
}
});
onProductWillRemoveFromCartSubscription =
eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
CartInfo cartInfo =
getCartInfoByBusiness(store.state.cartInfos, event.business);
if (cartInfo != null) {
if (cartInfo.productList.length > 0) {
if (event.productListIndex != -1) {
if (cartInfo.productList[event.productListIndex].quantity <= 1) {
String uuid = cartInfo.productList[event.productListIndex].uuid;
cartInfo.productList.removeAt(event.productListIndex);
removeSubproduct(cartInfo, uuid);
} else {
cartInfo.productList[event.productListIndex].quantity -= 1;
addSubproductQty(cartInfo, cartInfo.productList[event.productListIndex], remove: true);
}
} else {
int productListIndex = -1;
for (var i = 0; i < cartInfo.productList.length; i++) {
if (cartInfo.productList[i].product.id == event.product.id) {
productListIndex = i;
break;
}
}
if (productListIndex != -1) {
if (cartInfo.productList[productListIndex].quantity <= 1) {
String uuid = cartInfo.productList[productListIndex].uuid;
cartInfo.productList.removeAt(productListIndex);
removeSubproduct(cartInfo, uuid);
} else {
cartInfo.productList[productListIndex].quantity -= 1;
addSubproductQty(cartInfo, cartInfo.productList[productListIndex], remove: true);
}
}
}
}
if (cartInfo.productList.length <= 0) {
store.dispatch(UpdateCartInfo(removeCartInfoFromCartInfoList(
store.state.cartInfos, cartInfo)));
} else {
store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList(
store.state.cartInfos, cartInfo)));
}
eventBus.fire(new OnCartInfoUpdated());
}
});
}
static bool equalsIgnoreCase(String a, String b) =>
(a == null && b == null) ||
(a != null && b != null && a.toLowerCase() == b.toLowerCase());
@@ -373,6 +510,8 @@ class Utils {
message = error.response.data.toString();
}
}
} else if (error is String) {
message = '$error';
} else if (error.message != null) {
message = error.message;
} else {
@@ -642,7 +781,8 @@ class Utils {
}
static void loadProducts(int businessId, int categoryId, int page, bool more,
OnComplete onComplete, OnError onError) {
OnComplete onComplete, OnError onError, {int featuredCount=4, int hotSaleCount=4, String keyword=''}) {
print('feature $featuredCount');
HttpUtil.httpGet(
more ? 'v1/service-category-products-more' : 'v1/service-category-products',
businessId: businessId,
@@ -650,9 +790,12 @@ class Utils {
// 'lat': store.state.position.latitude.toString(),
// 'lng': store.state.position.longitude.toString(),
'category_id': categoryId,
'preview': 'no',
'preview': Constants.isPreview,
'page': page,
'num_per_page': Constants.ORDERS_PER_PAGE,
'featured_count': featuredCount,
'hot_sale_count': hotSaleCount,
'keyword': Uri.encodeComponent(keyword),
},
).then((value) {
if (onComplete != null) {
@@ -667,6 +810,9 @@ class Utils {
static String timestampToString(BuildContext context, int timestamp, {bool withTime=false}) {
DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
if (timestamp == 0) {
return '';
}
return datetimeFormat(context, date, withTime: withTime);
}
@@ -966,6 +1112,10 @@ class Utils {
child: row,
);
}
static int getBusinessId() {
return Constants.BUSINESS_ID;
}
}
class RuntimeError extends Error {

View File

@@ -0,0 +1,464 @@
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../generated/l10n.dart';
import '../../models/group.dart';
import '../../pages/buy_service.dart';
import '../../routes.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
class CreateOnlineStore1 extends StatefulWidget {
final int businessId;
const CreateOnlineStore1(this.businessId, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return CreateOnlineStore1State();
}
}
class CreateOnlineStore1State extends State<CreateOnlineStore1> {
double sideSpace = 0;
double mainSpace = 1200;
TextEditingController groupNumberController = TextEditingController();
TextEditingController domainController = TextEditingController();
bool canSubmit = false;
List<dynamic> stores = [];
Map<String, dynamic> service;
dynamic selectedStore;
Group group;
String selectedDomain;
List<dynamic> domainResult = [];
@override
Widget build(BuildContext context) {
if (MediaQuery
.of(context)
.size
.width <= 1200) {
mainSpace = MediaQuery
.of(context)
.size
.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery
.of(context)
.size
.width - 1200) / 2;
}
Row row = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
row.children.add(
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 16.0, right: 16.0, top: 20, bottom: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(bottom: 4.0),
child: Text(
S.of(context).open_online_store,
style: TextStyle(
fontSize: 28,
),
),
),
Container(
padding: EdgeInsets.only(top: 4, bottom: 4),
child: Text(
S.of(context)
.select_a_store,
style: TextStyle(
color: Colors.black45,
),
),
),
Container(
padding: EdgeInsets.only(top: 4),
child: DropdownButton<dynamic>(
items: stores.map((e) => DropdownMenuItem<dynamic>(
value: e,
child: Text(e['name']),
)).toList(),
isExpanded: false,
hint: Text(S.of(context).select_a_store),
onChanged: (newValue) {
print('newValue $newValue');
setState(() {
selectedStore = newValue;
});
},
value: selectedStore,
),
),
],
),
decoration: BoxDecoration(
border: Border(
right: BorderSide(
width: 1,
color: Colors.black12,
),
),
),
),
),
);
row.children.add(
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 16.0, right: 16.0, top: 20, bottom: 20),
child: Visibility(
child: getSearchDomainWidget(),
visible: selectedStore != null,
),
),
),
);
return Scaffold(
appBar: MiniNavigationBar(
title: S
.of(context)
.blog,
back: true,
breadCrumbs: [
BreadCrumb(S
.of(context)
.open_online_store, null),
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
),
body: SingleChildScrollView(
child: Row(
children: [
Container(
width: sideSpace,
),
Expanded(child: row,),
Container(
width: sideSpace,
),
],
),
),
bottomNavigationBar: BottomNav(),
);
}
Widget getSearchDomainWidget() {
if (selectedStore == null) {
return SizedBox.shrink();
}
Column col = Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
col.children.add(
Container(
padding: EdgeInsets.only(bottom: 4,),
child: Text(selectedStore == null ? '' : selectedStore['name'],
style: TextStyle(
fontSize: 28,
),
),
),
);
Map<String, dynamic> existing_web_svc;
if (selectedStore != null && (selectedStore['services'] as List).length > 0) {
for (Map<String, dynamic>svc in (selectedStore['services'] as List)) {
if (svc['code'] == Constants.WEB_MINISTORE_SERVICE) {
existing_web_svc = svc;
break;
}
}
}
if (existing_web_svc != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'${existing_web_svc['description']}',
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).expiration_date + ": "
+ Utils.utcDatetimeStringToLocalDatetimeString(context, existing_web_svc['expiration_date']),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).store + ": " + '${existing_web_svc['store']['name']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).domain_name + ": " + '${existing_web_svc['domain']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(S.of(context).renew_service_now),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: existing_web_svc['domain'],
sid: existing_web_svc['store']['id'],
),
));
},
),
),
);
} else {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(S.of(context).enter_desired_domain),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 0,),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: TextFormField(
controller: domainController,
decoration: new InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black12,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
labelText: S.of(context).domains_separated_comma,
),
style: TextStyle(
fontSize: 18.0
),
autofocus: true,
validator: (String value) {
if (value.trim().isEmpty) {
return S.of(context).domains_separated_comma;
}
return null;
},
onChanged: (string) {
if (string.isNotEmpty) {
canSubmit = true;
} else {
canSubmit = false;
}
setState(() {});
},
),
),
Container(
padding: EdgeInsets.only(left: 8.0),
child: ElevatedButton(
child: Text(
S.of(context).check_domain_name,
),
onPressed: domainController.text.length > 0 ? checkDomainAvailability : null,
),
),
],
),
)
);
if (domainResult.length > 0) {
for (dynamic dr in domainResult) {
col.children.add(_getDomain(dr));
}
}
if (selectedDomain != null && service != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['description'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['options'][0]['name'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'\$${service['options'][0]['price']}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.orange,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(
S.of(context).place_order_now,
),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: selectedDomain,
sid: selectedStore['id'],
),
));
},
),
),
);
}
}
return Container(
padding: EdgeInsets.only(bottom: 4,),
child: col,
);
}
@override
void initState() {
super.initState();
HttpUtil.httpGet(
'v1/get-contact-stores',
queryParameters: {
'service': Constants.WEB_MINISTORE_SERVICE
}
).then((value) {
setState(() {
stores = value['stores'];
service = value['service'];
group = Group.fromJson(value['group']);
print('stores: ${value}');
});
}).onError((error, stackTrace) {
Utils.showMessageDialog(context, error, onOk: () {
Routes.router.navigateTo(context, '/');
});
});
}
Future<void> checkDomainAvailability() async {
Utils.showLoadingDialog(context);
selectedDomain = null;
domainResult = [];
setState(() {});
HttpUtil.httpGet(
'v1/check-domain-availability',
queryParameters: {
'domain': domainController.text,
},
).then((value) {
Routes.router.pop(context);
print('value: $value');
if (value['status'] == 'OK') {
domainResult = (value['domain_check_result'] as List);
setState(() {});
} else if (value['status'] == 'ERROR') {
String errors = '';
for (int i = 0; i < (value['errors'] as List).length; i++) {
errors += value['errors'][i] + '\n';
}
Utils.showMessageDialog(context, errors);
}
}).onError((error, stackTrace) {
Routes.router.pop(context);
Utils.showMessageDialog(context, error);
});
}
Widget _getDomain(dynamic d) {
if ((d['available'] as bool)) {
return Container(
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
leading: Radio(
value: d['domain'],
groupValue: selectedDomain,
onChanged: (val) {
setState(() {
selectedDomain = val;
});
},
),
),
);
} else {
return Container(
padding: EdgeInsets.only(top: 1.0),
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
color: Colors.black45,
),
),
leading: Icon(Icons.clear, color: Colors.red,),
),
);
}
}
}

View File

@@ -39,7 +39,8 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).home,
'/',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/',
clearStack: true,
),
@@ -47,14 +48,16 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).download,
'/download',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/download',
),
SizedBox(width: 15.0,),
TextLink(
S.of(context).tutorials,
Constants.TUTORIAL_URL,
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/tutorials',
isLink: true,
),
@@ -62,21 +65,24 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).support,
'/my-support/${Constants.BUSINESS_ID}',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/my-support/${Constants.BUSINESS_ID}',
),
SizedBox(width: 15.0,),
TextLink(
S.of(context).shop,
'/shop',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/shop',
),
SizedBox(width: 15.0,),
TextLink(
S.of(context).blog,
'/blog/${Constants.BUSINESS_ID}',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/blog/${Constants.BUSINESS_ID}',
),
SizedBox(width: 15.0,),
@@ -126,7 +132,8 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).login,
'/login',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/login',
),
],

View File

@@ -85,7 +85,7 @@ class DesktopBlogState extends State<DesktopBlog> {
BuildContext mainContext = context;
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [
@@ -272,6 +272,7 @@ class DesktopBlogState extends State<DesktopBlog> {
'size': Constants.BLOG_PER_PAGE_DESKTOP.toString()
}
).then((value) {
print('value: $value');
if (mounted) {
if (isRefresh) {
_refreshController.refreshCompleted();

View File

@@ -72,6 +72,18 @@ class DesktopBuyServiceState extends State<DesktopBuyService> {
Utils.buildLine(S.of(context).your_group, widget.data['group']['name'], valueSize: 16),
);
if (widget.data['store']['id'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).store, widget.data['store']['name'], valueSize: 16),
);
}
if (widget.data['domain'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).domain_name, widget.data['domain'], valueSize: 16),
);
}
if (widget.data['exists_service'] == null) {
col1.children.add(
Utils.buildLine(S.of(context).current_plan, 'N/A', valueSize: 16),
@@ -171,7 +183,7 @@ class DesktopBuyServiceState extends State<DesktopBuyService> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -178,7 +178,7 @@ class DesktopCheckoutState extends State<DesktopCheckout> with SingleTickerProvi
Scaffold scaffold = Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [
@@ -355,6 +355,7 @@ class DesktopCheckoutState extends State<DesktopCheckout> with SingleTickerProvi
check();
},
initialLabelIndex: deliveryMethodIndex,
totalSwitches: shippingMethodLabels.length,
);
switch (position) {
case 0:

View File

@@ -329,7 +329,7 @@ class DesktopContactUsState extends State<DesktopContactUs> {
);
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -78,7 +78,7 @@ class DesktopCouponsState extends State<DesktopCoupons> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -399,7 +399,7 @@ class DesktopEditAddressState extends State<DesktopEditAddress> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).edit_address,
back: true,
breadCrumbs: [

View File

@@ -101,7 +101,8 @@ class DesktopIndexMainContent3State extends State<DesktopIndexMainContent3> {
TextLink(S.of(context).support_ticket, '/my-support/${Constants.BUSINESS_ID}', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0,)
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 10.0,)
],
),
),
@@ -250,7 +251,8 @@ class DesktopIndexMainContent3State extends State<DesktopIndexMainContent3> {
TextLink(S.of(context).support_ticket, '/my-support/${Constants.BUSINESS_ID}', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 0.0,)
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 0.0,)
],
),
),

View File

@@ -63,7 +63,7 @@ class DesktopMyAddressesState extends State<DesktopMyAddresses> {
BuildContext mainContext = context;
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).my_addresses,
back: true,
breadCrumbs: [

View File

@@ -48,7 +48,7 @@ class MyCardsState extends State<DesktopMyCards> {
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -88,7 +88,7 @@ class DesktopMySupportState extends State<DesktopMySupport> {
BuildContext mainContext = context;
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).my_support,
back: true,
breadCrumbs: [

View File

@@ -2,28 +2,25 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_wisetronic/widgets/desktop/desktop_appbar_menu.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../constants.dart';
import '../../dialog/logout_dialog.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/user.dart';
import '../../routes.dart';
import '../../store/store.dart';
import '../../utils/utils.dart';
import '../../widgets/general/navigationbar_logo.dart';
import '../../widgets/general/text_link.dart';
import '../../widgets/desktop/desktop_appbar_menu.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
class DesktopNavigationBar extends StatefulWidget {
final bool hasBack;
final List<BreadCrumb> breadCrumbs;
final Widget shoppingCart;
final OnBackPress onBackPress;
const DesktopNavigationBar({Key key, this.hasBack, this.breadCrumbs,
this.shoppingCart}) : super(key: key);
this.shoppingCart, this.onBackPress}) : super(key: key);
@override
State<StatefulWidget> createState() {
@@ -37,132 +34,6 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
@override
Widget build(BuildContext context) {
// String currentRoute = ModalRoute.of(context).settings.name;
// Stack stack = Stack(
// children: [
// Container(
// color: Colors.blue,
// height: 80.0,
// ),
// Container(
// height: 80.0,
// padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// NavigationBarLogo(),
// Expanded(
// child: Container(
// alignment: Alignment.centerRight,
// padding: EdgeInsets.only(left: 8.0, right: 16.0),
// child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// SizedBox(width: 20.0,),
// TextLink(
// S.of(context).home,
// '/',
// color: Colors.white,
// selected: currentRoute == '/',
// clearStack: true,
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).download,
// '/download',
// color: Colors.white,
// selected: currentRoute == '/download',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).tutorials,
// '/tutorials',
// color: Colors.white,
// selected: currentRoute == '/tutorials',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).support,
// '/my-support/${Constants.BUSINESS_ID}',
// color: Colors.white,
// selected: currentRoute == '/my-support/${Constants.BUSINESS_ID}',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).shop,
// '/shop',
// color: Colors.white,
// selected: currentRoute == '/shop',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).blog,
// '/blog/${Constants.BUSINESS_ID}',
// color: Colors.white,
// selected: currentRoute == '/blog/${Constants.BUSINESS_ID}',
// ),
// SizedBox(width: 15.0,),
// _user != null ?
// (currentRoute == '/me') ?
// MouseRegion(
// cursor: SystemMouseCursors.click,
// child: GestureDetector(
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Container(
// padding: EdgeInsets.only(right: 4.0),
// child: Text(
// S.of(context).logout,
// style: TextStyle(
// color: Colors.white,
// ),
// ),
// ),
// Icon(
// Icons.logout,
// color: Colors.white,
// size: 16.0,
// )
// ],
// ),
// onTap: () {
// showDialog(
// context: context,
// builder: (BuildContext context) {
// return logoutDialog(context);
// }
// );
// },
// ),
// ) : IconButton(
// icon: Icon(
// Icons.account_circle,
// color: Colors.white,
// ),
// onPressed: () {
// Routes.router.navigateTo(context, '/me');
// },
// ) :
// TextLink(
// S.of(context).login,
// '/login',
// color: Colors.white,
// selected: currentRoute == '/login',
// ),
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ],
// );
Widget sc = SizedBox.shrink();
if (widget.shoppingCart != null) {
sc = widget.shoppingCart;
@@ -171,8 +42,8 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
if (widget.breadCrumbs != null && widget.breadCrumbs.length > 0) {
breadCrumbBar = Container(
width: MediaQuery.of(context).size.width,
height: 38.0,
color: Color(0xFF4FB0C6),
height: Constants.BREADCRUMB_HEIGHT,
padding: EdgeInsets.only(top: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -180,6 +51,7 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
Expanded(
child: BreadCrumbs(
widget.hasBack ?? false,
onBackPress: widget.onBackPress,
breadCrumbs: widget.breadCrumbs,
),
),
@@ -189,14 +61,18 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
),
],
),
decoration: BoxDecoration(
color: Colors.black12,
border: Border(
bottom: BorderSide(
width: 1.0,
color: Colors.black26,
),
),
),
);
}
// stack.children.add(
// Positioned(
// top: 90.0,
// child: breadCrumbBar,
// ),
// );
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -324,7 +324,7 @@ class DesktopNewAddressState extends State<DesktopNewAddress> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).new_address,
back: true,
breadCrumbs: [

View File

@@ -62,7 +62,7 @@ class DesktopNewCommentState extends State<DesktopNewComment> {
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).new_comment,
back: true,
breadCrumbs: [

View File

@@ -958,7 +958,7 @@ class DesktopOrderDetailState extends State<DesktopOrderDetail> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -98,7 +98,7 @@ class DesktopOrdersState extends State<DesktopOrders> with SingleTickerProviderS
return Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -345,7 +345,7 @@ class DesktopPayNowState extends State<DesktopPayNow> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -60,7 +60,7 @@ class DesktopPlainPageState extends State<DesktopPlainPage> {
));
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -79,7 +79,7 @@ class DesktopProductDetailPageState extends State<DesktopProductDetailPage>
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).shop,
back: true,
breadCrumbs: [

View File

@@ -167,7 +167,7 @@ class DesktopRenewLicenseState extends State<DesktopRenewLicense> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -136,7 +136,7 @@ class DesktopRenewMiniOfficeState extends State<DesktopRenewMiniOffice> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -45,7 +45,7 @@ class DesktopSearchPlaceState extends State<DesktopSearchPlace> {
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).search_place,
back: true,
breadCrumbs: [

View File

@@ -288,7 +288,7 @@ class DesktopSetPasswordState extends State<DesktopSetPassword> {
);
},
queryParameters: {
'action': 'reset_password',
'action': 'create_user',
},
isFormData: true,
body: {

View File

@@ -109,7 +109,7 @@ class DesktopStripePayWebState extends State<DesktopStripePayWeb> {
return Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -1,127 +0,0 @@
import '../../constants.dart';
import '../../utils/iframe_web.dart' if (dart.library.io) '../../utils/fake_iframe_web.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class DesktopTutorials extends StatefulWidget {
const DesktopTutorials({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return DesktopTutorialsState();
}
}
class DesktopTutorialsState extends State<DesktopTutorials> {
double sideSpace = 0;
double mainSpace = 1200;
InAppWebViewController webView;
String url = "";
double progress = 0;
bool isLoadStop = false;
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
if (kIsWeb) {
return Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: IFrameWeb(
width: double.maxFinite.toString(),
height: double.maxFinite.toString(),
src: Constants.TUTORIAL_URL,
),
),
],
),
),
Container(
width: sideSpace,
),
],
);
} else {
print('progress: $progress');
return Stack(
children: [
Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse(Constants.TUTORIAL_URL)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (controller, url) {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = false;
});
}
},
onLoadStop: (controller, url) async {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = true;
});
}
},
onProgressChanged: (InAppWebViewController controller, int progress) {
if (mounted) {
setState(() {
if (this.progress < 1.0) {
this.isLoadStop = false;
} else {
this.isLoadStop = true;
}
this.progress = progress / 100;
});
}
},
),
),
Container(
width: sideSpace,
),
],
),
isLoadStop ? Container() :
Center(
child: CircularProgressIndicator(),
),
],
);
}
}
}

View File

@@ -13,6 +13,8 @@ import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
class DesktopViewBlog extends StatefulWidget {
final Key key;
final int bid;
@@ -172,11 +174,7 @@ class DesktopViewBlogState extends State<DesktopViewBlog> {
: Container(
width: mainSpace / 2 - 100.0,
height: mainSpace / 2 - 100.0,
child: PhotoView(
imageProvider: NetworkImage(
'https:${blog.imageUrl}',
),
),
child: Util.showImage('https:${blog.imageUrl}'),
),
),
],

View File

@@ -0,0 +1,280 @@
import 'package:flutter/material.dart';
import 'package:hovering/hovering.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/show_price.dart';
class ProductItem extends StatefulWidget {
final Business business;
final Product product;
final bool horizontal;
const ProductItem(this.product, this.business, {Key key, this.horizontal = false}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductItemState();
}
class ProductItemState extends State<ProductItem> {
@override
Widget build(BuildContext context) {
return HoverWidget(
child: Container(
width: 160.0,
height: widget.horizontal ? 160 : 268.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
bottom: new BorderSide(
color: new Color(0xFFEBEBEB),
),
),
),
child: new SizedBox.expand(
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0),
child: widget.horizontal ? getHorizontal(false) : getVertial(false),
),
),
),
hoverChild: Container(
width: 160.0,
height: widget.horizontal ? 160 : 268.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
top: new BorderSide(
color: new Color(0xFFEBEBEB),
),
left: new BorderSide(
color: new Color(0xFFEBEBEB),
),
right: new BorderSide(
color: new Color(0xFFEBEBEB),
),
bottom: new BorderSide(
color: new Color(0xFFBBBBBB),
),
),
),
child: new SizedBox.expand(
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0),
child: widget.horizontal ? getHorizontal(true) : getVertial(true),
),
),
),
onHover: (event) {
}
);
}
Widget getHorizontal(bool onHover) {
return Row(
children: [
Container(
margin: new EdgeInsets.all(10.0),
width: 110.0,
height: 110.0,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
),
),
],
);
}
Widget getVertial(bool onHover) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: new EdgeInsets.all(10.0),
width: 110.0,
height: 110.0,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Container(
child: Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
),
),
],
);
}
void _showProductDetail() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: widget.product,
business: widget.business,
)),
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
}
}

View File

@@ -0,0 +1,181 @@
import 'package:dio/dio.dart';
import 'package:flappy_search_bar/flappy_search_bar.dart';
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
import 'product_item.dart';
class ProductSearch extends StatefulWidget {
final Business business;
const ProductSearch(this.business, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductSearchState();
}
class ProductSearchState extends State<ProductSearch> {
double sideSpace = 0;
double mainSpace = 1200;
double rate = 1;
int page = 1;
int numPerPage = 10;
int lastResultSize = 0;
double lastBottomPosition = 0;
String lastKeyword = '';
SearchBarController _controller = SearchBarController<Product>();
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
rate = mainSpace / 1200;
return Scaffold(
appBar: MiniNavigationBar(
title: S.of(context).search_product,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).search_product, null),
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
),
drawer: null,
body: SafeArea(
child: Container(
child: Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: NotificationListener<ScrollNotification>(
child: SearchBar(
searchBarController: _controller,
minimumChars: 2,
hintText: S.of(context).enter_keyword,
cancellationWidget: Text(
S.of(context).cancel,
),
onSearch: search,
onItemFound: (Product searchProduct, int index) {
return ProductItem(
searchProduct,
widget.business,
horizontal: true,
);
},
onError: (error) {
return Center(
child: Text("$error"),
);
},
emptyWidget: Center(
child: Text(
S.of(context).empty_result_change_keyword,
),
),
),
onNotification: (notification) {
if (notification.metrics.atEdge) {
print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}');
if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) {
if (notification.metrics.pixels > lastBottomPosition) {
lastBottomPosition = notification.metrics.pixels;
page += 1;
_controller.replayLastSearch();
}
}
}
return true;
},
),
),
),
Container(
width: sideSpace,
),
],
),
),
),
bottomNavigationBar: BottomNav(),
);
}
Future<List<Product>> search(String keyword) async {
if (lastKeyword != keyword) {
page = 1;
}
lastKeyword = keyword;
var result = await HttpUtil.httpGet('v1/search-store-product2',
queryParameters: {
'store_id': widget.business.id,
'keyword': keyword,
'page': page,
'num_per_page': numPerPage,
},
returnError: true,
);
if (result is DioError) {
if (result.response != null) {
throw RuntimeError(result.response.data);
} else {
throw RuntimeError(result.message);
}
} else if (result != null && result is List) {
lastBottomPosition = 0;
var r = result.map((e) => Product.fromJson(e)).toList();
lastResultSize = r.length;
if (lastResultSize < numPerPage) {
page = 1;
}
return r;
}
return [];
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {});
}
});
}
void _showProductDetail(Product p) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: widget.business,
)),
);
}
}

View File

@@ -0,0 +1,297 @@
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../../utils/utils.dart';
import '../../widgets/desktop/shop_products.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
import '../../widgets/general/sliding_up_panel.dart';
import '../../widgets/mobile/shopping_cart_bar.dart';
import 'shop_bulletin.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/category_products.dart';
import 'product_search.dart';
import 'shop_promote.dart';
import 'shopping_cart_widget.dart';
class Shop extends StatefulWidget {
final int businessId;
const Shop({Key key, this.businessId}): super(key: key);
@override
State<StatefulWidget> createState() => ShopState();
}
class ShopState extends State<Shop> {
Business _business;
PanelController panelController = PanelController();
SlidingUpPanel _slidUpShoppingCart;
GlobalKey endKey = GlobalKey();
List<CategoryProducts> _categoryProducts;
bool displayProductByCategoryClick = false;
String displayProductByCategoryClickIndicator = '';
int categoryId = 0;
static int _productCurrentPage = 1;
int _categoryIndex = 0;
bool _categoryIndexChange = false;
bool _isLoading = false;
dynamic data;
@override
Widget build(BuildContext context) {
if (_business == null) {
return Scaffold(
body: Center(
child: SpinKitWave(
color: Colors.lightBlueAccent,
size: 40.0,
),
),
);
}
_slidUpShoppingCart = SlidingUpPanel(
controller: panelController,
minHeight: 0.0,
maxHeight: 250.0,
isDraggable: false,
backdropEnabled: true,
slideDirection: SlideDirection.DOWN,
panel: ShoppingCartBar(
business: _business,
endKey: endKey,
barAtBottom: true,
hasPicture: true,
onEmptyCartListener: () {
Future.delayed(Duration(seconds: 1), () {
panelController.close();
});
},
onPanelOpenCloseRequest: () {
if (panelController.isPanelOpen) {
panelController.close();
} else {
panelController.open();
}
},
),
);
Scaffold scaffold = Scaffold(
appBar: MiniNavigationBar(
title: S.of(context).shop,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).shop, null),
BreadCrumb(null, null,
item: Container(
margin: EdgeInsets.only(left: 20.0),
child: Row(
children: [
Container(
child: Icon(
Icons.search,
size: 24,
color: Colors.blue,
),
),
Container(
child: Text(
S.of(context).search_product,
),
),
],
),
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return ProductSearch(_business);
}));
},
),
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
shoppingCart: ShoppingCartWidget(
business: _business,
onTap: () {
if (panelController.isPanelClosed) {
panelController.open();
}
},
),
),
body: Scrollbar(
child: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification &&
scrollNotification.metrics.pixels == scrollNotification.metrics.maxScrollExtent) {
loadMoreProducts();
}
return false;
},
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ShopPromote(data),
ShopBulletin(_business),
ShopProducts(data),
],
),
),
),
),
bottomNavigationBar: BottomNav(),
);
return Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
bottom: 0,
child: scaffold,
),
_slidUpShoppingCart,
],
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
eventBus.on<CategoryChangeEvent>().listen((event) {
if (mounted) {
// setState(() {
// categoryId = event.categoryId;
// _productCurrentPage = 1;
// });
categoryId = event.categoryId;
_productCurrentPage = 1;
_isLoading = true;
Utils.showLoadingDialog(context, message: S.of(context).loading);
loadProducts();
}
});
loadProducts();
}
void loadProducts() {
print('categoryId $categoryId');
if (categoryId < 0) {
return;
}
_productCurrentPage = 1;
Utils.loadProducts(
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
if (_business == null) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
if (categoryId == 0 && displayProductByCategoryClick) {
categoryId = _categoryProducts[0].id;
}
data = value;
});
} else {
eventBus.fire(GetCategoryProducts(value));
}
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {});
}
Utils.showMessageDialog(context, error);
}, featuredCount: 6, hotSaleCount: 0, keyword: ''
);
}
void loadMoreProducts() {
if (_productCurrentPage == 0 || categoryId <= 0) {
return;
}
_productCurrentPage += 1;
Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true, (value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
List<CategoryProducts> moreCategoryProducts = (value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
} else {
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
_productCurrentPage = 0;
}
}
eventBus.fire(MoreCategoryProducts(moreCategoryProducts));
}
}, (error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
);
}
int nextCategoryId(int currentCategoryId) {
if (_categoryProducts.length <= 0) {
return 0;
}
for (int i = 0; i < _categoryProducts.length; i++) {
if (_categoryProducts[i].id == currentCategoryId) {
try {
CategoryProducts cps = _categoryProducts[i + 1];
return cps.id;
} catch (error) {
print('Error $error');
}
}
}
return 0;
}
}

View File

@@ -1,14 +1,11 @@
import 'dart:async';
import 'dart:math';
import 'package:badges/badges.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_wisetronic/widgets/mobile/shopping_cart_bar.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
@@ -24,34 +21,31 @@ import '../../models/comment.dart';
import '../../models/product.dart';
import '../../models/product_image.dart';
import '../../pages/product_detail_page.dart';
import '../../pages/store_product_search.dart';
import '../../store/actions.dart';
import '../../store/store.dart';
import '../../utils/http_util.dart';
import '../../utils/shop_scroll_controller.dart';
import '../../utils/shop_scroll_coordinator.dart';
import '../../utils/util_web.dart'
if (dart.library.io) '../../utils/util_io.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import '../../utils/utils.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/carousel.dart';
import '../../widgets/general/navigationbar.dart';
import '../../widgets/general/product_item.dart';
import '../../widgets/general/read_more_text.dart';
import '../../widgets/general/show_price.dart';
import '../../widgets/general/sliding_up_panel.dart';
import '../../widgets/general/style.dart';
import 'desktop_shopping_cart_widget.dart';
import '../../widgets/mobile/shopping_cart_bar.dart';
import 'product_item.dart';
import 'shopping_cart_widget.dart';
class DesktopShop extends StatefulWidget {
class Shop extends StatefulWidget {
final int businessId;
const DesktopShop({Key key, this.businessId}) : super(key: key);
const Shop({Key key, this.businessId}) : super(key: key);
@override
State<StatefulWidget> createState() => DesktopShopState();
State<StatefulWidget> createState() => ShopState();
}
MediaQueryData mediaQuery;
@@ -59,7 +53,7 @@ double statusBarHeight;
double screenWidth;
double screenHeight;
class DesktopShopState extends State<DesktopShop>
class ShopState extends State<Shop>
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@@ -109,7 +103,7 @@ class DesktopShopState extends State<DesktopShop>
int _commentPageCount = 1;
bool _commentLoadingFinish = false;
RefreshController _commentRefreshController =
RefreshController(initialRefresh: true);
RefreshController(initialRefresh: true);
PanelController panelController = PanelController();
SlidingUpPanel _slidUpShoppingCart;
@@ -123,6 +117,44 @@ class DesktopShopState extends State<DesktopShop>
double lastProductListScrollPositionPixel = 0;
final TextEditingController _searchController = new TextEditingController();
Widget searchFieldPlaceHolder;
Icon searchIcon = new Icon(
Icons.search,
color: Colors.blue,
);
bool _isSearching = false;
String _searchText = "";
dynamic responseData;
ShopState() {
_searchController.addListener(() {
if (_searchController.text.isEmpty) {
setState(() {
// _isSearching = false;
_searchText = "";
if (responseData != null) {
_categoryProducts.clear();
_categoryProducts = (responseData['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
} else {
categoryId = 0;
loadProducts();
}
});
} else {
if (!displayProductByCategoryClick) {
setState(() {
_isSearching = true;
_searchText = _searchController.text;
});
}
}
});
}
void _onCommentRefresh() {
if (_commentPage - 1 > 1) {
_commentPage -= 1;
@@ -253,9 +285,33 @@ class DesktopShopState extends State<DesktopShop>
left: 10.0,
top: 10.0,
bottom: 10.0,
right: 10.0,
),
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
width: 220.0,
height: 220.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Colors.white,
border: Border(
top: BorderSide(
width: 1.0,
color: Colors.black12,
),
bottom: BorderSide(
width: 1.0,
color: Colors.black12,
),
left: BorderSide(
width: 1.0,
color: Colors.black12,
),
right: BorderSide(
width: 1.0,
color: Colors.black12,
),
),
),
width: 240.0,
height: 320.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
@@ -263,6 +319,7 @@ class DesktopShopState extends State<DesktopShop>
child: Container(
child: Util.showImage(
_business.promoProducts[i].imagePath,
width: 120.0,
),
),
onTap: () {
@@ -307,8 +364,8 @@ class DesktopShopState extends State<DesktopShop>
pinned: false,
floating: true,
delegate: _SliverAppBarDelegate2(
minHeight: 350.0,
maxHeight: 350.0,
minHeight: 260.0,
maxHeight: 260.0,
child: Row(
children: [
Container(
@@ -413,10 +470,24 @@ class DesktopShopState extends State<DesktopShop>
final newOffset = _pageScrollController.offset + ps.scrollDelta.dy;
if (ps.scrollDelta.dy.isNegative) {
_pageScrollController.jumpTo(max(0, newOffset));
if (max(0, newOffset) == 0) {
_listScrollController1.jumpTo(max(0, _listScrollController1.offset - 10));
}
} else {
_pageScrollController
.jumpTo(min(_pageScrollController.position.maxScrollExtent, newOffset));
if (newOffset > _pageScrollController.position.maxScrollExtent) {
_listScrollController1.jumpTo(min(_listScrollController1.position.maxScrollExtent, _listScrollController1.offset + 10));
}
}
// if (ps.scrollDelta.dy.isNegative) {
// _listScrollController2.jumpTo(max(0, newOffset));
// } else {
// _listScrollController2
// .jumpTo(min(_listScrollController2.position.maxScrollExtent, newOffset));
// }
}
},
child: CustomScrollView(
@@ -427,45 +498,86 @@ class DesktopShopState extends State<DesktopShop>
pinned: true,
floating: true,
delegate: _SliverAppBarDelegate2(
minHeight: 94,
maxHeight: 94,
minHeight: 98,
maxHeight: 98,
child: Column(
children: [
NavigationBar(
MiniNavigationBar(
title: S.of(context).shop,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).shop, null),
BreadCrumb(null, null,
// BreadCrumb(null, null,
// item: Container(
// margin: EdgeInsets.only(left: 20.0),
// child: Row(
// children: [
// Container(
// child: Icon(
// Icons.search,
// size: 24,
// color: Colors.blue,
// ),
// ),
// Container(
// child: Text(
// S.of(context).search_product,
// ),
// ),
// ],
// ),
// ),
// onTap: () {
// // Navigator.push(context,
// // MaterialPageRoute(builder: (BuildContext context) {
// // return ProductSearch(_business);
// // }));
// },
// ),
BreadCrumb(
null, null,
item: Container(
margin: EdgeInsets.only(left: 20.0),
width: 280.0,
padding: EdgeInsets.only(left: 20.0, right: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Icon(
Icons.search,
size: 24,
color: Colors.blue,
MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Container(
padding: EdgeInsets.only(right: 10.0),
child: Icon(
searchIcon.icon,
size: 20.0,
color: Colors.blue,
),
),
onTap: () {
onSearchTap();
},
),
),
Container(
child: Text(
S.of(context).search_product,
Expanded(child: searchFieldPlaceHolder == null ? MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Text(
S.of(context).search_products,
style: new TextStyle(color: Colors.blue),
),
onTap: () {
onSearchTap();
},
),
),
) : searchFieldPlaceHolder),
],
),
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return StoreProductSearch(_business);
}));
},
),
)
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
shoppingCart: DesktopShoppingCartWidget(
shoppingCart: ShoppingCartWidget(
business: _business,
onTap: () {
if (panelController.isPanelClosed) {
@@ -573,21 +685,20 @@ class DesktopShopState extends State<DesktopShop>
stack.children.addAll(children);
if (!_business.isPublic) {
/* todo */
// stack.children.add(
// Positioned(
// top: 0,
// right: 0,
// left: screenWidth - 100,
// bottom: screenHeight - 100,
// child: Image.asset(
// 'assets/images/under_renovation.png',
// width: 200.0,
// height: 200.0,
// fit: BoxFit.fill,
// ),
// ),
// );
stack.children.add(
Positioned(
top: 0,
right: 0,
left: screenWidth - 100,
bottom: screenHeight - 100,
child: Image.asset(
'assets/images/under_renovation.png',
width: 200.0,
height: 200.0,
fit: BoxFit.fill,
),
),
);
}
return stack;
@@ -626,7 +737,7 @@ class DesktopShopState extends State<DesktopShop>
cancelButton: CupertinoActionSheetAction(
child: Text(S.of(context).close),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
},
),
);
@@ -872,8 +983,8 @@ class DesktopShopState extends State<DesktopShop>
));
var duration = Duration(
seconds: (_business.distanceInfo.duration != null
? _business.distanceInfo.duration.value
: 30) +
? _business.distanceInfo.duration.value
: 30) +
_business.shippingTime * 60);
var hours = duration.inHours.remainder(60);
var minutes = duration.inMinutes.remainder(60);
@@ -1008,28 +1119,28 @@ class DesktopShopState extends State<DesktopShop>
children: <Widget>[
_business.bulletin.isNotEmpty ? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
children: <Widget>[
Container(
padding:
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
child: Icon(
Icons.announcement,
size: 14.0,
color: Colors.white,
)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
// overflow: TextOverflow.ellipsis,
),
),
],
) : SizedBox.shrink(),
),
],
) : SizedBox.shrink(),
_business.description.isNotEmpty ? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -1276,7 +1387,7 @@ class DesktopShopState extends State<DesktopShop>
height: 70.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
decoration: new BoxDecoration(
color: _categoryIndex == i ? Style.backgroundColor : null,
color: _categoryIndex == i ? Colors.white : null,
border: new Border(
bottom:
new BorderSide(color: new Color(0xFFEBEBEB)))),
@@ -1309,10 +1420,10 @@ class DesktopShopState extends State<DesktopShop>
_categoryIndexChange = true;
_listScrollController1
.animateTo(height,
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
.then((value) {
_categoryIndexChange = false;
});
@@ -1522,10 +1633,11 @@ class DesktopShopState extends State<DesktopShop>
if (it.moveNext()) {
r1.children.add(
Container(
width: (mainSpace - 200) / c,
width: (mainSpace - 200) / c - 4.0,
margin: EdgeInsets.only(top: 2.0, bottom: 2.0, left: 2.0, right: 2.0),
child: ProductItem(
product: it.current,
business: _business,
it.current,
_business,
),
),
);
@@ -1656,128 +1768,6 @@ class DesktopShopState extends State<DesktopShop>
}
});
// onProductWillAddToCartSubscription =
// eventBus.on<OnProductWillAddToCart>().listen((event) {
// if (mounted) {
//
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
//
// if (cartInfo == null || cartInfo.productList.length == 0) {
// cartInfo = CartInfo();
// cartInfo.id = 0;
// cartInfo.amountPaid = 0.0;
// cartInfo.businessInfo = event.business;
// cartInfo.extraFeeList = [];
// cartInfo.discountList = [];
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList = [lineItem];
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (event.product.productAttributes.length > 0) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// int found = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (event.product.id == cartInfo.productList[i].product.id) {
// found = i;
// break;
// }
// }
// if (found == -1) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (cartInfo.productList[found].quantity + 1.0 >
// event.product.leftNum) {
// Fluttertoast.showToast(
// msg: S.of(context).product_insufficient,
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
// backgroundColor: Colors.red,
// textColor: Colors.white);
// } else {
// cartInfo.productList[found].quantity += 1;
// store.dispatch(new UpdateCartInfo(
// Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// }
// }
// }
// });
// onProductWillRemoveFromCartSubscription =
// eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
// if (mounted) {
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
// if (cartInfo != null) {
// if (cartInfo.productList.length > 0) {
// if (event.productListIndex != -1) {
// if (cartInfo.productList[event.productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(event.productListIndex);
// } else {
// cartInfo.productList[event.productListIndex].quantity -= 1;
// }
// } else {
// int productListIndex = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (cartInfo.productList[i].product.id == event.product.id) {
// productListIndex = i;
// break;
// }
// }
// if (productListIndex != -1) {
// if (cartInfo.productList[productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(productListIndex);
// } else {
// cartInfo.productList[productListIndex].quantity -= 1;
// }
// }
// }
// }
//
// if (cartInfo.productList.length <= 0) {
// store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList(
// store.state.cartInfos, cartInfo)));
// } else {
// store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// }
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// });
loadProducts();
}
@@ -1792,68 +1782,80 @@ class DesktopShopState extends State<DesktopShop>
lastProductListScrollPositionPixel = 0;
_productCurrentPage = 1;
Utils.loadProducts(
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
_featuredProducts = (value['featured_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_hotSaleProducts = (value['hot_sale_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_prompts = value['prompt'] as List;
_isSearching = false;
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (_searchController.text.isEmpty) {
responseData = value;
}
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
// _featuredProducts = (value['featured_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
// _hotSaleProducts = (value['hot_sale_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
_featuredProducts = [];
_hotSaleProducts = [];
_prompts = value['prompt'] as List;
checkActionAndClose(context);
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
checkActionAndClose(context);
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
_isSearching = false;
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
if (mounted) {
setState(() {});
}
Utils.showMessageDialog(context, error);
}, featuredCount: 5, hotSaleCount: 0, keyword: _searchController.text
);
}
@@ -1863,59 +1865,59 @@ class DesktopShopState extends State<DesktopShop>
}
_productCurrentPage += 1;
Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
Utils.showMessageDialog(context, error);
}, keyword: _searchController.text
);
}
CartLineItem _newCartLineItem(
{int id,
double price,
Product product,
String name,
String description,
double quantity}) {
double price,
Product product,
String name,
String description,
double quantity}) {
CartLineItem lineItem = CartLineItem();
lineItem.unitPrice = price;
lineItem.product = product;
@@ -2087,10 +2089,10 @@ class DesktopShopState extends State<DesktopShop>
S.of(context).store_closed,
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -2143,10 +2145,10 @@ class DesktopShopState extends State<DesktopShop>
),
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -2169,7 +2171,7 @@ class DesktopShopState extends State<DesktopShop>
title: Text(_prompt['title']),
content: Text(_prompt['message']),
actions: [
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
@@ -2184,6 +2186,158 @@ class DesktopShopState extends State<DesktopShop>
@override
bool get wantKeepAlive => true;
void onSearchTap() {
setState(() {
if (searchIcon.icon == Icons.search) {
searchIcon = new Icon(
Icons.close,
color: Colors.white,
);
if (displayProductByCategoryClick) {
searchFieldPlaceHolder = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child:
TextField(
controller: _searchController,
textInputAction: TextInputAction.search,
onSubmitted: (value) {
onSearchButtonTap();
},
style: TextStyle(
color: Colors.black87,
),
decoration: new InputDecoration(
hintText: S
.of(context)
.enter_keyword,
hintStyle: TextStyle(color: Colors.black26)),
onChanged: searchOperation,
),
),
SizedBox(width: 5,),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.redAccent,
onPrimary: Colors.white,
padding: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
elevation: 2.0,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(5.0),
),
),
onPressed: onSearchButtonTap,
icon: Icon(
Icons.search,
size: 16,
color: Colors.green,
),
label: Text(
S.of(context).search,
style: TextStyle(
color: Colors.green,
),
),
),
],
);
} else {
searchFieldPlaceHolder = TextField(
controller: _searchController,
style: TextStyle(
color: Colors.black87,
),
decoration: new InputDecoration(
hintText: S
.of(context)
.enter_keyword,
hintStyle: TextStyle(color: Colors.black26)),
onChanged: searchOperation,
);
_handleSearchStart();
}
} else {
_handleSearchEnd();
}
});
}
void _handleSearchStart() {
setState(() {
_isSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
searchIcon = new Icon(
Icons.search,
color: Colors.blue,
);
searchFieldPlaceHolder = MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Text(
S.of(context).search_products,
style: new TextStyle(color: Colors.blue),
),
onTap: () {
onSearchTap();
},
),
);
_isSearching = false;
_searchController.clear();
if (displayProductByCategoryClick) {
categoryId = 0;
loadProducts();
}
});
}
void searchOperation(String searchText) {
if (displayProductByCategoryClick) {
} else {
if (responseData != null) {
_categoryProducts.clear();
List<CategoryProducts> cps = (responseData['category_products'] as List)
.map((i) {
CategoryProducts cp = CategoryProducts.fromJson(i);
List<Product> ps = [];
for (Product p in cp.products) {
if (p.name.toLowerCase().contains(searchText.toLowerCase()) ||
p.description.toLowerCase().contains(searchText.toLowerCase()) ||
(p.detailDescription != null && p.detailDescription.toLowerCase().contains(searchText.toLowerCase()))) {
ps.add(p);
}
}
if (ps.length > 0) {
cp.products = ps;
return cp;
}
}).toList();
for (CategoryProducts cp in cps) {
if (cp != null) {
_categoryProducts.add(cp);
}
}
print('$searchText, count: ${_categoryProducts.length}');
setState(() {});
}
}
}
void onSearchButtonTap() {
String kw = _searchController.text;
if (kw.isNotEmpty) {
_handleSearchStart();
loadProducts();
}
}
}
class _SliverAppBarDelegate2 extends SliverPersistentHeaderDelegate {

View File

@@ -0,0 +1,70 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../models/business.dart';
class ShopBulletin extends StatefulWidget {
final Business business;
const ShopBulletin(this.business, {Key key}): super(key: key);
@override
State<StatefulWidget> createState() => ShopBulletinState();
}
class ShopBulletinState extends State<ShopBulletin> {
double sideSpace = 0;
double mainSpace = 1200;
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
if (widget.business.bulletin != null && widget.business.bulletin.isNotEmpty) {
return Container(
margin: EdgeInsets.only(bottom: 12),
child: Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: Container(
padding: EdgeInsets.only(top: 10, left: 16.0, right: 16.0, bottom: 10.0),
child: Text(
'${widget.business.bulletin}',
overflow: TextOverflow.ellipsis,
maxLines: 3,
style: TextStyle(
color: Colors.white,
),
),
decoration: BoxDecoration(
color: Colors.orangeAccent,
border: Border.all(
color: Colors.red[500],
width: 1.0,
),
borderRadius: BorderRadius.all(Radius.circular(16)),
),
),
),
Container(
width: sideSpace,
),
],
),
);
}
return SizedBox.shrink();
}
}

View File

@@ -0,0 +1,431 @@
import 'package:badges/badges.dart';
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/cart_info.dart';
import '../../models/category_products.dart';
import '../../store/store.dart';
import '../../utils/utils.dart';
import '../../widgets/desktop/product_item.dart';
class ShopProducts extends StatefulWidget {
final dynamic data;
const ShopProducts(this.data, {Key key}): super(key: key);
@override
State<StatefulWidget> createState() => ShopProductsState();
}
class ShopProductsState extends State<ShopProducts> {
double sideSpace = 0;
double mainSpace = 1200;
dynamic data;
static const num _categoryHeight = 50.0;
static const num _categoryDescHeight = 50.0;
static const num _productHeight = 266.0;
bool displayProductByCategoryClick = false;
String displayProductByCategoryClickIndicator = '';
int categoryId = 0;
double leftSideMenuWidth = 0;
int _categoryIndex = 0;
List<CategoryProducts> _categoryProducts = [];
Business _business;
double menuPosition = 0;
ScrollController _menuScrollController = ScrollController();
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: sideSpace,
),
Expanded(
child: Container(
child:
// Row(
// mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// _buildCategories(),
// Expanded(
// child: _buildProducts(),
// ),
// ],
// ),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
_buildCategories(),
Expanded(
child: _buildProducts(),
),
],
),
),
),
),
Container(
width: sideSpace,
),
],
),
);
}
Widget _buildCategories() {
return new Container(
width: leftSideMenuWidth,
height: 500,
color: new Color(0xFFF5F5F5),
child: new SizedBox.expand(
child: ListView.builder(
physics: ClampingScrollPhysics(),
controller: _menuScrollController,
itemCount: _categoryProducts == null ? 0 : _categoryProducts.length,
itemBuilder: (BuildContext context, int i) {
CategoryProducts cp = _categoryProducts[i];
int qtyInCategory = 0;
CartInfo cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, _business);
if (cartInfo != null &&
cartInfo.businessInfo.id == _business.id &&
cartInfo.productList != null) {
for (var i = 0; i < cartInfo.productList.length; i++) {
if (cartInfo.productList[i].product.categoryId == cp.id) {
qtyInCategory += cartInfo.productList[i].quantity.ceil();
}
}
}
Row categoryRow = Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[],
);
categoryRow.children.add(
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(top: 5.0, bottom: 5.0),
child: Text(
cp.name,
style: TextStyle(
fontSize: 13.0,
fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id == Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
softWrap: true,
maxLines: 2,
),
),
),
);
if (qtyInCategory > 0) {
categoryRow.children.add(
Badge(
badgeContent: Text(
'$qtyInCategory',
style: TextStyle(
color: Colors.white,
fontSize: 11.0,
),
),
animationType: BadgeAnimationType.scale,
),
);
} else {
categoryRow.children.add(SizedBox.shrink());
}
return GestureDetector(
child: new Container(
height: 70.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
decoration: new BoxDecoration(
color: cp.id == categoryId ? Colors.white : null,
border: new Border(
bottom:
new BorderSide(color: new Color(0xFFEBEBEB)))),
child: categoryRow,
),
onTap: () => _selectCategory(cp.id),
);
}
),
),
);
}
void _selectCategory(int i) {
categoryId = i;
eventBus.fire(CategoryChangeEvent(i));
}
Widget _buildProducts() {
if (_categoryProducts == null) {
return SizedBox.shrink();
}
Column col = new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[],
);
for (int i = 0; i < _categoryProducts.length; i++) {
CategoryProducts cp = _categoryProducts[i];
if (cp.products.length > 0) {
col.children.add(new Container(
height: _categoryDescHeight,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
color: new Color(0xFFF5F5F5),
child: new Row(
children: <Widget>[
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 5.0),
child: new Text(
cp.name,
style: new TextStyle(
fontSize: 16.0,
fontWeight:
(cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id ==
Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
overflow: TextOverflow.ellipsis,
),
),
new Visibility(
visible: cp.description.isNotEmpty,
child: new Text(
cp.description,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)),
),
replacement: const SizedBox.shrink()),
],
))
],
)));
var it = cp.products.iterator;
for (int i = 0; i < cp.products.length; i++) {
var r1 = Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [],
);
double d = getProductCountInRow();
int c = int.parse(d.toString());
while (d > 0) {
if (it.moveNext()) {
r1.children.add(
Container(
width: (mainSpace - leftSideMenuWidth) / c - 4.0,
margin: EdgeInsets.only(top: 2.0, bottom: 2.0, left: 2.0, right: 2.0),
child: ProductItem(
it.current,
_business,
),
),
);
}
d -= 1;
}
col.children.add(r1);
}
if (displayProductByCategoryClick) {
if (displayProductByCategoryClickIndicator.isNotEmpty) {
col.children.add(
Container(
padding: EdgeInsets.all(12.0),
child: Center(
child: Text(
displayProductByCategoryClickIndicator,
style: TextStyle(
color: Colors.black54,
),
),
),
),
);
} else if (categoryId > 0) {
if (cp.products.length < Constants.ORDERS_PER_PAGE) {
col.children.add(
Container(
padding: EdgeInsets.all(12.0),
child: Center(
child: Text(
S
.of(context)
.end_of_the_list,
style: TextStyle(
color: Colors.black54,
),
),
),
),
);
} else {
col.children.add(
Container(
padding: EdgeInsets.all(12.0),
child: Center(
child: Text(
S
.of(context)
.pull_up_to_load_more,
style: TextStyle(
color: Colors.black54,
),
),
),
),
);
}
}
}
}
}
return col;
}
void loadData() {
// _categoryProducts .clear();
_categoryProducts = (data['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
_business = Business.fromJson(data['business']);
displayProductByCategoryClick = data['display_product_by_category_click'];
if (displayProductByCategoryClick) {
leftSideMenuWidth = 200;
}
displayProductByCategoryClickIndicator = '';
if (categoryId == 0 && displayProductByCategoryClick) {
categoryId = _categoryProducts[0].id;
}
setState(() {
});
}
@override
void initState() {
super.initState();
data = widget.data;
loadData();
eventBus.on<GetCategoryProducts>().listen((event) {
if (mounted) {
data = event.data;
loadData();
}
});
eventBus.on<MoreCategoryProducts>().listen((event) {
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts = event.data;
if (moreCategoryProducts.isEmpty) {
displayProductByCategoryClickIndicator = S
.of(context)
.end_of_the_list;
} else {
if (moreCategoryProducts[0].products.length <
Constants.ORDERS_PER_PAGE) {
displayProductByCategoryClickIndicator = S
.of(context)
.end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S
.of(context)
.pull_up_to_load_more;
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
displayProductByCategoryClickIndicator = S
.of(context)
.end_of_the_list;
}
}
});
}
});
}
int numCategoriesHasProducts() {
int num = 0;
for (CategoryProducts cp in _categoryProducts) {
if (cp.products.length > 0) {
num += 1;
}
}
return num;
}
CategoryProducts getCategoryProductByCategoryId(int cid) {
for (CategoryProducts cp in _categoryProducts) {
if (cp.id == cid) {
return cp;
}
}
return null;
}
double getProductCountInRow() {
double d = 2;
if (mainSpace >= 800 && mainSpace < 1000) {
d = 3;
} else if (mainSpace >= 1000) {
d = 4;
}
return d;
}
}

View File

@@ -0,0 +1,185 @@
import 'package:flutter/material.dart';
import '../../generated/l10n.dart';
import '../../pages/product_detail_page.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/show_price.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
class ShopPromote extends StatefulWidget {
final dynamic data;
const ShopPromote(this.data, {Key key}): super(key: key);
@override
State<StatefulWidget> createState() => ShopPromoteState();
}
class ShopPromoteState extends State<ShopPromote> {
double sideSpace = 0;
double mainSpace = 1200;
Business _business;
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
Row promoteRow = getPromoteRow();
if (promoteRow.children.length > 0) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: sideSpace,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(top: 12, bottom: 6),
child: Text(
S.of(context).promotions,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Container(
padding: EdgeInsets.only(bottom: 10),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: promoteRow,
),
),
],
),
),
Container(
width: sideSpace,
),
],
),
);
} else {
return SizedBox.shrink();
}
}
@override
void initState() {
super.initState();
_business = Business.fromJson(widget.data['business']);
}
Row getPromoteRow() {
Row promotRow = Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[],
);
for (var i = 0; i < _business.promoProducts.length; i++) {
promotRow.children.add(Container(
padding: EdgeInsets.only(
left: 10.0,
top: 10.0,
bottom: 10.0,
right: 10.0,
),
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
width: 220.0,
height: 220.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Colors.white,
border: Border(
top: BorderSide(
width: 1.0,
color: Colors.black12,
),
bottom: BorderSide(
width: 1.0,
color: Colors.black12,
),
left: BorderSide(
width: 1.0,
color: Colors.black12,
),
right: BorderSide(
width: 1.0,
color: Colors.black12,
),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
child: Container(
child: Util.showImage(
_business.promoProducts[i].imagePath,
width: 120.0,
),
),
onTap: () {
_showProductDetail(_business.promoProducts[i]);
},
),
Container(
child: Text(
_business.promoProducts[i].name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14.0),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ShowPrice(
_business.promoProducts[i].price,
currencySign: '\$',
fontWeight: FontWeight.bold,
smallFontSize: 15,
largeFontSize: 24,
regularPrice: _business.promoProducts[i].regularPrice,
),
Container(
child: AddRemoveButton(
product: _business.promoProducts[i],
business: _business,
addOnly: true,
),
)
],
)
],
),
));
}
return promotRow;
}
void _showProductDetail(Product p) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: _business,
)),
);
}
}

View File

@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../models/business.dart';
import '../../models/cart_info.dart';
import '../../store/store.dart';
import '../../utils/utils.dart';
class ShoppingCartWidget extends StatefulWidget {
final Business business;
final Function onTap;
ShoppingCartWidget({@required this.business, this.onTap});
@override
State<StatefulWidget> createState() => ShoppingCartWidgetState();
}
class ShoppingCartWidgetState extends State<ShoppingCartWidget> {
CartInfo cartInfo;
double totalPrice = 0.0;
@override
Widget build(BuildContext context) {
totalPrice = 0.0;
cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business);
if (cartInfo != null && cartInfo.businessInfo.id == widget.business.id) {
totalPrice = cartInfo.getTotalPrice();
}
Row row = Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.only(left: 16.0, right: 4.0, top: 8.0),
child: Icon(
Icons.shopping_basket_outlined,
size: 24,
color: Colors.blue,
),
),
Container(
padding: EdgeInsets.only(left: 4.0, right: 16.0, top: 8.0),
child: Text(
'\$${totalPrice.toStringAsFixed(2)}',
style: TextStyle(
color: totalPrice > 0 ? Colors.red : Colors.black45,
fontWeight: totalPrice > 0 ? FontWeight.bold : FontWeight.normal,
),
),
),
],
);
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Container(
child: row,
width: 160.0,
),
onTap: widget.onTap,
),
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
}
}

View File

@@ -4,11 +4,13 @@ import 'package:flutter/rendering.dart';
import '../../generated/l10n.dart';
import '../../routes.dart';
import 'navigationbar.dart';
class BreadCrumbs extends StatelessWidget {
final List<BreadCrumb> breadCrumbs;
final bool hasBack;
const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key}) : super(key: key);
final OnBackPress onBackPress;
const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key, this.onBackPress}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -39,8 +41,8 @@ class BreadCrumbs extends StatelessWidget {
),
],
),
onTap: () {
Routes.router.pop(context);
onTap: onBackPress != null ? onBackPress : () {
Navigator.of(context).maybePop();
},
),
),
@@ -72,7 +74,7 @@ class BreadCrumbs extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(top: 0.0),
padding: EdgeInsets.only(top: 6.0, left: 4.0, right: 4.0),
child: Icon(
Icons.circle,
size: 6.0,
@@ -123,7 +125,7 @@ class BreadCrumbs extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(top: 0.0),
padding: EdgeInsets.only(top: 6.0, left: 4.0, right: 4.0),
child: Icon(
Icons.circle,
size: 6.0,

View File

@@ -6,7 +6,9 @@ import '../../widgets/desktop/desktop_navigationbar.dart';
import '../../widgets/mobile/mobile_navigationbar.dart';
import 'breadcrumbs.dart';
class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
typedef OnBackPress();
class MiniNavigationBar extends StatefulWidget implements PreferredSizeWidget {
final Key key;
final String title;
final bool back;
@@ -16,7 +18,7 @@ class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
final double breadCrumbHeight;
final Widget shoppingCart;
NavigationBar({Key key, PreferredSizeWidget bottom, String title,
MiniNavigationBar({Key key, PreferredSizeWidget bottom, String title,
bool back, bool toHome, bool showMe, this.breadCrumbs,
this.breadCrumbHeight, this.shoppingCart})
: key = key,
@@ -32,12 +34,12 @@ class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
@override
State<StatefulWidget> createState() {
return NavigationBarState();
return MiniNavigationBarState();
}
}
class NavigationBarState extends State<NavigationBar> {
class MiniNavigationBarState extends State<MiniNavigationBar> {
@override
Widget build(BuildContext context) {

View File

@@ -33,6 +33,9 @@ class PaymentVerificationCodeDialogState extends State<PaymentVerificationCodeDi
String getCodeText = '';
String paymentCodeEncrypt = '';
String verifyMethod;
String verifyName;
final TextEditingController _pinPutController = TextEditingController();
final FocusNode _pinPutFocusNode = FocusNode();
BoxDecoration get _pinPutDecoration {
@@ -53,12 +56,15 @@ class PaymentVerificationCodeDialogState extends State<PaymentVerificationCodeDi
Container(
padding: EdgeInsets.only(top: 0.0, bottom: 10.0, left: 0.0, right: 0.0),
child: Text(
S.of(context).payment_verification_sent(Utils.safePhoneNumber(widget.user.mobile)),
(verifyMethod != null) ? S.of(context).payment_verification_sent(
(verifyName == 'sms') ? S.of(context).mobile : S.of(context).email,
Utils.safePhoneNumber(verifyName)
) : '',
),
),
Container(
padding: EdgeInsets.only(top: 0.0, bottom: 10.0, left: 0.0, right: 0.0),
child: FlatButton(
child: TextButton(
child: Text(getCodeText),
onPressed: enableGetCode ? () {
getPaymentCode();
@@ -146,6 +152,8 @@ class PaymentVerificationCodeDialogState extends State<PaymentVerificationCodeDi
},
).then((data) {
paymentCodeEncrypt = data['payment_code_encrypt'];
verifyMethod = data['verify_method'];
verifyName = data['verify_name'];
print('data: $data');
startCountDown();
}).catchError((error) {

View File

@@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/models/business.dart';
import 'package:flutter_wisetronic/models/product.dart';
import 'package:flutter_wisetronic/widgets/desktop/desktop_product_item.dart';
import 'package:flutter_wisetronic/widgets/mobile/mobile_product_item.dart';
import 'package:responsive_builder/responsive_builder.dart';
class ProductItem extends StatelessWidget {
final Product product;
final Business business;
const ProductItem({Key key, this.product, this.business}) : super(key: key);
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
ScreenTypeLayout(
mobile: MobileProductItem(product: product, business: business,),
tablet: DesktopProductItem(product: product, business: business,),
desktop: DesktopProductItem(product: product, business: business,),
),
);
}
}

View File

@@ -3,6 +3,7 @@ import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_wisetronic/utils/utils.dart';
import 'package:hovering/hovering.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../routes.dart';
@@ -11,6 +12,7 @@ class TextLink extends StatelessWidget {
final String title;
final String url;
final Color color;
final Color hoverColor;
final double paddingHorizontal;
final double paddingVertical;
final FontWeight fontWeight;
@@ -24,8 +26,14 @@ class TextLink extends StatelessWidget {
final bool closeDrawer;
final bool isEmail;
final bool isPhone;
final double fontSize;
final bool isAddress;
final TextOverflow overflow;
final int maxLines;
TextLink(this.title, this.url, {
this.color,
this.hoverColor,
this.paddingHorizontal,
this.paddingVertical,
this.fontWeight,
@@ -39,6 +47,10 @@ class TextLink extends StatelessWidget {
bool closeDrawer,
bool isEmail,
bool isPhone,
double fontSize,
bool isAddress,
TextOverflow overflow,
int maxLines,
}) :
isLink = isLink ?? false,
replace = replace ?? false,
@@ -47,7 +59,11 @@ class TextLink extends StatelessWidget {
rootNavigator = rootNavigator ?? false,
closeDrawer = closeDrawer ?? false,
isEmail = isEmail ?? false,
isPhone = isPhone ?? false;
isPhone = isPhone ?? false,
fontSize = fontSize ?? null,
isAddress = isAddress ?? false,
overflow = overflow ?? TextOverflow.ellipsis,
maxLines = maxLines ?? 1;
@override
Widget build(BuildContext context) {
@@ -59,19 +75,37 @@ class TextLink extends StatelessWidget {
vertical: paddingVertical ?? 0.0,
horizontal: paddingHorizontal ?? 0.0
),
child: Text(
title,
style: TextStyle(
color: color ?? Colors.blue,
fontWeight: fontWeight ?? FontWeight.normal,
child: HoverWidget(
child: Text(
title,
style: TextStyle(
color: color ?? Colors.blue,
fontWeight: fontWeight ?? FontWeight.normal,
fontSize: fontSize,
),
overflow: overflow,
maxLines: maxLines,
),
hoverChild: Text(
title,
style: TextStyle(
color: hoverColor ?? Colors.grey,
fontSize: fontSize,
fontWeight: fontWeight ?? FontWeight.normal,
),
overflow: overflow,
maxLines: maxLines,
),
onHover: (event) {
},
),
decoration: BoxDecoration(
border: (selected != null && selected) ? Border(
bottom: BorderSide(
color: color ?? Colors.blue,
width: 3.0,
)
bottom: BorderSide(
color: color ?? Colors.blue,
width: 3.0,
)
) : null,
),
),
@@ -81,6 +115,8 @@ class TextLink extends StatelessWidget {
Utils.openEmail(url);
} else if (isPhone) {
Utils.callPhone(url);
} else if (isAddress) {
await launch('https://maps.google.com/?q=${url}');
} else if (!isLink) {
if (closeDrawer) {
Routes.router.pop(context);

View File

@@ -0,0 +1,411 @@
import 'package:flutter/material.dart';
import '/models/group.dart';
import '/pages/buy_service.dart';
import '../../constants.dart';
import '../../generated/l10n.dart';
import '../../routes.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
class CreateOnlineStore1 extends StatefulWidget {
final int businessId;
const CreateOnlineStore1(this.businessId, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return CreateOnlineStore1State();
}
}
class CreateOnlineStore1State extends State<CreateOnlineStore1> {
TextEditingController groupNumberController = TextEditingController();
TextEditingController domainController = TextEditingController();
bool canSubmit = false;
List<dynamic> stores = [];
Map<String, dynamic> service;
dynamic selectedStore;
Group group;
String selectedDomain;
List<dynamic> domainResult = [];
@override
Widget build(BuildContext context) {
Column col = Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 20, left: 16, right: 16, bottom: 10,),
child: Text(
S.of(context).open_online_store,
style: TextStyle(
fontSize: 28,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4, bottom: 4, left: 16.0, right: 16.0),
child: Text(
S.of(context)
.select_a_store,
style: TextStyle(
color: Colors.black45,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4, bottom: 4, left: 16.0, right: 16.0),
child: DropdownButton<dynamic>(
items: stores.map((e) => DropdownMenuItem<dynamic>(
value: e,
child: Text(e['name']),
)).toList(),
isExpanded: false,
hint: Text(S.of(context).select_a_store),
onChanged: (newValue) {
print('newValue $newValue');
setState(() {
selectedStore = newValue;
});
},
value: selectedStore,
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(
left: 16.0, right: 16.0, top: 20, bottom: 20),
child: Visibility(
child: getSearchDomainWidget(),
visible: selectedStore != null,
),
),
);
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: (){
Navigator.of(context).pop();
},
),
title: Text(S.of(context).open_online_store),
backgroundColor: Theme.of(context).primaryColor,
),
body: SingleChildScrollView(
child: col,
),
);
}
Widget getSearchDomainWidget() {
if (selectedStore == null) {
return SizedBox.shrink();
}
Column col = Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
col.children.add(
Container(
padding: EdgeInsets.only(bottom: 4,),
child: Text(selectedStore == null ? '' : selectedStore['name'],
style: TextStyle(
fontSize: 28,
),
),
),
);
Map<String, dynamic> existing_web_svc;
if (selectedStore != null && (selectedStore['services'] as List).length > 0) {
for (Map<String, dynamic>svc in (selectedStore['services'] as List)) {
if (svc['code'] == Constants.WEB_MINISTORE_SERVICE) {
existing_web_svc = svc;
break;
}
}
}
if (existing_web_svc != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'${existing_web_svc['description']}',
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).expiration_date + ": "
+ Utils.utcDatetimeStringToLocalDatetimeString(context, existing_web_svc['expiration_date']),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).store + ": " + '${existing_web_svc['store']['name']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).domain_name + ": " + '${existing_web_svc['domain']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(S.of(context).renew_service_now),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: existing_web_svc['domain'],
sid: existing_web_svc['store']['id'],
),
));
},
),
),
);
} else {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(S.of(context).enter_desired_domain),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 0,),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: TextFormField(
controller: domainController,
decoration: new InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black12,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
labelText: S.of(context).domains_separated_comma,
),
style: TextStyle(
fontSize: 18.0
),
autofocus: true,
validator: (String value) {
if (value.trim().isEmpty) {
return S.of(context).domains_separated_comma;
}
return null;
},
onChanged: (string) {
if (string.isNotEmpty) {
canSubmit = true;
} else {
canSubmit = false;
}
setState(() {});
},
),
),
Container(
padding: EdgeInsets.only(left: 8.0),
child: ElevatedButton(
child: Text(
S.of(context).check_domain_name,
),
onPressed: domainController.text.length > 0 ? checkDomainAvailability : null,
),
),
],
),
)
);
if (domainResult.length > 0) {
for (dynamic dr in domainResult) {
col.children.add(_getDomain(dr));
}
}
if (selectedDomain != null && service != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['description'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['options'][0]['name'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'\$${service['options'][0]['price']}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.orange,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(
S.of(context).place_order_now,
),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: selectedDomain,
sid: selectedStore['id'],
),
));
},
),
),
);
}
}
return Container(
padding: EdgeInsets.only(bottom: 4,),
child: col,
);
}
@override
void initState() {
super.initState();
HttpUtil.httpGet(
'v1/get-contact-stores',
queryParameters: {
'service': Constants.WEB_MINISTORE_SERVICE
}
).then((value) {
setState(() {
stores = value['stores'];
service = value['service'];
group = Group.fromJson(value['group']);
print('stores: ${value}');
});
}).onError((error, stackTrace) {
Utils.showMessageDialog(context, error, onOk: () {
Routes.router.navigateTo(context, '/');
});
});
}
Future<void> checkDomainAvailability() async {
Utils.showLoadingDialog(context);
selectedDomain = null;
domainResult = [];
setState(() {});
HttpUtil.httpGet(
'v1/check-domain-availability',
queryParameters: {
'domain': domainController.text,
},
).then((value) {
Routes.router.pop(context);
print('value: $value');
if (value['status'] == 'OK') {
domainResult = (value['domain_check_result'] as List);
setState(() {});
} else if (value['status'] == 'ERROR') {
String errors = '';
for (int i = 0; i < (value['errors'] as List).length; i++) {
errors += value['errors'][i] + '\n';
}
Utils.showMessageDialog(context, errors);
}
}).onError((error, stackTrace) {
Routes.router.pop(context);
Utils.showMessageDialog(context, error);
});
}
Widget _getDomain(dynamic d) {
if ((d['available'] as bool)) {
return Container(
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
leading: Radio(
value: d['domain'],
groupValue: selectedDomain,
onChanged: (val) {
setState(() {
selectedDomain = val;
});
},
),
),
);
} else {
return Container(
padding: EdgeInsets.only(top: 1.0),
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
color: Colors.black45,
),
),
leading: Icon(Icons.clear, color: Colors.red,),
),
);
}
}
}

View File

@@ -52,6 +52,18 @@ class MobileBuyServiceState extends State<MobileBuyService> {
Utils.buildLine(S.of(context).your_group, widget.data['group']['name'], valueSize: 16),
);
if (widget.data['store']['id'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).store, widget.data['store']['name'], valueSize: 16),
);
}
if (widget.data['domain'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).domain_name, widget.data['domain'], valueSize: 16),
);
}
if (widget.data['exists_service'] == null) {
col1.children.add(
Utils.buildLine(S.of(context).current_plan, 'N/A', valueSize: 16),

View File

@@ -335,6 +335,7 @@ class MobileCheckoutState extends State<MobileCheckout> with SingleTickerProvide
check();
},
initialLabelIndex: deliveryMethodIndex,
totalSwitches: shippingMethodLabels.length,
);
switch (position) {
case 0:

View File

@@ -189,6 +189,7 @@ class MobileNavigationDrawerState extends State<MobileNavigationDrawer> {
TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,),
TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,),
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,),
TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 10.0,),
Container(
margin: EdgeInsets.only(top: 20.0, bottom: 10.0),
child: Text(

View File

@@ -1,92 +0,0 @@
import '../../constants.dart';
import '../../utils/iframe_web.dart' if (dart.library.io) '../../utils/fake_iframe_web.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class MobileTutorials extends StatefulWidget {
const MobileTutorials({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MobileTutorialsState();
}
}
class MobileTutorialsState extends State<MobileTutorials> {
InAppWebViewController webView;
String url = "";
double progress = 0;
bool isLoadStop = false;
@override
Widget build(BuildContext context) {
if (kIsWeb) {
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: IFrameWeb(
width: double.maxFinite.toString(),
height: double.maxFinite.toString(),
src: Constants.TUTORIAL_URL,
),
),
],
);
} else {
print('progress: $progress');
return Stack(
children: [
InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse(Constants.TUTORIAL_URL)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (controller, url) {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = false;
});
}
},
onLoadStop: (controller, url) async {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = true;
});
}
},
onProgressChanged: (InAppWebViewController controller, int progress) {
if (mounted) {
setState(() {
if (this.progress < 1.0) {
this.isLoadStop = false;
} else {
this.isLoadStop = true;
}
this.progress = progress / 100;
});
}
},
),
isLoadStop ? Container() :
Center(
child: CircularProgressIndicator(),
),
],
);
}
}
}

View File

@@ -13,6 +13,8 @@ import '../../store/store.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
class MobileViewBlog extends StatefulWidget {
final Key key;
final int bid;
@@ -126,11 +128,7 @@ class MobileViewBlogState extends State<MobileViewBlog> {
Container(
width: min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) - 100.0,
height: min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) - 100.0,
child: PhotoView(
imageProvider: NetworkImage(
'https:${blog.imageUrl}',
),
),
child: Util.showImage('https:${blog.imageUrl}'),
) : SizedBox.shrink(),
decoration: BoxDecoration(
border: Border(

View File

@@ -0,0 +1,261 @@
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/show_price.dart';
class ProductItem extends StatefulWidget {
final Business business;
final Product product;
final bool horizontal;
final double imageWidth;
const ProductItem(this.product, this.business, {
Key key,
this.horizontal = false,
this.imageWidth = 110,
}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductItemState();
}
class ProductItemState extends State<ProductItem> {
@override
Widget build(BuildContext context) {
return Container(
// width: 160.0,
height: widget.horizontal ? Constants.PRODUCT_ITEM_HEIGHT_H : Constants.PRODUCT_ITEM_HEIGHT_V,
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
bottom: new BorderSide(
color: new Color(0xFFEBEBEB),
),
),
),
child: new SizedBox.expand(
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0),
child: widget.horizontal ? getHorizontal(true) : getVertial(true),
),
),
);
}
Widget getHorizontal(bool onHover) {
Row row1 = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: new EdgeInsets.all(10.0),
width: widget.imageWidth,
height: widget.imageWidth,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
],
),
),
],
);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
row1,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
);
}
Widget getVertial(bool onHover) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: new EdgeInsets.all(10.0),
width: widget.imageWidth,
height: widget.imageWidth,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Container(
child: Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
),
),
],
);
}
void _showProductDetail() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: widget.product,
business: widget.business,
)),
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
}
}

View File

@@ -0,0 +1,152 @@
import 'package:dio/dio.dart';
import 'package:flappy_search_bar/flappy_search_bar.dart';
import 'package:flutter/material.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
import 'product_item.dart';
class ProductSearch extends StatefulWidget {
final Business business;
const ProductSearch(this.business, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductSearchState();
}
class ProductSearchState extends State<ProductSearch> {
int page = 1;
int numPerPage = 10;
int lastResultSize = 0;
double lastBottomPosition = 0;
String lastKeyword = '';
SearchBarController _controller = SearchBarController<Product>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MiniNavigationBar(
title: S.of(context).search_product,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).search_product, null),
],
),
drawer: null,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: NotificationListener<ScrollNotification>(
child: SearchBar(
searchBarController: _controller,
minimumChars: 2,
hintText: S.of(context).enter_keyword,
cancellationWidget: Text(
S.of(context).cancel,
),
onSearch: search,
onItemFound: (Product searchProduct, int index) {
return ProductItem(
searchProduct,
widget.business,
horizontal: true,
imageWidth: 80.0,
);
},
onError: (error) {
return Center(
child: Text("$error"),
);
},
emptyWidget: Center(
child: Text(
S.of(context).empty_result_change_keyword,
),
),
),
onNotification: (notification) {
if (notification.metrics.atEdge) {
print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}');
if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) {
if (notification.metrics.pixels > lastBottomPosition) {
lastBottomPosition = notification.metrics.pixels;
page += 1;
_controller.replayLastSearch();
}
}
}
return true;
},
),
),
),
bottomNavigationBar: null,
);
}
Future<List<Product>> search(String keyword) async {
if (lastKeyword != keyword) {
page = 1;
}
lastKeyword = keyword;
var result = await HttpUtil.httpGet('v1/search-store-product2',
queryParameters: {
'store_id': widget.business.id,
'keyword': keyword,
'page': page,
'num_per_page': numPerPage,
},
returnError: true,
);
if (result is DioError) {
if (result.response != null) {
throw RuntimeError(result.response.data);
} else {
throw RuntimeError(result.message);
}
} else if (result != null && result is List) {
lastBottomPosition = 0;
var r = result.map((e) => Product.fromJson(e)).toList();
lastResultSize = r.length;
if (lastResultSize < numPerPage) {
page = 1;
}
return r;
}
return [];
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {});
}
});
}
void _showProductDetail(Product p) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: widget.business,
)),
);
}
}

View File

@@ -1,63 +1,59 @@
import 'dart:async';
import 'dart:math';
import 'package:badges/badges.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_wisetronic/events/eventbus.dart';
import 'package:flutter_wisetronic/events/events.dart';
import 'package:flutter_wisetronic/generated/l10n.dart';
import 'package:flutter_wisetronic/models/business.dart';
import 'package:flutter_wisetronic/models/cart_info.dart';
import 'package:flutter_wisetronic/models/cart_line_item.dart';
import 'package:flutter_wisetronic/models/category_products.dart';
import 'package:flutter_wisetronic/models/comment.dart';
import 'package:flutter_wisetronic/models/product.dart';
import 'package:flutter_wisetronic/models/product_image.dart';
import 'package:flutter_wisetronic/pages/product_detail_page.dart';
import 'package:flutter_wisetronic/store/store.dart';
import 'package:flutter_wisetronic/utils/http_util.dart';
import 'package:flutter_wisetronic/utils/shop_scroll_controller.dart';
import 'package:flutter_wisetronic/utils/shop_scroll_coordinator.dart';
import 'package:flutter_wisetronic/utils/utils.dart';
import 'package:flutter_wisetronic/widgets/general/add_remove_button.dart';
import 'package:flutter_wisetronic/widgets/general/animation_point_manager.dart';
import 'package:flutter_wisetronic/widgets/general/carousel.dart';
import 'package:flutter_wisetronic/widgets/general/read_more_text.dart';
import 'package:flutter_wisetronic/widgets/general/show_price.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_wisetronic/widgets/general/sliding_up_panel.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/cart_info.dart';
import '../../models/cart_line_item.dart';
import '../../models/category_products.dart';
import '../../models/comment.dart';
import '../../models/product.dart';
import '../../models/product_image.dart';
import '../../pages/product_detail_page.dart';
import '../../pages/store_product_search.dart';
import '../../routes.dart';
import '../../store/actions.dart';
import '../../store/store.dart';
import '../../utils/http_util.dart';
import '../../utils/shop_scroll_controller.dart';
import '../../utils/shop_scroll_coordinator.dart';
import '../../utils/util_web.dart'
if (dart.library.io) '../../utils/util_io.dart';
import '../../utils/utils.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/animation_point_manager.dart';
import '../../widgets/general/carousel.dart';
import '../../widgets/general/product_item.dart';
import '../../widgets/general/read_more_text.dart';
import '../../widgets/general/sliding_up_panel.dart';
import '../../widgets/general/style.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import 'product_item.dart';
import 'product_search.dart';
import 'shopping_cart_bar.dart';
class MobileShop extends StatefulWidget {
final int businessId;
const MobileShop({Key key, this.businessId}) : super(key: key);
@override
State<StatefulWidget> createState() => MobileShopState();
}
MediaQueryData mediaQuery;
double statusBarHeight;
double screenWidth;
double screenHeight;
class MobileShopState extends State<MobileShop>
class Shop extends StatefulWidget {
final int businessId;
const Shop({Key key, this.businessId}) : super(key: key);
@override
State<StatefulWidget> createState() => ShopState();
}
class ShopState extends State<Shop>
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Business _business;
@@ -75,7 +71,7 @@ class MobileShopState extends State<MobileShop>
static const num _categoryHeight = 50.0;
static const num _categoryDescHeight = 50.0;
static const num _productHeight = 115.0;
static const num _productHeight = Constants.PRODUCT_ITEM_HEIGHT_H;
int _categoryIndex = 0;
bool _categoryIndexChange = false;
@@ -103,7 +99,7 @@ class MobileShopState extends State<MobileShop>
int _commentPageCount = 1;
bool _commentLoadingFinish = false;
RefreshController _commentRefreshController =
RefreshController(initialRefresh: true);
RefreshController(initialRefresh: true);
PanelController panelController = PanelController();
SlidingUpPanel _slidUpShoppingCart;
@@ -256,9 +252,33 @@ class MobileShopState extends State<MobileShop>
padding: EdgeInsets.only(
left: 10.0,
top: 10.0,
right: 10.0,
bottom: 10.0,
),
width: 150.0,
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Colors.white,
border: Border(
top: BorderSide(
width: 1.0,
color: Colors.black12,
),
bottom: BorderSide(
width: 1.0,
color: Colors.black12,
),
left: BorderSide(
width: 1.0,
color: Colors.black12,
),
right: BorderSide(
width: 1.0,
color: Colors.black12,
),
),
),
width: 160.0,
height: 220.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -267,6 +287,7 @@ class MobileShopState extends State<MobileShop>
child: Container(
child: Util.showImage(
_business.promoProducts[i].imagePath,
width: 110.0,
),
),
onTap: () {
@@ -308,7 +329,7 @@ class MobileShopState extends State<MobileShop>
pinned: false,
floating: true,
delegate: _SliverAppBarDelegate2(
minHeight: 250.0,
minHeight: 256.0,
maxHeight: 260.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
@@ -359,7 +380,7 @@ class MobileShopState extends State<MobileShop>
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
if (_animationFinish) {
Routes.router.pop(context);
Navigator.of(context).maybePop();
}
}),
titleSpacing: 0.0,
@@ -371,8 +392,8 @@ class MobileShopState extends State<MobileShop>
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return StoreProductSearch(_business);
}));
return ProductSearch(_business);
}));
},
),
),
@@ -540,7 +561,7 @@ class MobileShopState extends State<MobileShop>
cancelButton: CupertinoActionSheetAction(
child: Text(S.of(context).close),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
},
),
);
@@ -786,8 +807,8 @@ class MobileShopState extends State<MobileShop>
));
var duration = Duration(
seconds: (_business.distanceInfo.duration != null
? _business.distanceInfo.duration.value
: 30) +
? _business.distanceInfo.duration.value
: 30) +
_business.shippingTime * 60);
var hours = duration.inHours.remainder(60);
var minutes = duration.inMinutes.remainder(60);
@@ -922,28 +943,28 @@ class MobileShopState extends State<MobileShop>
children: <Widget>[
_business.bulletin.isNotEmpty ? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
children: <Widget>[
Container(
padding:
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
child: Icon(
Icons.announcement,
size: 14.0,
color: Colors.white,
)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
// overflow: TextOverflow.ellipsis,
),
),
],
) : SizedBox.shrink(),
),
],
) : SizedBox.shrink(),
_business.description.isNotEmpty ? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -1092,13 +1113,13 @@ class MobileShopState extends State<MobileShop>
}
Widget _buildMainContent() {
return new Row(
return Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildCategories(),
Expanded(
child: _buildProducts(),
)
),
],
);
}
@@ -1116,7 +1137,7 @@ class MobileShopState extends State<MobileShop>
CategoryProducts cp = _categoryProducts[i];
int qtyInCategory = 0;
CartInfo cartInfo =
Utils.getCartInfoByBusiness(store.state.cartInfos, _business);
Utils.getCartInfoByBusiness(store.state.cartInfos, _business);
if (cartInfo != null &&
cartInfo.businessInfo.id == _business.id &&
cartInfo.productList != null) {
@@ -1141,14 +1162,14 @@ class MobileShopState extends State<MobileShop>
style: TextStyle(
fontSize: 13.0,
fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id == Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
? Colors.lightGreen
: Colors.black87)),
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
softWrap: true,
@@ -1178,10 +1199,10 @@ class MobileShopState extends State<MobileShop>
height: 70.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
decoration: new BoxDecoration(
color: _categoryIndex == i ? Style.backgroundColor : null,
color: _categoryIndex == i ? Colors.white : null,
border: new Border(
bottom:
new BorderSide(color: new Color(0xFFEBEBEB)))),
new BorderSide(color: new Color(0xFFEBEBEB)))),
child: categoryRow,
),
onTap: () => _selectCategory(i),
@@ -1208,10 +1229,10 @@ class MobileShopState extends State<MobileShop>
_categoryIndexChange = true;
_listScrollController1
.animateTo(height,
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
.then((value) {
_categoryIndexChange = false;
});
@@ -1316,7 +1337,7 @@ class MobileShopState extends State<MobileShop>
controller: _listScrollController1,
// itemCount: displayProductByCategoryClick ? 1 : (_categoryProducts == null ? 0 : _categoryProducts.length),
itemCount:
_categoryProducts == null ? 0 : numCategoriesHasProducts(),
_categoryProducts == null ? 0 : numCategoriesHasProducts(),
itemBuilder: (BuildContext context, int i) {
CategoryProducts cp;
cp = _categoryProducts[i];
@@ -1357,42 +1378,42 @@ class MobileShopState extends State<MobileShop>
children: <Widget>[
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 5.0),
child: new Text(
cp.name,
style: new TextStyle(
fontSize: 16.0,
fontWeight:
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 5.0),
child: new Text(
cp.name,
style: new TextStyle(
fontSize: 16.0,
fontWeight:
(cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id ==
Constants.FEATURED_PRODUCT_ID)
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id ==
Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
overflow: TextOverflow.ellipsis,
),
),
new Visibility(
visible: cp.description.isNotEmpty,
child: new Text(
cp.description,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)),
overflow: TextOverflow.ellipsis,
),
),
replacement: const SizedBox.shrink()),
],
))
new Visibility(
visible: cp.description.isNotEmpty,
child: new Text(
cp.description,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)),
),
replacement: const SizedBox.shrink()),
],
))
],
)));
for (var p in cp.products) {
@@ -1400,9 +1421,13 @@ class MobileShopState extends State<MobileShop>
children: <Widget>[],
);
pStack.children.add(new ProductItem(
product: p,
business: _business,
pStack.children.add(Container(
// width: MediaQuery.of(context).size.width - 100.0,
child: ProductItem(
p, _business,
horizontal: true,
imageWidth: 80.0,
),
));
col.children.add(pStack);
@@ -1494,129 +1519,6 @@ class MobileShopState extends State<MobileShop>
}
});
// onProductWillAddToCartSubscription =
// eventBus.on<OnProductWillAddToCart>().listen((event) {
// if (mounted) {
// itemAddToCart(event.buttonKey);
//
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
//
// if (cartInfo == null || cartInfo.productList.length == 0) {
// cartInfo = CartInfo();
// cartInfo.id = 0;
// cartInfo.amountPaid = 0.0;
// cartInfo.businessInfo = event.business;
// cartInfo.extraFeeList = [];
// cartInfo.discountList = [];
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList = [lineItem];
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (event.product.productAttributes.length > 0) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// int found = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (event.product.id == cartInfo.productList[i].product.id) {
// found = i;
// break;
// }
// }
// if (found == -1) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (cartInfo.productList[found].quantity + 1.0 >
// event.product.leftNum) {
// Fluttertoast.showToast(
// msg: S.of(context).product_insufficient,
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
// backgroundColor: Colors.red,
// textColor: Colors.white);
// } else {
// cartInfo.productList[found].quantity += 1;
// store.dispatch(new UpdateCartInfo(
// Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// }
// }
// }
// });
// onProductWillRemoveFromCartSubscription =
// eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
// if (mounted) {
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
// if (cartInfo != null) {
// if (cartInfo.productList.length > 0) {
// if (event.productListIndex != -1) {
// if (cartInfo.productList[event.productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(event.productListIndex);
// } else {
// cartInfo.productList[event.productListIndex].quantity -= 1;
// }
// } else {
// int productListIndex = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (cartInfo.productList[i].product.id == event.product.id) {
// productListIndex = i;
// break;
// }
// }
// if (productListIndex != -1) {
// if (cartInfo.productList[productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(productListIndex);
// } else {
// cartInfo.productList[productListIndex].quantity -= 1;
// }
// }
// }
// }
//
// if (cartInfo.productList.length <= 0) {
// store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList(
// store.state.cartInfos, cartInfo)));
// } else {
// store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// }
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// });
loadProducts();
}
@@ -1630,67 +1532,71 @@ class MobileShopState extends State<MobileShop>
}
_productCurrentPage = 1;
Utils.loadProducts(
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
// _featuredProducts = (value['featured_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
_featuredProducts = [];
// _hotSaleProducts = (value['hot_sale_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
_hotSaleProducts = [];
_prompts = value['prompt'] as List;
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
checkActionAndClose(context);
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
Utils.showMessageDialog(context, error);
}
if (mounted) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
_featuredProducts = (value['featured_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_hotSaleProducts = (value['hot_sale_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_prompts = value['prompt'] as List;
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
checkActionAndClose(context);
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
);
}
@@ -1700,59 +1606,59 @@ class MobileShopState extends State<MobileShop>
}
_productCurrentPage += 1;
Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
});
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
Utils.showMessageDialog(context, error);
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
);
}
CartLineItem _newCartLineItem(
{int id,
double price,
Product product,
String name,
String description,
double quantity}) {
double price,
Product product,
String name,
String description,
double quantity}) {
CartLineItem lineItem = CartLineItem();
lineItem.unitPrice = price;
lineItem.product = product;
@@ -1787,9 +1693,9 @@ class MobileShopState extends State<MobileShop>
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: _business,
)),
product: p,
business: _business,
)),
);
}
@@ -1925,10 +1831,10 @@ class MobileShopState extends State<MobileShop>
S.of(context).store_closed,
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -1981,10 +1887,10 @@ class MobileShopState extends State<MobileShop>
),
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -2007,10 +1913,10 @@ class MobileShopState extends State<MobileShop>
title: Text(_prompt['title']),
content: Text(_prompt['message']),
actions: [
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(idx + 1);
},
),
@@ -2053,4 +1959,4 @@ class _SliverAppBarDelegate2 extends SliverPersistentHeaderDelegate {
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}
}

View File

@@ -21,7 +21,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.1"
version: "2.8.2"
awesome_card:
dependency: transitive
description:
@@ -84,7 +84,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
charcode:
dependency: transitive
description:
@@ -601,7 +601,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
version: "0.12.11"
meta:
dependency: transitive
description:
@@ -1000,7 +1000,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
version: "0.4.3"
timezone:
dependency: transitive
description:
@@ -1119,7 +1119,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
video_player:
dependency: transitive
description:
@@ -1219,5 +1219,5 @@ packages:
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.13.0 <3.0.0"
dart: ">=2.14.0 <3.0.0"
flutter: ">=2.2.0"

View File

@@ -20,7 +20,7 @@
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="flutter_wisetronic">
<meta name="apple-mobile-web-app-title" content="Wisetronic">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->