Merge remote-tracking branch 'origin/dev_reason_v1.0' into dev_reason_v1.0
# Conflicts: # android/app/build.gradle # pubspec.lock
Showing
25 changed files
with
876 additions
and
70 deletions
| ... | @@ -32,8 +32,8 @@ if (keystorePropertiesFile.exists()) { | ... | @@ -32,8 +32,8 @@ if (keystorePropertiesFile.exists()) { |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | android { | 34 | android { |
| 35 | - compileSdkVersion 33 | 35 | + compileSdkVersion 32 |
| 36 | - buildToolsVersion "33" | 36 | + buildToolsVersion "32" |
| 37 | 37 | ||
| 38 | compileOptions { | 38 | compileOptions { |
| 39 | sourceCompatibility JavaVersion.VERSION_1_8 | 39 | sourceCompatibility JavaVersion.VERSION_1_8 | ... | ... |
| ... | @@ -21,6 +21,6 @@ | ... | @@ -21,6 +21,6 @@ |
| 21 | <key>CFBundleVersion</key> | 21 | <key>CFBundleVersion</key> |
| 22 | <string>1.0</string> | 22 | <string>1.0</string> |
| 23 | <key>MinimumOSVersion</key> | 23 | <key>MinimumOSVersion</key> |
| 24 | - <string>9.0</string> | 24 | + <string>11.0</string> |
| 25 | </dict> | 25 | </dict> |
| 26 | </plist> | 26 | </plist> | ... | ... |
| 1 | # Uncomment this line to define a global platform for your project | 1 | # Uncomment this line to define a global platform for your project |
| 2 | -# platform :ios, '9.0' | 2 | +platform :ios, '12.0' |
| 3 | -platform :ios, '10.0' | ||
| 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. |
| 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' | 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' |
| 6 | 5 | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -363,7 +363,7 @@ | ... | @@ -363,7 +363,7 @@ |
| 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | 363 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
| 364 | GCC_WARN_UNUSED_FUNCTION = YES; | 364 | GCC_WARN_UNUSED_FUNCTION = YES; |
| 365 | GCC_WARN_UNUSED_VARIABLE = YES; | 365 | GCC_WARN_UNUSED_VARIABLE = YES; |
| 366 | - IPHONEOS_DEPLOYMENT_TARGET = 9.0; | 366 | + IPHONEOS_DEPLOYMENT_TARGET = 11.0; |
| 367 | MTL_ENABLE_DEBUG_INFO = NO; | 367 | MTL_ENABLE_DEBUG_INFO = NO; |
| 368 | SDKROOT = iphoneos; | 368 | SDKROOT = iphoneos; |
| 369 | SUPPORTED_PLATFORMS = iphoneos; | 369 | SUPPORTED_PLATFORMS = iphoneos; |
| ... | @@ -380,14 +380,14 @@ | ... | @@ -380,14 +380,14 @@ |
| 380 | CLANG_ENABLE_MODULES = YES; | 380 | CLANG_ENABLE_MODULES = YES; |
| 381 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | 381 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; |
| 382 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | 382 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
| 383 | - DEVELOPMENT_TEAM = FLS6Y2LS7Z; | 383 | + DEVELOPMENT_TEAM = 5PX6JTCZ6G; |
| 384 | ENABLE_BITCODE = NO; | 384 | ENABLE_BITCODE = NO; |
| 385 | INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; | 385 | INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; |
| 386 | LD_RUNPATH_SEARCH_PATHS = ( | 386 | LD_RUNPATH_SEARCH_PATHS = ( |
| 387 | "$(inherited)", | 387 | "$(inherited)", |
| 388 | "@executable_path/Frameworks", | 388 | "@executable_path/Frameworks", |
| 389 | ); | 389 | ); |
| 390 | - PRODUCT_BUNDLE_IDENTIFIER = pub.yiyan.parlando.Parlando; | 390 | + PRODUCT_BUNDLE_IDENTIFIER = ink.parlando.parlando; |
| 391 | PRODUCT_NAME = "$(TARGET_NAME)"; | 391 | PRODUCT_NAME = "$(TARGET_NAME)"; |
| 392 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | 392 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; |
| 393 | SWIFT_VERSION = 5.0; | 393 | SWIFT_VERSION = 5.0; |
| ... | @@ -442,7 +442,7 @@ | ... | @@ -442,7 +442,7 @@ |
| 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
| 443 | GCC_WARN_UNUSED_FUNCTION = YES; | 443 | GCC_WARN_UNUSED_FUNCTION = YES; |
| 444 | GCC_WARN_UNUSED_VARIABLE = YES; | 444 | GCC_WARN_UNUSED_VARIABLE = YES; |
| 445 | - IPHONEOS_DEPLOYMENT_TARGET = 9.0; | 445 | + IPHONEOS_DEPLOYMENT_TARGET = 11.0; |
| 446 | MTL_ENABLE_DEBUG_INFO = YES; | 446 | MTL_ENABLE_DEBUG_INFO = YES; |
| 447 | ONLY_ACTIVE_ARCH = YES; | 447 | ONLY_ACTIVE_ARCH = YES; |
| 448 | SDKROOT = iphoneos; | 448 | SDKROOT = iphoneos; |
| ... | @@ -491,7 +491,7 @@ | ... | @@ -491,7 +491,7 @@ |
| 491 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | 491 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
| 492 | GCC_WARN_UNUSED_FUNCTION = YES; | 492 | GCC_WARN_UNUSED_FUNCTION = YES; |
| 493 | GCC_WARN_UNUSED_VARIABLE = YES; | 493 | GCC_WARN_UNUSED_VARIABLE = YES; |
| 494 | - IPHONEOS_DEPLOYMENT_TARGET = 9.0; | 494 | + IPHONEOS_DEPLOYMENT_TARGET = 11.0; |
| 495 | MTL_ENABLE_DEBUG_INFO = NO; | 495 | MTL_ENABLE_DEBUG_INFO = NO; |
| 496 | SDKROOT = iphoneos; | 496 | SDKROOT = iphoneos; |
| 497 | SUPPORTED_PLATFORMS = iphoneos; | 497 | SUPPORTED_PLATFORMS = iphoneos; |
| ... | @@ -509,14 +509,14 @@ | ... | @@ -509,14 +509,14 @@ |
| 509 | CLANG_ENABLE_MODULES = YES; | 509 | CLANG_ENABLE_MODULES = YES; |
| 510 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | 510 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; |
| 511 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | 511 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
| 512 | - DEVELOPMENT_TEAM = FLS6Y2LS7Z; | 512 | + DEVELOPMENT_TEAM = 5PX6JTCZ6G; |
| 513 | ENABLE_BITCODE = NO; | 513 | ENABLE_BITCODE = NO; |
| 514 | INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; | 514 | INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; |
| 515 | LD_RUNPATH_SEARCH_PATHS = ( | 515 | LD_RUNPATH_SEARCH_PATHS = ( |
| 516 | "$(inherited)", | 516 | "$(inherited)", |
| 517 | "@executable_path/Frameworks", | 517 | "@executable_path/Frameworks", |
| 518 | ); | 518 | ); |
| 519 | - PRODUCT_BUNDLE_IDENTIFIER = pub.yiyan.parlando.Parlando; | 519 | + PRODUCT_BUNDLE_IDENTIFIER = ink.parlando.parlando; |
| 520 | PRODUCT_NAME = "$(TARGET_NAME)"; | 520 | PRODUCT_NAME = "$(TARGET_NAME)"; |
| 521 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | 521 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; |
| 522 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | 522 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; |
| ... | @@ -533,14 +533,14 @@ | ... | @@ -533,14 +533,14 @@ |
| 533 | CLANG_ENABLE_MODULES = YES; | 533 | CLANG_ENABLE_MODULES = YES; |
| 534 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; | 534 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; |
| 535 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | 535 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
| 536 | - DEVELOPMENT_TEAM = FLS6Y2LS7Z; | 536 | + DEVELOPMENT_TEAM = 5PX6JTCZ6G; |
| 537 | ENABLE_BITCODE = NO; | 537 | ENABLE_BITCODE = NO; |
| 538 | INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; | 538 | INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; |
| 539 | LD_RUNPATH_SEARCH_PATHS = ( | 539 | LD_RUNPATH_SEARCH_PATHS = ( |
| 540 | "$(inherited)", | 540 | "$(inherited)", |
| 541 | "@executable_path/Frameworks", | 541 | "@executable_path/Frameworks", |
| 542 | ); | 542 | ); |
| 543 | - PRODUCT_BUNDLE_IDENTIFIER = pub.yiyan.parlando.Parlando; | 543 | + PRODUCT_BUNDLE_IDENTIFIER = ink.parlando.parlando; |
| 544 | PRODUCT_NAME = "$(TARGET_NAME)"; | 544 | PRODUCT_NAME = "$(TARGET_NAME)"; |
| 545 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | 545 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; |
| 546 | SWIFT_VERSION = 5.0; | 546 | SWIFT_VERSION = 5.0; | ... | ... |
| ... | @@ -2,12 +2,6 @@ | ... | @@ -2,12 +2,6 @@ |
| 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 3 | <plist version="1.0"> | 3 | <plist version="1.0"> |
| 4 | <dict> | 4 | <dict> |
| 5 | - <key>NSLocalNetworkUsageDescription</key> | ||
| 6 | - <string>Allow flutter app</string> | ||
| 7 | - <key>NSBonjourServices</key> | ||
| 8 | - <array> | ||
| 9 | - <string>_dartobservatory._tcp</string> | ||
| 10 | - </array> | ||
| 11 | <key>CFBundleDevelopmentRegion</key> | 5 | <key>CFBundleDevelopmentRegion</key> |
| 12 | <string>$(DEVELOPMENT_LANGUAGE)</string> | 6 | <string>$(DEVELOPMENT_LANGUAGE)</string> |
| 13 | <key>CFBundleDisplayName</key> | 7 | <key>CFBundleDisplayName</key> |
| ... | @@ -35,6 +29,12 @@ | ... | @@ -35,6 +29,12 @@ |
| 35 | <key>NSAllowsArbitraryLoads</key> | 29 | <key>NSAllowsArbitraryLoads</key> |
| 36 | <true/> | 30 | <true/> |
| 37 | </dict> | 31 | </dict> |
| 32 | + <key>NSBonjourServices</key> | ||
| 33 | + <array> | ||
| 34 | + <string>_dartobservatory._tcp</string> | ||
| 35 | + </array> | ||
| 36 | + <key>NSLocalNetworkUsageDescription</key> | ||
| 37 | + <string>Allow flutter app</string> | ||
| 38 | <key>NSMicrophoneUsageDescription</key> | 38 | <key>NSMicrophoneUsageDescription</key> |
| 39 | <string>打开话筒</string> | 39 | <string>打开话筒</string> |
| 40 | <key>UILaunchStoryboardName</key> | 40 | <key>UILaunchStoryboardName</key> | ... | ... |
ios/Runner/Info-Profile.plist
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 3 | +<plist version="1.0"> | ||
| 4 | +<dict> | ||
| 5 | + <key>CFBundleDevelopmentRegion</key> | ||
| 6 | + <string>$(DEVELOPMENT_LANGUAGE)</string> | ||
| 7 | + <key>CFBundleDisplayName</key> | ||
| 8 | + <string>一言临境</string> | ||
| 9 | + <key>CFBundleExecutable</key> | ||
| 10 | + <string>$(EXECUTABLE_NAME)</string> | ||
| 11 | + <key>CFBundleIdentifier</key> | ||
| 12 | + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||
| 13 | + <key>CFBundleInfoDictionaryVersion</key> | ||
| 14 | + <string>6.0</string> | ||
| 15 | + <key>CFBundleName</key> | ||
| 16 | + <string>Parlando</string> | ||
| 17 | + <key>CFBundlePackageType</key> | ||
| 18 | + <string>APPL</string> | ||
| 19 | + <key>CFBundleShortVersionString</key> | ||
| 20 | + <string>$(FLUTTER_BUILD_NAME)</string> | ||
| 21 | + <key>CFBundleSignature</key> | ||
| 22 | + <string>????</string> | ||
| 23 | + <key>CFBundleVersion</key> | ||
| 24 | + <string>$(FLUTTER_BUILD_NUMBER)</string> | ||
| 25 | + <key>LSRequiresIPhoneOS</key> | ||
| 26 | + <true/> | ||
| 27 | + <key>NSAppTransportSecurity</key> | ||
| 28 | + <dict> | ||
| 29 | + <key>NSAllowsArbitraryLoads</key> | ||
| 30 | + <true/> | ||
| 31 | + </dict> | ||
| 32 | + <key>NSMicrophoneUsageDescription</key> | ||
| 33 | + <string>打开话筒</string> | ||
| 34 | + <key>UILaunchStoryboardName</key> | ||
| 35 | + <string>LaunchScreen</string> | ||
| 36 | + <key>UIMainStoryboardFile</key> | ||
| 37 | + <string>Main</string> | ||
| 38 | + <key>UIStatusBarHidden</key> | ||
| 39 | + <false/> | ||
| 40 | + <key>UISupportedInterfaceOrientations</key> | ||
| 41 | + <array> | ||
| 42 | + <string>UIInterfaceOrientationPortrait</string> | ||
| 43 | + <string>UIInterfaceOrientationLandscapeLeft</string> | ||
| 44 | + <string>UIInterfaceOrientationLandscapeRight</string> | ||
| 45 | + </array> | ||
| 46 | + <key>UISupportedInterfaceOrientations~ipad</key> | ||
| 47 | + <array> | ||
| 48 | + <string>UIInterfaceOrientationPortrait</string> | ||
| 49 | + <string>UIInterfaceOrientationPortraitUpsideDown</string> | ||
| 50 | + <string>UIInterfaceOrientationLandscapeLeft</string> | ||
| 51 | + <string>UIInterfaceOrientationLandscapeRight</string> | ||
| 52 | + </array> | ||
| 53 | + <key>UIViewControllerBasedStatusBarAppearance</key> | ||
| 54 | + <false/> | ||
| 55 | +</dict> | ||
| 56 | +</plist> |
lib/apis/api_base.dart
0 → 100644
| 1 | +import 'dart:convert'; | ||
| 2 | + | ||
| 3 | +import 'package:Parlando/apis/api_response.dart'; | ||
| 4 | +import 'package:Parlando/net/dio_utils.dart'; | ||
| 5 | +import 'package:common_utils/common_utils.dart'; | ||
| 6 | +import 'package:dio/dio.dart'; | ||
| 7 | +import 'package:flutter/material.dart'; | ||
| 8 | + | ||
| 9 | +class BaseApi { | ||
| 10 | + Future<Response<T>> post<T>( | ||
| 11 | + String path, { | ||
| 12 | + data, | ||
| 13 | + Map<String, dynamic>? queryParameters, | ||
| 14 | + Options? options, | ||
| 15 | + CancelToken? cancelToken, | ||
| 16 | + ProgressCallback? onSendProgress, | ||
| 17 | + ProgressCallback? onReceiveProgress, | ||
| 18 | + }) { | ||
| 19 | + return _getDio().post<T>( | ||
| 20 | + path, | ||
| 21 | + data: data, | ||
| 22 | + queryParameters: queryParameters, | ||
| 23 | + options: options, | ||
| 24 | + cancelToken: cancelToken, | ||
| 25 | + onSendProgress: onSendProgress, | ||
| 26 | + onReceiveProgress: onReceiveProgress, | ||
| 27 | + ); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + Dio _getDio() { | ||
| 31 | + return DioUtils.instance.dio; | ||
| 32 | + } | ||
| 33 | +} |
lib/apis/api_order.dart
0 → 100644
| 1 | +import 'dart:convert'; | ||
| 2 | + | ||
| 3 | +import 'package:Parlando/apis/api_base.dart'; | ||
| 4 | +import 'package:Parlando/apis/api_response.dart'; | ||
| 5 | +import 'package:common_utils/common_utils.dart'; | ||
| 6 | +import 'package:dio/dio.dart'; | ||
| 7 | +import 'package:flutter/material.dart'; | ||
| 8 | + | ||
| 9 | +class OrderApi extends BaseApi { | ||
| 10 | + OrderApi._privateConstructor(); | ||
| 11 | + | ||
| 12 | + static final OrderApi _instance = OrderApi._privateConstructor(); | ||
| 13 | + | ||
| 14 | + static OrderApi get request { | ||
| 15 | + return _instance; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + Future<dynamic> createOrder(String productId) { | ||
| 19 | + var data = {"goods_id": productId}; | ||
| 20 | + return post("order", data: data).then((value) { | ||
| 21 | + if (TextUtil.isEmpty(value.data)) { | ||
| 22 | + return {}; | ||
| 23 | + } | ||
| 24 | + return json.decode(value.data); | ||
| 25 | + }); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + Future<dynamic> verifyOrder(String orderId, String type, String token, {Map<String, dynamic>? others}) { | ||
| 29 | + var data = { | ||
| 30 | + "order_sn": orderId, | ||
| 31 | + "pay_type": type, | ||
| 32 | + "token": token, | ||
| 33 | + "others": others ?? {}, | ||
| 34 | + }; | ||
| 35 | + return post("pay", data: data).then((value) { | ||
| 36 | + if (TextUtil.isEmpty(value.data)) { | ||
| 37 | + return {}; | ||
| 38 | + } | ||
| 39 | + return value.data; | ||
| 40 | + }); | ||
| 41 | + } | ||
| 42 | +} |
lib/base/base_state.dart
0 → 100644
| 1 | +import 'dart:async'; | ||
| 2 | + | ||
| 3 | +import 'package:flutter/material.dart'; | ||
| 4 | +import 'package:flutter_easyloading/flutter_easyloading.dart'; | ||
| 5 | + | ||
| 6 | +abstract class BaseState<T extends StatefulWidget> extends State<T> { | ||
| 7 | + bool _isFirstBuild = true; | ||
| 8 | + List<Timer> delayTimers = []; | ||
| 9 | + | ||
| 10 | + @override | ||
| 11 | + Widget build(BuildContext context) { | ||
| 12 | + if (_isFirstBuild) { | ||
| 13 | + onFirstBuildBody(context); | ||
| 14 | + _isFirstBuild = false; | ||
| 15 | + } | ||
| 16 | + return buildBody(context); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + postDelay(VoidCallback fn, int delayTime) { | ||
| 20 | + var delayTimer = Timer(Duration(milliseconds: delayTime), fn); | ||
| 21 | + delayTimers.add(delayTimer); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + Widget buildBody(BuildContext context); | ||
| 25 | + | ||
| 26 | + void onFirstBuildBody(BuildContext context) {} | ||
| 27 | + | ||
| 28 | + showLoading({String text = 'Loading...'}) { | ||
| 29 | + EasyLoading.show(status: text); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + hideLoading() { | ||
| 33 | + EasyLoading.dismiss(); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + toast(String text) { | ||
| 37 | + EasyLoading.showToast(text); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + Widget buildLoading() { | ||
| 41 | + return const Center(child: CircularProgressIndicator()); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @override | ||
| 45 | + void dispose() { | ||
| 46 | + super.dispose(); | ||
| 47 | + for (var element in delayTimers) { | ||
| 48 | + element.cancel(); | ||
| 49 | + } | ||
| 50 | + hideLoading(); | ||
| 51 | + } | ||
| 52 | +} |
lib/extension/widget_ext.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | + | ||
| 3 | +extension WidgetExt on Widget { | ||
| 4 | + Expanded expanded({int flex = 1}) { | ||
| 5 | + return Expanded(flex: flex, child: this); | ||
| 6 | + } | ||
| 7 | + | ||
| 8 | + SafeArea safe() { | ||
| 9 | + return SafeArea(child: this); | ||
| 10 | + } | ||
| 11 | + | ||
| 12 | + ClipRRect round({double? radius, BorderRadius? borderRadius}) { | ||
| 13 | + return ClipRRect( | ||
| 14 | + borderRadius: borderRadius ?? BorderRadius.all(Radius.circular(radius ?? 5)), | ||
| 15 | + child: this, | ||
| 16 | + ); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + Container height(double height, {Alignment? alignment}) { | ||
| 20 | + return Container(height: height, alignment: alignment, child: this); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + Container height48({Alignment? alignment}) { | ||
| 24 | + return Container(height: 48, alignment: alignment, child: this); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + Container paddingALL(double padding) { | ||
| 28 | + return Container(child: this, padding: EdgeInsets.all(padding)); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + Container paddingTopBottom(double padding) { | ||
| 32 | + return Container(child: this, padding: EdgeInsets.only(bottom: padding, top: padding)); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + Container paddingBottom(double padding) { | ||
| 36 | + return Container(child: this, padding: EdgeInsets.only(bottom: padding)); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + Container paddingTop(double padding) { | ||
| 40 | + return Container(child: this, padding: EdgeInsets.only(top: padding)); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + Widget paddingLeftRight(double padding) { | ||
| 44 | + return Container(child: this, padding: EdgeInsets.only(left: padding, right: padding)); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + Container paddingLeft(double padding) { | ||
| 48 | + return Container(child: this, padding: EdgeInsets.only(left: padding)); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + Container paddingRight(double padding) { | ||
| 52 | + return Container(child: this, padding: EdgeInsets.only(right: padding)); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + Row rowRight() { | ||
| 56 | + return Row(mainAxisAlignment: MainAxisAlignment.end, children: [this]); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + Row rowLeft() { | ||
| 60 | + return Row(mainAxisAlignment: MainAxisAlignment.start, children: [this]); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + Row rowCenter() { | ||
| 64 | + return Row(mainAxisAlignment: MainAxisAlignment.center, children: [this]); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + Widget click( | ||
| 68 | + GestureTapCallback? onTap, { | ||
| 69 | + Color? color, | ||
| 70 | + double? radius, | ||
| 71 | + BorderRadius? borderRadius, | ||
| 72 | + Color? bgColor, | ||
| 73 | + }) { | ||
| 74 | + if (color != null) { | ||
| 75 | + var border = radius == null ? null : BorderRadius.all(Radius.circular(radius)); | ||
| 76 | + return getMaterialInkWell( | ||
| 77 | + this, | ||
| 78 | + onTap, | ||
| 79 | + color, | ||
| 80 | + borderRadius: borderRadius ?? border, | ||
| 81 | + bgColor: bgColor, | ||
| 82 | + ); | ||
| 83 | + } | ||
| 84 | + return getWhiteInkWell(this, onTap); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + ///当InkWell效果失效时,使用这个套件 | ||
| 88 | + Widget getMaterialInkWell( | ||
| 89 | + Widget widget, | ||
| 90 | + GestureTapCallback? onTap, | ||
| 91 | + Color? color, { | ||
| 92 | + BorderRadius? borderRadius, | ||
| 93 | + Color? splashColor, | ||
| 94 | + Color? bgColor = Colors.white, | ||
| 95 | + }) { | ||
| 96 | + return Material( | ||
| 97 | + color: bgColor, | ||
| 98 | + child: Ink( | ||
| 99 | + decoration: BoxDecoration( | ||
| 100 | + color: color, | ||
| 101 | + borderRadius: borderRadius, | ||
| 102 | + ), | ||
| 103 | + child: InkWell( | ||
| 104 | + onTap: onTap, | ||
| 105 | + splashColor: splashColor, | ||
| 106 | + borderRadius: borderRadius, | ||
| 107 | + child: widget, | ||
| 108 | + ), | ||
| 109 | + ), | ||
| 110 | + ); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + ///当InkWell效果失效时,使用这个套件 | ||
| 114 | + Widget getWhiteInkWell(Widget widget, GestureTapCallback? onTap, {BorderRadius? borderRadius}) { | ||
| 115 | + return Material( | ||
| 116 | + child: Ink( | ||
| 117 | + color: Colors.white, | ||
| 118 | + child: InkWell(onTap: onTap, child: widget), | ||
| 119 | + ), | ||
| 120 | + ); | ||
| 121 | + } | ||
| 122 | +} |
| ... | @@ -68,6 +68,10 @@ MembershipData $MembershipDataFromJson(Map<String, dynamic> json) { | ... | @@ -68,6 +68,10 @@ MembershipData $MembershipDataFromJson(Map<String, dynamic> json) { |
| 68 | if (videoCover != null) { | 68 | if (videoCover != null) { |
| 69 | membershipData.videoCover = videoCover; | 69 | membershipData.videoCover = videoCover; |
| 70 | } | 70 | } |
| 71 | + final String? expireVipAt = jsonConvert.convert<String>(json['expire_vip_time']); | ||
| 72 | + if (videoCover != null) { | ||
| 73 | + membershipData.expireVipAt = expireVipAt; | ||
| 74 | + } | ||
| 71 | final String? terminal = jsonConvert.convert<String>(json['terminal']); | 75 | final String? terminal = jsonConvert.convert<String>(json['terminal']); |
| 72 | if (terminal != null) { | 76 | if (terminal != null) { |
| 73 | membershipData.terminal = terminal; | 77 | membershipData.terminal = terminal; |
| ... | @@ -105,6 +109,7 @@ Map<String, dynamic> $MembershipDataToJson(MembershipData entity) { | ... | @@ -105,6 +109,7 @@ Map<String, dynamic> $MembershipDataToJson(MembershipData entity) { |
| 105 | data['bg_images'] = entity.bgImages; | 109 | data['bg_images'] = entity.bgImages; |
| 106 | data['video_url'] = entity.videoUrl; | 110 | data['video_url'] = entity.videoUrl; |
| 107 | data['video_cover'] = entity.videoCover; | 111 | data['video_cover'] = entity.videoCover; |
| 112 | + data['expire_vip_time'] = entity.expireVipAt; | ||
| 108 | data['terminal'] = entity.terminal; | 113 | data['terminal'] = entity.terminal; |
| 109 | data['state'] = entity.state; | 114 | data['state'] = entity.state; |
| 110 | data['created_at'] = entity.createdAt; | 115 | data['created_at'] = entity.createdAt; |
| ... | @@ -116,17 +121,19 @@ Map<String, dynamic> $MembershipDataToJson(MembershipData entity) { | ... | @@ -116,17 +121,19 @@ Map<String, dynamic> $MembershipDataToJson(MembershipData entity) { |
| 116 | 121 | ||
| 117 | MembershipDataGoodsList $MembershipDataGoodsListFromJson( | 122 | MembershipDataGoodsList $MembershipDataGoodsListFromJson( |
| 118 | Map<String, dynamic> json) { | 123 | Map<String, dynamic> json) { |
| 119 | - final MembershipDataGoodsList membershipDataGoodsList = | 124 | + final MembershipDataGoodsList membershipDataGoodsList = MembershipDataGoodsList(); |
| 120 | - MembershipDataGoodsList(); | ||
| 121 | final int? id = jsonConvert.convert<int>(json['id']); | 125 | final int? id = jsonConvert.convert<int>(json['id']); |
| 122 | if (id != null) { | 126 | if (id != null) { |
| 123 | membershipDataGoodsList.id = id; | 127 | membershipDataGoodsList.id = id; |
| 124 | } | 128 | } |
| 125 | - final String? membershipId = | 129 | + final String? membershipId = jsonConvert.convert<String>(json['membership_id']); |
| 126 | - jsonConvert.convert<String>(json['membership_id']); | ||
| 127 | if (membershipId != null) { | 130 | if (membershipId != null) { |
| 128 | membershipDataGoodsList.membershipId = membershipId; | 131 | membershipDataGoodsList.membershipId = membershipId; |
| 129 | } | 132 | } |
| 133 | + final String? iapId = jsonConvert.convert<String>(json['iap_id']); | ||
| 134 | + if (iapId != null) { | ||
| 135 | + membershipDataGoodsList.iapId = iapId; | ||
| 136 | + } | ||
| 130 | final String? name = jsonConvert.convert<String>(json['name']); | 137 | final String? name = jsonConvert.convert<String>(json['name']); |
| 131 | if (name != null) { | 138 | if (name != null) { |
| 132 | membershipDataGoodsList.name = name; | 139 | membershipDataGoodsList.name = name; |
| ... | @@ -192,6 +199,7 @@ Map<String, dynamic> $MembershipDataGoodsListToJson( | ... | @@ -192,6 +199,7 @@ Map<String, dynamic> $MembershipDataGoodsListToJson( |
| 192 | final Map<String, dynamic> data = <String, dynamic>{}; | 199 | final Map<String, dynamic> data = <String, dynamic>{}; |
| 193 | data['id'] = entity.id; | 200 | data['id'] = entity.id; |
| 194 | data['membership_id'] = entity.membershipId; | 201 | data['membership_id'] = entity.membershipId; |
| 202 | + data['iap_id'] = entity.iapId; | ||
| 195 | data['name'] = entity.name; | 203 | data['name'] = entity.name; |
| 196 | data['price'] = entity.price; | 204 | data['price'] = entity.price; |
| 197 | data['line_price'] = entity.linePrice; | 205 | data['line_price'] = entity.linePrice; | ... | ... |
| ... | @@ -10,6 +10,10 @@ import 'package:Parlando/widgets/my_button.dart'; | ... | @@ -10,6 +10,10 @@ import 'package:Parlando/widgets/my_button.dart'; |
| 10 | import 'package:Parlando/widgets/my_scroll_view.dart'; | 10 | import 'package:Parlando/widgets/my_scroll_view.dart'; |
| 11 | 11 | ||
| 12 | import 'package:Parlando/extension/int_extension.dart'; | 12 | import 'package:Parlando/extension/int_extension.dart'; |
| 13 | +import 'package:getwidget/components/loader/gf_loader.dart'; | ||
| 14 | + | ||
| 15 | +import '../../net/dio_utils.dart'; | ||
| 16 | +import '../../net/http_api.dart'; | ||
| 13 | 17 | ||
| 14 | class UpdatePasswordPage extends StatefulWidget { | 18 | class UpdatePasswordPage extends StatefulWidget { |
| 15 | const UpdatePasswordPage({Key? key}) : super(key: key); | 19 | const UpdatePasswordPage({Key? key}) : super(key: key); |
| ... | @@ -26,6 +30,7 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> | ... | @@ -26,6 +30,7 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> |
| 26 | final FocusNode _nodeText1 = FocusNode(); | 30 | final FocusNode _nodeText1 = FocusNode(); |
| 27 | final FocusNode _nodeText2 = FocusNode(); | 31 | final FocusNode _nodeText2 = FocusNode(); |
| 28 | bool _clickable = false; | 32 | bool _clickable = false; |
| 33 | + bool _isLoading = false; | ||
| 29 | 34 | ||
| 30 | @override | 35 | @override |
| 31 | Map<ChangeNotifier, List<VoidCallback>?>? changeNotifier() { | 36 | Map<ChangeNotifier, List<VoidCallback>?>? changeNotifier() { |
| ... | @@ -56,8 +61,25 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> | ... | @@ -56,8 +61,25 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> |
| 56 | } | 61 | } |
| 57 | 62 | ||
| 58 | void _confirm() { | 63 | void _confirm() { |
| 59 | - Toast.show('修改成功!'); | 64 | + _isLoading = true; |
| 65 | + Map<String, String> params = <String, String>{ | ||
| 66 | + "password": _newPwdController.text, | ||
| 67 | + "password_confirmation": _newPwdController.text, | ||
| 68 | + }; | ||
| 69 | + DioUtils.instance.asyncRequestNetwork( | ||
| 70 | + Method.post, | ||
| 71 | + HttpApi.changePassword, | ||
| 72 | + params: params, | ||
| 73 | + onSuccess: (data) { | ||
| 74 | + _isLoading = false; | ||
| 60 | NavigatorUtils.goBack(context); | 75 | NavigatorUtils.goBack(context); |
| 76 | + }, | ||
| 77 | + onError: (code, msg) { | ||
| 78 | + _isLoading = false; | ||
| 79 | + Toast.show(msg.toString()); | ||
| 80 | + setState(() {}); | ||
| 81 | + }, | ||
| 82 | + ); | ||
| 61 | } | 83 | } |
| 62 | 84 | ||
| 63 | @override | 85 | @override |
| ... | @@ -76,7 +98,7 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> | ... | @@ -76,7 +98,7 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> |
| 76 | ), | 98 | ), |
| 77 | Gaps.vGap8, | 99 | Gaps.vGap8, |
| 78 | Text( | 100 | Text( |
| 79 | - '设置账号 15000000000', | 101 | + ' ', |
| 80 | style: Theme.of(context) | 102 | style: Theme.of(context) |
| 81 | .textTheme | 103 | .textTheme |
| 82 | .subtitle2 | 104 | .subtitle2 |
| ... | @@ -102,7 +124,10 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> | ... | @@ -102,7 +124,10 @@ class _UpdatePasswordPageState extends State<UpdatePasswordPage> |
| 102 | MyButton( | 124 | MyButton( |
| 103 | onPressed: _clickable ? _confirm : null, | 125 | onPressed: _clickable ? _confirm : null, |
| 104 | text: '确认', | 126 | text: '确认', |
| 105 | - ) | 127 | + ), |
| 128 | + Container( | ||
| 129 | + child: _isLoading ? const GFLoader() : null, | ||
| 130 | + ), | ||
| 106 | ], | 131 | ], |
| 107 | ), | 132 | ), |
| 108 | ); | 133 | ); | ... | ... |
| ... | @@ -6,6 +6,7 @@ import 'package:dio/dio.dart'; | ... | @@ -6,6 +6,7 @@ import 'package:dio/dio.dart'; |
| 6 | import 'package:flustars/flustars.dart'; | 6 | import 'package:flustars/flustars.dart'; |
| 7 | import 'package:flutter/material.dart'; | 7 | import 'package:flutter/material.dart'; |
| 8 | import 'package:flutter/services.dart'; | 8 | import 'package:flutter/services.dart'; |
| 9 | +import 'package:flutter_easyloading/flutter_easyloading.dart'; | ||
| 9 | import 'package:oktoast/oktoast.dart'; | 10 | import 'package:oktoast/oktoast.dart'; |
| 10 | import 'package:provider/provider.dart'; | 11 | import 'package:provider/provider.dart'; |
| 11 | import 'package:quick_actions/quick_actions.dart'; | 12 | import 'package:quick_actions/quick_actions.dart'; |
| ... | @@ -60,8 +61,7 @@ Future<void> main() async { | ... | @@ -60,8 +61,7 @@ Future<void> main() async { |
| 60 | await SpUtil.getInstance(); | 61 | await SpUtil.getInstance(); |
| 61 | 62 | ||
| 62 | WidgetsFlutterBinding.ensureInitialized(); | 63 | WidgetsFlutterBinding.ensureInitialized(); |
| 63 | - SystemChrome.setPreferredOrientations( | 64 | + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); |
| 64 | - [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); | ||
| 65 | 65 | ||
| 66 | /// 1.22 预览功能: 在输入频率与显示刷新率不匹配情况下提供平滑的滚动效果 | 66 | /// 1.22 预览功能: 在输入频率与显示刷新率不匹配情况下提供平滑的滚动效果 |
| 67 | // GestureBinding.instance?.resamplingEnabled = true; | 67 | // GestureBinding.instance?.resamplingEnabled = true; |
| ... | @@ -69,8 +69,7 @@ Future<void> main() async { | ... | @@ -69,8 +69,7 @@ Future<void> main() async { |
| 69 | handleError(() => runApp(MyApp())); | 69 | handleError(() => runApp(MyApp())); |
| 70 | 70 | ||
| 71 | /// 隐藏状态栏。为启动页、引导页设置。完成后修改回显示状态栏。 | 71 | /// 隐藏状态栏。为启动页、引导页设置。完成后修改回显示状态栏。 |
| 72 | - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, | 72 | + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom]); |
| 73 | - overlays: [SystemUiOverlay.bottom]); | ||
| 74 | // TODO(weilu): 启动体验不佳。状态栏、导航栏在冷启动开始的一瞬间为黑色,且无法通过隐藏、修改颜色等方式进行处理。。。 | 73 | // TODO(weilu): 启动体验不佳。状态栏、导航栏在冷启动开始的一瞬间为黑色,且无法通过隐藏、修改颜色等方式进行处理。。。 |
| 75 | // 相关问题跟踪:https://github.com/flutter/flutter/issues/73351 | 74 | // 相关问题跟踪:https://github.com/flutter/flutter/issues/73351 |
| 76 | if (Platform.isAndroid) { | 75 | if (Platform.isAndroid) { |
| ... | @@ -133,8 +132,7 @@ class MyApp extends StatelessWidget { | ... | @@ -133,8 +132,7 @@ class MyApp extends StatelessWidget { |
| 133 | } | 132 | } |
| 134 | 133 | ||
| 135 | quickActions.setShortcutItems(<ShortcutItem>[ | 134 | quickActions.setShortcutItems(<ShortcutItem>[ |
| 136 | - const ShortcutItem( | 135 | + const ShortcutItem(type: 'demo', localizedTitle: '发一言', icon: 'flutter_dash_black'), |
| 137 | - type: 'demo', localizedTitle: '发一言', icon: 'flutter_dash_black'), | ||
| 138 | ]); | 136 | ]); |
| 139 | } | 137 | } |
| 140 | } | 138 | } |
| ... | @@ -149,8 +147,7 @@ class MyApp extends StatelessWidget { | ... | @@ -149,8 +147,7 @@ class MyApp extends StatelessWidget { |
| 149 | ChangeNotifierProvider(create: (_) => MembershipViewProvider()) | 147 | ChangeNotifierProvider(create: (_) => MembershipViewProvider()) |
| 150 | ], | 148 | ], |
| 151 | child: Consumer2<ThemeProvider, LocaleProvider>( | 149 | child: Consumer2<ThemeProvider, LocaleProvider>( |
| 152 | - builder: | 150 | + builder: (_, ThemeProvider provider, LocaleProvider localeProvider, __) { |
| 153 | - (_, ThemeProvider provider, LocaleProvider localeProvider, __) { | ||
| 154 | return _buildMaterialApp(provider, localeProvider); | 151 | return _buildMaterialApp(provider, localeProvider); |
| 155 | }, | 152 | }, |
| 156 | ), | 153 | ), |
| ... | @@ -159,15 +156,13 @@ class MyApp extends StatelessWidget { | ... | @@ -159,15 +156,13 @@ class MyApp extends StatelessWidget { |
| 159 | /// Toast 配置 | 156 | /// Toast 配置 |
| 160 | return OKToast( | 157 | return OKToast( |
| 161 | backgroundColor: Colors.black54, | 158 | backgroundColor: Colors.black54, |
| 162 | - textPadding: | 159 | + textPadding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0), |
| 163 | - const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0), | ||
| 164 | radius: 20.0, | 160 | radius: 20.0, |
| 165 | position: ToastPosition.bottom, | 161 | position: ToastPosition.bottom, |
| 166 | child: app); | 162 | child: app); |
| 167 | } | 163 | } |
| 168 | 164 | ||
| 169 | - Widget _buildMaterialApp( | 165 | + Widget _buildMaterialApp(ThemeProvider provider, LocaleProvider localeProvider) { |
| 170 | - ThemeProvider provider, LocaleProvider localeProvider) { | ||
| 171 | return MaterialApp( | 166 | return MaterialApp( |
| 172 | title: '一言', | 167 | title: '一言', |
| 173 | // showPerformanceOverlay: true, //显示性能标签 | 168 | // showPerformanceOverlay: true, //显示性能标签 |
| ... | @@ -185,7 +180,7 @@ class MyApp extends StatelessWidget { | ... | @@ -185,7 +180,7 @@ class MyApp extends StatelessWidget { |
| 185 | supportedLocales: ParlandoLocalizations.supportedLocales, | 180 | supportedLocales: ParlandoLocalizations.supportedLocales, |
| 186 | locale: localeProvider.locale, | 181 | locale: localeProvider.locale, |
| 187 | navigatorKey: navigatorKey, | 182 | navigatorKey: navigatorKey, |
| 188 | - builder: (BuildContext context, Widget? child) { | 183 | + builder: EasyLoading.init(builder: (context, child) { |
| 189 | /// 仅针对安卓 | 184 | /// 仅针对安卓 |
| 190 | if (Device.isAndroid) { | 185 | if (Device.isAndroid) { |
| 191 | /// 切换深色模式会触发此方法,这里设置导航栏颜色 | 186 | /// 切换深色模式会触发此方法,这里设置导航栏颜色 |
| ... | @@ -197,7 +192,7 @@ class MyApp extends StatelessWidget { | ... | @@ -197,7 +192,7 @@ class MyApp extends StatelessWidget { |
| 197 | data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), | 192 | data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), |
| 198 | child: child!, | 193 | child: child!, |
| 199 | ); | 194 | ); |
| 200 | - }, | 195 | + }), |
| 201 | 196 | ||
| 202 | /// 因为使用了fluro,这里设置主要针对Web | 197 | /// 因为使用了fluro,这里设置主要针对Web |
| 203 | onUnknownRoute: (_) { | 198 | onUnknownRoute: (_) { | ... | ... |
| ... | @@ -42,6 +42,8 @@ class MembershipData { | ... | @@ -42,6 +42,8 @@ class MembershipData { |
| 42 | String? createdAt; | 42 | String? createdAt; |
| 43 | @JSONField(name: "updated_at") | 43 | @JSONField(name: "updated_at") |
| 44 | String? updatedAt; | 44 | String? updatedAt; |
| 45 | + @JSONField(name: "expire_vip_time") | ||
| 46 | + String? expireVipAt; | ||
| 45 | @JSONField(name: "is_vip") | 47 | @JSONField(name: "is_vip") |
| 46 | int? isVip; | 48 | int? isVip; |
| 47 | @JSONField(name: "goods_list") | 49 | @JSONField(name: "goods_list") |
| ... | @@ -65,6 +67,8 @@ class MembershipDataGoodsList { | ... | @@ -65,6 +67,8 @@ class MembershipDataGoodsList { |
| 65 | int? id; | 67 | int? id; |
| 66 | @JSONField(name: "membership_id") | 68 | @JSONField(name: "membership_id") |
| 67 | String? membershipId; | 69 | String? membershipId; |
| 70 | + @JSONField(name: "iap_id") | ||
| 71 | + String? iapId; | ||
| 68 | String? name; | 72 | String? name; |
| 69 | String? price; | 73 | String? price; |
| 70 | @JSONField(name: "line_price") | 74 | @JSONField(name: "line_price") | ... | ... |
This diff is collapsed. Click to expand it.
lib/models/nearby_response.dart
0 → 100644
| 1 | +class NearbyPlacesResponse { | ||
| 2 | + List<Results>? results; | ||
| 3 | + String? status; | ||
| 4 | + | ||
| 5 | + NearbyPlacesResponse({this.results, this.status}); | ||
| 6 | + | ||
| 7 | + NearbyPlacesResponse.fromJson(Map<String, dynamic> json) { | ||
| 8 | + if (json['results'] != null) { | ||
| 9 | + results = <Results>[]; | ||
| 10 | + json['results'].forEach((v) { | ||
| 11 | + results!.add(Results.fromJson(v)); | ||
| 12 | + }); | ||
| 13 | + } | ||
| 14 | + status = json['status']; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + Map<String, dynamic> toJson() { | ||
| 18 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 19 | + if (this.results != null) { | ||
| 20 | + data['results'] = this.results!.map((v) => v.toJson()).toList(); | ||
| 21 | + } | ||
| 22 | + data['status'] = this.status; | ||
| 23 | + return data; | ||
| 24 | + } | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +class Results { | ||
| 28 | + Geometry? geometry; | ||
| 29 | + String? icon; | ||
| 30 | + String? iconBackgroundColor; | ||
| 31 | + String? iconMaskBaseUri; | ||
| 32 | + String? name; | ||
| 33 | + List<Photos>? photos; | ||
| 34 | + String? placeId; | ||
| 35 | + String? reference; | ||
| 36 | + String? scope; | ||
| 37 | + List<String>? types; | ||
| 38 | + String? vicinity; | ||
| 39 | + String? businessStatus; | ||
| 40 | + OpeningHours? openingHours; | ||
| 41 | + PlusCode? plusCode; | ||
| 42 | + dynamic rating; | ||
| 43 | + int? userRatingsTotal; | ||
| 44 | + bool isSelect = false; | ||
| 45 | + | ||
| 46 | + Results( | ||
| 47 | + {this.geometry, | ||
| 48 | + this.icon, | ||
| 49 | + this.iconBackgroundColor, | ||
| 50 | + this.iconMaskBaseUri, | ||
| 51 | + this.name, | ||
| 52 | + this.photos, | ||
| 53 | + this.placeId, | ||
| 54 | + this.reference, | ||
| 55 | + this.scope, | ||
| 56 | + this.types, | ||
| 57 | + this.vicinity, | ||
| 58 | + this.businessStatus, | ||
| 59 | + this.openingHours, | ||
| 60 | + this.plusCode, | ||
| 61 | + this.rating, | ||
| 62 | + this.userRatingsTotal, | ||
| 63 | + this.isSelect = false}); | ||
| 64 | + | ||
| 65 | + Results.fromJson(Map<String, dynamic> json) { | ||
| 66 | + geometry = json['geometry'] != null ? Geometry.fromJson(json['geometry']) : null; | ||
| 67 | + icon = json['icon']; | ||
| 68 | + iconBackgroundColor = json['icon_background_color']; | ||
| 69 | + iconMaskBaseUri = json['icon_mask_base_uri']; | ||
| 70 | + name = json['name']; | ||
| 71 | + if (json['photos'] != null) { | ||
| 72 | + photos = <Photos>[]; | ||
| 73 | + json['photos'].forEach((v) { | ||
| 74 | + photos!.add(Photos.fromJson(v)); | ||
| 75 | + }); | ||
| 76 | + } | ||
| 77 | + placeId = json['place_id']; | ||
| 78 | + reference = json['reference']; | ||
| 79 | + scope = json['scope']; | ||
| 80 | + types = json['types'].cast<String>(); | ||
| 81 | + vicinity = json['vicinity']; | ||
| 82 | + businessStatus = json['business_status']; | ||
| 83 | + openingHours = json['opening_hours'] != null ? OpeningHours.fromJson(json['opening_hours']) : null; | ||
| 84 | + plusCode = json['plus_code'] != null ? PlusCode.fromJson(json['plus_code']) : null; | ||
| 85 | + rating = json['rating']; | ||
| 86 | + userRatingsTotal = json['user_ratings_total']; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + Map<String, dynamic> toJson() { | ||
| 90 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 91 | + if (this.geometry != null) { | ||
| 92 | + data['geometry'] = this.geometry!.toJson(); | ||
| 93 | + } | ||
| 94 | + data['icon'] = this.icon; | ||
| 95 | + data['icon_background_color'] = this.iconBackgroundColor; | ||
| 96 | + data['icon_mask_base_uri'] = this.iconMaskBaseUri; | ||
| 97 | + data['name'] = this.name; | ||
| 98 | + if (this.photos != null) { | ||
| 99 | + data['photos'] = this.photos!.map((v) => v.toJson()).toList(); | ||
| 100 | + } | ||
| 101 | + data['place_id'] = this.placeId; | ||
| 102 | + data['reference'] = this.reference; | ||
| 103 | + data['scope'] = this.scope; | ||
| 104 | + data['types'] = this.types; | ||
| 105 | + data['vicinity'] = this.vicinity; | ||
| 106 | + data['business_status'] = this.businessStatus; | ||
| 107 | + if (this.openingHours != null) { | ||
| 108 | + data['opening_hours'] = this.openingHours!.toJson(); | ||
| 109 | + } | ||
| 110 | + if (this.plusCode != null) { | ||
| 111 | + data['plus_code'] = this.plusCode!.toJson(); | ||
| 112 | + } | ||
| 113 | + data['rating'] = this.rating; | ||
| 114 | + data['user_ratings_total'] = this.userRatingsTotal; | ||
| 115 | + return data; | ||
| 116 | + } | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +class Geometry { | ||
| 120 | + Location? location; | ||
| 121 | + Viewport? viewport; | ||
| 122 | + | ||
| 123 | + Geometry({this.location, this.viewport}); | ||
| 124 | + | ||
| 125 | + Geometry.fromJson(Map<String, dynamic> json) { | ||
| 126 | + location = json['location'] != null ? Location.fromJson(json['location']) : null; | ||
| 127 | + viewport = json['viewport'] != null ? Viewport.fromJson(json['viewport']) : null; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + Map<String, dynamic> toJson() { | ||
| 131 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 132 | + if (this.location != null) { | ||
| 133 | + data['location'] = this.location!.toJson(); | ||
| 134 | + } | ||
| 135 | + if (this.viewport != null) { | ||
| 136 | + data['viewport'] = this.viewport!.toJson(); | ||
| 137 | + } | ||
| 138 | + return data; | ||
| 139 | + } | ||
| 140 | +} | ||
| 141 | + | ||
| 142 | +class Location { | ||
| 143 | + double? lat; | ||
| 144 | + double? lng; | ||
| 145 | + | ||
| 146 | + Location({this.lat, this.lng}); | ||
| 147 | + | ||
| 148 | + Location.fromJson(Map<String, dynamic> json) { | ||
| 149 | + lat = json['lat']; | ||
| 150 | + lng = json['lng']; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + Map<String, dynamic> toJson() { | ||
| 154 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 155 | + data['lat'] = this.lat; | ||
| 156 | + data['lng'] = this.lng; | ||
| 157 | + return data; | ||
| 158 | + } | ||
| 159 | +} | ||
| 160 | + | ||
| 161 | +class Viewport { | ||
| 162 | + Location? northeast; | ||
| 163 | + Location? southwest; | ||
| 164 | + | ||
| 165 | + Viewport({this.northeast, this.southwest}); | ||
| 166 | + | ||
| 167 | + Viewport.fromJson(Map<String, dynamic> json) { | ||
| 168 | + northeast = json['northeast'] != null ? Location.fromJson(json['northeast']) : null; | ||
| 169 | + southwest = json['southwest'] != null ? Location.fromJson(json['southwest']) : null; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + Map<String, dynamic> toJson() { | ||
| 173 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 174 | + if (this.northeast != null) { | ||
| 175 | + data['northeast'] = this.northeast!.toJson(); | ||
| 176 | + } | ||
| 177 | + if (this.southwest != null) { | ||
| 178 | + data['southwest'] = this.southwest!.toJson(); | ||
| 179 | + } | ||
| 180 | + return data; | ||
| 181 | + } | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +class Photos { | ||
| 185 | + int? height; | ||
| 186 | + List<String>? htmlAttributions; | ||
| 187 | + String? photoReference; | ||
| 188 | + int? width; | ||
| 189 | + | ||
| 190 | + Photos({this.height, this.htmlAttributions, this.photoReference, this.width}); | ||
| 191 | + | ||
| 192 | + Photos.fromJson(Map<String, dynamic> json) { | ||
| 193 | + height = json['height']; | ||
| 194 | + htmlAttributions = json['html_attributions'].cast<String>(); | ||
| 195 | + photoReference = json['photo_reference']; | ||
| 196 | + width = json['width']; | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + Map<String, dynamic> toJson() { | ||
| 200 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 201 | + data['height'] = this.height; | ||
| 202 | + data['html_attributions'] = this.htmlAttributions; | ||
| 203 | + data['photo_reference'] = this.photoReference; | ||
| 204 | + data['width'] = this.width; | ||
| 205 | + return data; | ||
| 206 | + } | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | +class OpeningHours { | ||
| 210 | + bool? openNow; | ||
| 211 | + | ||
| 212 | + OpeningHours({this.openNow}); | ||
| 213 | + | ||
| 214 | + OpeningHours.fromJson(Map<String, dynamic> json) { | ||
| 215 | + openNow = json['open_now']; | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + Map<String, dynamic> toJson() { | ||
| 219 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 220 | + data['open_now'] = this.openNow; | ||
| 221 | + return data; | ||
| 222 | + } | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +class PlusCode { | ||
| 226 | + String? compoundCode; | ||
| 227 | + String? globalCode; | ||
| 228 | + | ||
| 229 | + PlusCode({this.compoundCode, this.globalCode}); | ||
| 230 | + | ||
| 231 | + PlusCode.fromJson(Map<String, dynamic> json) { | ||
| 232 | + compoundCode = json['compound_code']; | ||
| 233 | + globalCode = json['global_code']; | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + Map<String, dynamic> toJson() { | ||
| 237 | + final Map<String, dynamic> data = Map<String, dynamic>(); | ||
| 238 | + data['compound_code'] = this.compoundCode; | ||
| 239 | + data['global_code'] = this.globalCode; | ||
| 240 | + return data; | ||
| 241 | + } | ||
| 242 | +} |
lib/models/poisearch_model.dart
0 → 100644
| 1 | +class PoiSearch { | ||
| 2 | + PoiSearch({ | ||
| 3 | + required this.cityCode, | ||
| 4 | + required this.cityName, | ||
| 5 | + required this.provinceName, | ||
| 6 | + required this.title, | ||
| 7 | + required this.adName, | ||
| 8 | + required this.provinceCode, | ||
| 9 | + required this.latitude, | ||
| 10 | + required this.longitude, | ||
| 11 | + }); | ||
| 12 | + | ||
| 13 | + PoiSearch.fromJsonMap(Map<String, dynamic> map) | ||
| 14 | + : cityCode = map['cityCode'] as String, | ||
| 15 | + cityName = map['cityName'] as String, | ||
| 16 | + provinceName = map['provinceName'] as String, | ||
| 17 | + title = map['title'] as String, | ||
| 18 | + adName = map['adName'] as String, | ||
| 19 | + provinceCode = map['provinceCode'] as String, | ||
| 20 | + latitude = map['latitude'] as String, | ||
| 21 | + longitude = map['longitude'] as String; | ||
| 22 | + | ||
| 23 | + String cityCode; | ||
| 24 | + String cityName; | ||
| 25 | + String provinceName; | ||
| 26 | + String title; | ||
| 27 | + String adName; | ||
| 28 | + String provinceCode; | ||
| 29 | + String latitude; | ||
| 30 | + String longitude; | ||
| 31 | + | ||
| 32 | + Map<String, dynamic> toJson() { | ||
| 33 | + final Map<String, dynamic> data = <String, dynamic>{}; | ||
| 34 | + data['cityCode'] = cityCode; | ||
| 35 | + data['cityName'] = cityName; | ||
| 36 | + data['provinceName'] = provinceName; | ||
| 37 | + data['title'] = title; | ||
| 38 | + data['adName'] = adName; | ||
| 39 | + data['provinceCode'] = provinceCode; | ||
| 40 | + data['latitude'] = latitude; | ||
| 41 | + data['longitude'] = longitude; | ||
| 42 | + return data; | ||
| 43 | + } | ||
| 44 | +} |
| ... | @@ -7,6 +7,7 @@ class HttpApi { | ... | @@ -7,6 +7,7 @@ class HttpApi { |
| 7 | static const String uploadVideo = 'upload/video'; | 7 | static const String uploadVideo = 'upload/video'; |
| 8 | static const String uploadImage = 'upload/image'; | 8 | static const String uploadImage = 'upload/image'; |
| 9 | static const String immersive = 'immersive'; | 9 | static const String immersive = 'immersive'; |
| 10 | + static const String changePassword = 'user/changePassword'; | ||
| 10 | static const String avatar = 'avatar'; | 11 | static const String avatar = 'avatar'; |
| 11 | static const String user = 'user'; | 12 | static const String user = 'user'; |
| 12 | static const String membership = 'membership'; | 13 | static const String membership = 'membership'; | ... | ... |
lib/payment/payment_sdk.dart
0 → 100644
| 1 | +import 'dart:async'; | ||
| 2 | + | ||
| 3 | +import 'package:Parlando/apis/api_order.dart'; | ||
| 4 | +import 'package:Parlando/membership/models/membership_entity.dart'; | ||
| 5 | +import 'package:common_utils/common_utils.dart'; | ||
| 6 | +import 'package:in_app_purchase/in_app_purchase.dart'; | ||
| 7 | +import 'package:in_app_purchase_android/in_app_purchase_android.dart'; | ||
| 8 | +import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; | ||
| 9 | + | ||
| 10 | +class PaymentSdk { | ||
| 11 | + var currentOrder; | ||
| 12 | + | ||
| 13 | + PaymentSdk._privateConstructor(); | ||
| 14 | + | ||
| 15 | + static final PaymentSdk _instance = PaymentSdk._privateConstructor(); | ||
| 16 | + | ||
| 17 | + static PaymentSdk get instance { | ||
| 18 | + return _instance; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + static const Set<String> _kIds = <String>{'yearly_yiyan_vip', 'monthly_yiyan_vip'}; | ||
| 22 | + | ||
| 23 | + StreamSubscription<List<PurchaseDetails>>? _subscription; | ||
| 24 | + List<ProductDetails> products = []; | ||
| 25 | + Function? onPaySuccess; | ||
| 26 | + Function? onPending; | ||
| 27 | + Function? onFailed; | ||
| 28 | + Function? onCancel; | ||
| 29 | + | ||
| 30 | + initState({ | ||
| 31 | + Function? onPaySuccess, | ||
| 32 | + Function? onPending, | ||
| 33 | + Function? onFailed, | ||
| 34 | + Function? onCancel, | ||
| 35 | + }) { | ||
| 36 | + this.onPaySuccess = onPaySuccess; | ||
| 37 | + this.onPending = onPending; | ||
| 38 | + this.onFailed = onFailed; | ||
| 39 | + this.onCancel = onCancel; | ||
| 40 | + final Stream<List<PurchaseDetails>> purchaseUpdated = InAppPurchase.instance.purchaseStream; | ||
| 41 | + _subscription = purchaseUpdated.listen((purchaseDetailsList) { | ||
| 42 | + _listenToPurchaseUpdated(purchaseDetailsList); | ||
| 43 | + }, onDone: () { | ||
| 44 | + _subscription?.cancel(); | ||
| 45 | + }, onError: (error) { | ||
| 46 | + // handle error here. | ||
| 47 | + }); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + Future<List<ProductDetails>> queryProducts() async { | ||
| 51 | + final bool available = await InAppPurchase.instance.isAvailable(); | ||
| 52 | + if (!available) { | ||
| 53 | + return []; | ||
| 54 | + } | ||
| 55 | + final ProductDetailsResponse response = await InAppPurchase.instance.queryProductDetails(_kIds); | ||
| 56 | + return products = response.productDetails; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + buy(ProductDetails details, MembershipDataGoodsList e) { | ||
| 60 | + OrderApi.request.createOrder(e.id.toString()).then((value) { | ||
| 61 | + var orderId = value?['data']?['data']?['order_sn']; | ||
| 62 | + if (TextUtil.isEmpty(orderId)) { | ||
| 63 | + onFailed?.call(); | ||
| 64 | + return; | ||
| 65 | + } | ||
| 66 | + currentOrder = orderId; | ||
| 67 | + final PurchaseParam purchaseParam = PurchaseParam(productDetails: details, applicationUserName: orderId); | ||
| 68 | + if (_isConsumable(details)) { | ||
| 69 | + InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam); | ||
| 70 | + } else { | ||
| 71 | + InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam); | ||
| 72 | + } | ||
| 73 | + }); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async { | ||
| 77 | + for (var purchaseDetails in purchaseDetailsList) { | ||
| 78 | + if (purchaseDetails.status == PurchaseStatus.pending) { | ||
| 79 | + onPending?.call(); | ||
| 80 | + } else { | ||
| 81 | + if (purchaseDetails.status == PurchaseStatus.error) { | ||
| 82 | + _handleError(purchaseDetails.error!); | ||
| 83 | + } else if (purchaseDetails.status == PurchaseStatus.purchased || purchaseDetails.status == PurchaseStatus.restored) { | ||
| 84 | + bool valid = await _verifyPurchase(purchaseDetails); | ||
| 85 | + if (valid) { | ||
| 86 | + _deliverProduct(purchaseDetails); | ||
| 87 | + } else { | ||
| 88 | + _handleInvalidPurchase(purchaseDetails); | ||
| 89 | + } | ||
| 90 | + } else { | ||
| 91 | + onCancel?.call(); | ||
| 92 | + } | ||
| 93 | + if (purchaseDetails.pendingCompletePurchase) { | ||
| 94 | + await InAppPurchase.instance.completePurchase(purchaseDetails); | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + _verifyPurchase(PurchaseDetails purchaseDetails) async { | ||
| 101 | + return true; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + void _deliverProduct(PurchaseDetails purchaseDetails) { | ||
| 105 | + String type = ""; | ||
| 106 | + Map<String, dynamic> otherField = {}; | ||
| 107 | + if (purchaseDetails is GooglePlayPurchaseDetails) { | ||
| 108 | + currentOrder = purchaseDetails.billingClientPurchase.obfuscatedAccountId; | ||
| 109 | + type = "google"; | ||
| 110 | + otherField["google"] = { | ||
| 111 | + "originalJson": purchaseDetails.billingClientPurchase.originalJson, | ||
| 112 | + }; | ||
| 113 | + } | ||
| 114 | + if (purchaseDetails is AppStorePurchaseDetails) { | ||
| 115 | + type = "apple"; | ||
| 116 | + otherField["apple"] = { | ||
| 117 | + "transactionIdentifier": purchaseDetails.skPaymentTransaction.transactionIdentifier, | ||
| 118 | + "originalTransactionIdentifier": | ||
| 119 | + purchaseDetails.skPaymentTransaction.originalTransaction?.transactionIdentifier ?? "", | ||
| 120 | + }; | ||
| 121 | + } | ||
| 122 | + var serverVerifyStr = purchaseDetails.verificationData.serverVerificationData; | ||
| 123 | + var verifySource = purchaseDetails.verificationData.source; | ||
| 124 | + otherField["source"] = verifySource; | ||
| 125 | + OrderApi.request.verifyOrder(currentOrder, type, serverVerifyStr, others: otherField).then((value) { | ||
| 126 | + if (value != null) {} | ||
| 127 | + onPaySuccess?.call(); | ||
| 128 | + }); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + void _handleInvalidPurchase(PurchaseDetails purchaseDetails) { | ||
| 132 | + onFailed?.call(); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + void _handleError(IAPError iapError) { | ||
| 136 | + onFailed?.call(); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + bool _isConsumable(ProductDetails details) { | ||
| 140 | + return false; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + void restore() { | ||
| 144 | + InAppPurchase.instance.restorePurchases(); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + void dispose() { | ||
| 148 | + onPaySuccess = null; | ||
| 149 | + onPending = null; | ||
| 150 | + onFailed = null; | ||
| 151 | + onCancel = null; | ||
| 152 | + _subscription?.cancel(); | ||
| 153 | + } | ||
| 154 | +} |
| ... | @@ -26,7 +26,7 @@ class PaymentService { | ... | @@ -26,7 +26,7 @@ class PaymentService { |
| 26 | late StreamSubscription<PurchaseResult?> _purchaseErrorSubscription; | 26 | late StreamSubscription<PurchaseResult?> _purchaseErrorSubscription; |
| 27 | 27 | ||
| 28 | /// List of product ids you want to fetch | 28 | /// List of product ids you want to fetch |
| 29 | - final List<String> _productIds = ['test.yiyan.vip.1.month']; | 29 | + final List<String> _productIds = ['yearly_yiyan_vip', 'monthly_yiyan_vip']; |
| 30 | 30 | ||
| 31 | /// All available products will be store in this list | 31 | /// All available products will be store in this list |
| 32 | late List<IAPItem> _products; | 32 | late List<IAPItem> _products; |
| ... | @@ -36,12 +36,12 @@ class PaymentService { | ... | @@ -36,12 +36,12 @@ class PaymentService { |
| 36 | 36 | ||
| 37 | /// view of the app will subscribe to this to get notified | 37 | /// view of the app will subscribe to this to get notified |
| 38 | /// when premium status of the user changes | 38 | /// when premium status of the user changes |
| 39 | - final ObserverList<Function> _proStatusChangedListeners = | 39 | + final ObserverList<Function> _proStatusChangedListeners = ObserverList<Function>(); |
| 40 | - ObserverList<Function>(); | ||
| 41 | 40 | ||
| 42 | /// view of the app will subscribe to this to get errors of the purchase | 41 | /// view of the app will subscribe to this to get errors of the purchase |
| 43 | - final ObserverList<Function(String)> _errorListeners = | 42 | + final ObserverList<Function(String)> _errorListeners = ObserverList<Function(String)>(); |
| 44 | - ObserverList<Function(String)>(); | 43 | + |
| 44 | + final ObserverList<Function> _connectListeners = ObserverList<Function>(); | ||
| 45 | 45 | ||
| 46 | /// logged in user's premium status | 46 | /// logged in user's premium status |
| 47 | bool _isProUser = false; | 47 | bool _isProUser = false; |
| ... | @@ -68,6 +68,20 @@ class PaymentService { | ... | @@ -68,6 +68,20 @@ class PaymentService { |
| 68 | _errorListeners.remove(callback); | 68 | _errorListeners.remove(callback); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | + addConnectListener(Function? callback) { | ||
| 72 | + if (callback == null) { | ||
| 73 | + return; | ||
| 74 | + } | ||
| 75 | + _connectListeners.add(callback); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + removeConnectListener(Function? callback) { | ||
| 79 | + if (callback == null) { | ||
| 80 | + return; | ||
| 81 | + } | ||
| 82 | + _connectListeners.remove(callback); | ||
| 83 | + } | ||
| 84 | + | ||
| 71 | /// Call this method to notify all the subsctibers of _proStatusChangedListeners | 85 | /// Call this method to notify all the subsctibers of _proStatusChangedListeners |
| 72 | void _callProStatusChangedListeners() { | 86 | void _callProStatusChangedListeners() { |
| 73 | for (var callback in _proStatusChangedListeners) { | 87 | for (var callback in _proStatusChangedListeners) { |
| ... | @@ -84,18 +98,19 @@ class PaymentService { | ... | @@ -84,18 +98,19 @@ class PaymentService { |
| 84 | 98 | ||
| 85 | /// Call this method at the startup of you app to initialize connection | 99 | /// Call this method at the startup of you app to initialize connection |
| 86 | /// with billing server and get all the necessary data | 100 | /// with billing server and get all the necessary data |
| 87 | - void initConnection() { | 101 | + void initConnection() async { |
| 88 | - var result = FlutterInappPurchase.instance.initialize(); | 102 | + var result = await FlutterInappPurchase.instance.initialize(); |
| 89 | print("___________________________"); | 103 | print("___________________________"); |
| 90 | print("result:$result"); | 104 | print("result:$result"); |
| 91 | - _connectionSubscription = | 105 | + _connectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) { |
| 92 | - FlutterInappPurchase.connectionUpdated.listen((connected) {}); | 106 | + for (var value in _connectListeners) { |
| 107 | + value.call(); | ||
| 108 | + } | ||
| 109 | + }); | ||
| 93 | 110 | ||
| 94 | - _purchaseUpdatedSubscription = | 111 | + _purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen(_handlePurchaseUpdate); |
| 95 | - FlutterInappPurchase.purchaseUpdated.listen(_handlePurchaseUpdate); | ||
| 96 | 112 | ||
| 97 | - _purchaseErrorSubscription = | 113 | + _purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen(_handlePurchaseError); |
| 98 | - FlutterInappPurchase.purchaseError.listen(_handlePurchaseError); | ||
| 99 | 114 | ||
| 100 | _getItems(); | 115 | _getItems(); |
| 101 | _getPastPurchases(); | 116 | _getPastPurchases(); |
| ... | @@ -191,14 +206,14 @@ class PaymentService { | ... | @@ -191,14 +206,14 @@ class PaymentService { |
| 191 | } | 206 | } |
| 192 | 207 | ||
| 193 | Future<void> _getItems() async { | 208 | Future<void> _getItems() async { |
| 194 | - List<IAPItem> items = | 209 | + List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions(_productIds); |
| 195 | - await FlutterInappPurchase.instance.getSubscriptions(_productIds); | 210 | + print("############${items.length}"); |
| 196 | _products = []; | 211 | _products = []; |
| 197 | for (var item in items) { | 212 | for (var item in items) { |
| 198 | _products.add(item); | 213 | _products.add(item); |
| 199 | } | 214 | } |
| 200 | print("############"); | 215 | print("############"); |
| 201 | - print(_products); | 216 | + print("############${_products}"); |
| 202 | } | 217 | } |
| 203 | 218 | ||
| 204 | void _getPastPurchases() async { | 219 | void _getPastPurchases() async { |
| ... | @@ -206,8 +221,7 @@ class PaymentService { | ... | @@ -206,8 +221,7 @@ class PaymentService { |
| 206 | if (Platform.isIOS) { | 221 | if (Platform.isIOS) { |
| 207 | return; | 222 | return; |
| 208 | } | 223 | } |
| 209 | - List<PurchasedItem>? purchasedItems = | 224 | + List<PurchasedItem>? purchasedItems = await FlutterInappPurchase.instance.getAvailablePurchases(); |
| 210 | - await FlutterInappPurchase.instance.getAvailablePurchases(); | ||
| 211 | 225 | ||
| 212 | for (var purchasedItem in purchasedItems!) { | 226 | for (var purchasedItem in purchasedItems!) { |
| 213 | bool isValid = false; | 227 | bool isValid = false; |
| ... | @@ -236,8 +250,7 @@ class PaymentService { | ... | @@ -236,8 +250,7 @@ class PaymentService { |
| 236 | 250 | ||
| 237 | Future<void> buyProduct(IAPItem item) async { | 251 | Future<void> buyProduct(IAPItem item) async { |
| 238 | try { | 252 | try { |
| 239 | - await FlutterInappPurchase.instance | 253 | + await FlutterInappPurchase.instance.requestSubscription(item.productId.toString()); |
| 240 | - .requestSubscription(item.productId.toString()); | ||
| 241 | } catch (error) { | 254 | } catch (error) { |
| 242 | Toast.show("购买失败!"); | 255 | Toast.show("购买失败!"); |
| 243 | } | 256 | } | ... | ... |
| 1 | +import 'package:Parlando/models/nearby_response.dart'; | ||
| 1 | import 'package:Parlando/models/upload_entity.dart'; | 2 | import 'package:Parlando/models/upload_entity.dart'; |
| 2 | import 'package:Parlando/net/dio_utils.dart'; | 3 | import 'package:Parlando/net/dio_utils.dart'; |
| 3 | import 'package:Parlando/net/http_api.dart'; | 4 | import 'package:Parlando/net/http_api.dart'; |
| ... | @@ -109,12 +110,10 @@ class PoemPublishState extends State<PoemPublish> { | ... | @@ -109,12 +110,10 @@ class PoemPublishState extends State<PoemPublish> { |
| 109 | NavigatorUtils.pushResult( | 110 | NavigatorUtils.pushResult( |
| 110 | context, PoemRouter.addressSelectPage, (result) { | 111 | context, PoemRouter.addressSelectPage, (result) { |
| 111 | setState(() { | 112 | setState(() { |
| 112 | - // final BMFSuggestionInfo model = | 113 | + final Results model = result as Results; |
| 113 | - // result as BMFSuggestionInfo; | 114 | + _longitude = model.geometry!.location!.lng.toString(); |
| 114 | - // _longitude = model.location!.longitude.toString(); | 115 | + _latitude = model.geometry!.location!.lat.toString(); |
| 115 | - // _latitude = model.location!.latitude.toString(); | 116 | + _address = '${model.name} ${model.vicinity}'; |
| 116 | - // _address = | ||
| 117 | - // '${model.city!} ${model.district!} ${model.address!}'; | ||
| 118 | }); | 117 | }); |
| 119 | }); | 118 | }); |
| 120 | }, | 119 | }, |
| ... | @@ -130,12 +129,22 @@ class PoemPublishState extends State<PoemPublish> { | ... | @@ -130,12 +129,22 @@ class PoemPublishState extends State<PoemPublish> { |
| 130 | size: 15.px, | 129 | size: 15.px, |
| 131 | ), | 130 | ), |
| 132 | Gaps.hGap5, | 131 | Gaps.hGap5, |
| 132 | + Container( | ||
| 133 | + padding: const EdgeInsets.fromLTRB(0, 0, 10, 10), | ||
| 134 | + width: MediaQuery.of(context).size.width * 0.8, | ||
| 135 | + alignment: Alignment.centerLeft, | ||
| 136 | + child: Column( | ||
| 137 | + children: <Widget>[ | ||
| 133 | Text( | 138 | Text( |
| 134 | _address, | 139 | _address, |
| 135 | style: const TextStyle(color: Colors.black45), | 140 | style: const TextStyle(color: Colors.black45), |
| 141 | + textAlign: TextAlign.left, | ||
| 136 | ), | 142 | ), |
| 137 | ], | 143 | ], |
| 138 | ), | 144 | ), |
| 145 | + ) | ||
| 146 | + ], | ||
| 147 | + ), | ||
| 139 | ), | 148 | ), |
| 140 | ), | 149 | ), |
| 141 | InkWell( | 150 | InkWell( | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
| ... | @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev | ... | @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev |
| 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. | 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. |
| 16 | # Read more about iOS versioning at | 16 | # Read more about iOS versioning at |
| 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html | 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html |
| 18 | -version: 1.0.0+12 | 18 | +version: 1.0.0+16 |
| 19 | 19 | ||
| 20 | environment: | 20 | environment: |
| 21 | sdk: ">=2.16.2 <3.0.0" | 21 | sdk: ">=2.16.2 <3.0.0" |
| ... | @@ -101,11 +101,13 @@ dependencies: | ... | @@ -101,11 +101,13 @@ dependencies: |
| 101 | 101 | ||
| 102 | # A Dart timer that can be paused, resumed and reset. | 102 | # A Dart timer that can be paused, resumed and reset. |
| 103 | pausable_timer: ^1.0.0+3 | 103 | pausable_timer: ^1.0.0+3 |
| 104 | + | ||
| 105 | + flutter_easyloading: ^3.0.0 | ||
| 104 | email_validator: ^2.0.1 | 106 | email_validator: ^2.0.1 |
| 105 | 107 | ||
| 106 | getwidget: ^2.0.5 | 108 | getwidget: ^2.0.5 |
| 107 | sign_in_with_apple: ^4.0.0 | 109 | sign_in_with_apple: ^4.0.0 |
| 108 | - flutter_facebook_auth: ^4.3.4+2 | 110 | + flutter_facebook_auth: ^5.0.6 |
| 109 | flutter_signin_button: ^2.0.0 | 111 | flutter_signin_button: ^2.0.0 |
| 110 | twitter_login: ^4.2.3 | 112 | twitter_login: ^4.2.3 |
| 111 | 113 | ||
| ... | @@ -114,7 +116,10 @@ dependencies: | ... | @@ -114,7 +116,10 @@ dependencies: |
| 114 | animated_radial_menu: | 116 | animated_radial_menu: |
| 115 | path: plugins/animated_radial | 117 | path: plugins/animated_radial |
| 116 | 118 | ||
| 119 | + # 非官方库 暂时不删 | ||
| 117 | flutter_inapp_purchase: ^5.3.0 | 120 | flutter_inapp_purchase: ^5.3.0 |
| 121 | + # Flutter官方支付支持库 | ||
| 122 | + in_app_purchase: ^3.0.8 | ||
| 118 | 123 | ||
| 119 | jpush_flutter: ^2.2.9 | 124 | jpush_flutter: ^2.2.9 |
| 120 | share_plus: ^4.0.10 | 125 | share_plus: ^4.0.10 |
| ... | @@ -125,7 +130,9 @@ dependencies: | ... | @@ -125,7 +130,9 @@ dependencies: |
| 125 | google_fonts: ^3.0.1 | 130 | google_fonts: ^3.0.1 |
| 126 | wakelock: ^0.6.1+2 | 131 | wakelock: ^0.6.1+2 |
| 127 | location: ^4.4.0 | 132 | location: ^4.4.0 |
| 128 | - google_maps_flutter: ^2.1.10 | 133 | + # GoogleMap支持库 |
| 134 | + google_maps_flutter: ^2.2.1 | ||
| 135 | + http: ^0.13.5 | ||
| 129 | 136 | ||
| 130 | dependency_overrides: | 137 | dependency_overrides: |
| 131 | decimal: 1.5.0 | 138 | decimal: 1.5.0 | ... | ... |
-
Please register or login to post a comment