Reason Pun

Merge remote-tracking branch 'origin/dev_reason_v1.0' into dev_reason_v1.0

# Conflicts:
#	android/app/build.gradle
#	pubspec.lock
...@@ -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>
......
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>
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 +}
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 +}
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 +}
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;
60 - NavigatorUtils.goBack(context); 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;
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: (_) {
...@@ -236,4 +231,4 @@ Future<bool> requestLocationPermission() async { ...@@ -236,4 +231,4 @@ Future<bool> requestLocationPermission() async {
236 return false; 231 return false;
237 } 232 }
238 } 233 }
239 -}
...\ No newline at end of file ...\ No newline at end of file
234 +}
......
...@@ -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.
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 +}
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';
......
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,10 +129,20 @@ class PoemPublishState extends State<PoemPublish> { ...@@ -130,10 +129,20 @@ class PoemPublishState extends State<PoemPublish> {
130 size: 15.px, 129 size: 15.px,
131 ), 130 ),
132 Gaps.hGap5, 131 Gaps.hGap5,
133 - Text( 132 + Container(
134 - _address, 133 + padding: const EdgeInsets.fromLTRB(0, 0, 10, 10),
135 - style: const TextStyle(color: Colors.black45), 134 + width: MediaQuery.of(context).size.width * 0.8,
136 - ), 135 + alignment: Alignment.centerLeft,
136 + child: Column(
137 + children: <Widget>[
138 + Text(
139 + _address,
140 + style: const TextStyle(color: Colors.black45),
141 + textAlign: TextAlign.left,
142 + ),
143 + ],
144 + ),
145 + )
137 ], 146 ],
138 ), 147 ),
139 ), 148 ),
...@@ -209,12 +218,12 @@ class PoemPublishState extends State<PoemPublish> { ...@@ -209,12 +218,12 @@ class PoemPublishState extends State<PoemPublish> {
209 Gaps.vGap10, 218 Gaps.vGap10,
210 isUploading 219 isUploading
211 ? Padding( 220 ? Padding(
212 - padding: const EdgeInsets.all(20), 221 + padding: const EdgeInsets.all(20),
213 - child: ValueListenableBuilder<double>( 222 + child: ValueListenableBuilder<double>(
214 - builder: _buildWithValue, 223 + builder: _buildWithValue,
215 - valueListenable: _counter, 224 + valueListenable: _counter,
216 - ), 225 + ),
217 - ) 226 + )
218 : Container(), 227 : Container(),
219 ], 228 ],
220 ), 229 ),
...@@ -224,10 +233,10 @@ class PoemPublishState extends State<PoemPublish> { ...@@ -224,10 +233,10 @@ class PoemPublishState extends State<PoemPublish> {
224 ), 233 ),
225 isPublishing 234 isPublishing
226 ? const Center( 235 ? const Center(
227 - child: CupertinoActivityIndicator( 236 + child: CupertinoActivityIndicator(
228 - radius: 16.0, 237 + radius: 16.0,
229 - ), 238 + ),
230 - ) 239 + )
231 : Container(), 240 : Container(),
232 ], 241 ],
233 ), 242 ),
......
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
......