reason

Merge branch 'dev_chad_v1.0' into 'dev_reason_v1.0'

Google Map& Google 订阅支付



See merge request !1
...@@ -75,6 +75,9 @@ android { ...@@ -75,6 +75,9 @@ android {
75 release { 75 release {
76 signingConfig signingConfigs.release 76 signingConfig signingConfigs.release
77 } 77 }
78 + debug {
79 + signingConfig signingConfigs.release
80 + }
78 } 81 }
79 82
80 } 83 }
......
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 +}
1 +import 'package:flutter/material.dart';
2 +import 'package:flutter_easyloading/flutter_easyloading.dart';
3 +
4 +abstract class BaseState<T extends StatefulWidget> extends State<T> {
5 + bool _isFirstBuild = true;
6 +
7 + @override
8 + Widget build(BuildContext context) {
9 + if (_isFirstBuild) {
10 + onFirstBuildBody(context);
11 + _isFirstBuild = false;
12 + }
13 + return buildBody(context);
14 + }
15 +
16 + Widget buildBody(BuildContext context);
17 +
18 + void onFirstBuildBody(BuildContext context) {}
19 +
20 + showLoading({String text = 'Loading...'}) {
21 + EasyLoading.show(status: text);
22 + }
23 +
24 + hideLoading() {
25 + EasyLoading.dismiss();
26 + }
27 +
28 + toast(String text) {
29 + EasyLoading.showToast(text);
30 + }
31 +
32 + Widget buildLoading() {
33 + return const Center(child: CircularProgressIndicator());
34 + }
35 +}
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 +}
...@@ -116,17 +116,19 @@ Map<String, dynamic> $MembershipDataToJson(MembershipData entity) { ...@@ -116,17 +116,19 @@ Map<String, dynamic> $MembershipDataToJson(MembershipData entity) {
116 116
117 MembershipDataGoodsList $MembershipDataGoodsListFromJson( 117 MembershipDataGoodsList $MembershipDataGoodsListFromJson(
118 Map<String, dynamic> json) { 118 Map<String, dynamic> json) {
119 - final MembershipDataGoodsList membershipDataGoodsList = 119 + final MembershipDataGoodsList membershipDataGoodsList = MembershipDataGoodsList();
120 - MembershipDataGoodsList();
121 final int? id = jsonConvert.convert<int>(json['id']); 120 final int? id = jsonConvert.convert<int>(json['id']);
122 if (id != null) { 121 if (id != null) {
123 membershipDataGoodsList.id = id; 122 membershipDataGoodsList.id = id;
124 } 123 }
125 - final String? membershipId = 124 + final String? membershipId = jsonConvert.convert<String>(json['membership_id']);
126 - jsonConvert.convert<String>(json['membership_id']);
127 if (membershipId != null) { 125 if (membershipId != null) {
128 membershipDataGoodsList.membershipId = membershipId; 126 membershipDataGoodsList.membershipId = membershipId;
129 } 127 }
128 + final String? iapId = jsonConvert.convert<String>(json['iap_id']);
129 + if (iapId != null) {
130 + membershipDataGoodsList.iapId = iapId;
131 + }
130 final String? name = jsonConvert.convert<String>(json['name']); 132 final String? name = jsonConvert.convert<String>(json['name']);
131 if (name != null) { 133 if (name != null) {
132 membershipDataGoodsList.name = name; 134 membershipDataGoodsList.name = name;
...@@ -192,6 +194,7 @@ Map<String, dynamic> $MembershipDataGoodsListToJson( ...@@ -192,6 +194,7 @@ Map<String, dynamic> $MembershipDataGoodsListToJson(
192 final Map<String, dynamic> data = <String, dynamic>{}; 194 final Map<String, dynamic> data = <String, dynamic>{};
193 data['id'] = entity.id; 195 data['id'] = entity.id;
194 data['membership_id'] = entity.membershipId; 196 data['membership_id'] = entity.membershipId;
197 + data['iap_id'] = entity.iapId;
195 data['name'] = entity.name; 198 data['name'] = entity.name;
196 data['price'] = entity.price; 199 data['price'] = entity.price;
197 data['line_price'] = entity.linePrice; 200 data['line_price'] = entity.linePrice;
......
...@@ -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 +}
......
...@@ -65,6 +65,8 @@ class MembershipDataGoodsList { ...@@ -65,6 +65,8 @@ class MembershipDataGoodsList {
65 int? id; 65 int? id;
66 @JSONField(name: "membership_id") 66 @JSONField(name: "membership_id")
67 String? membershipId; 67 String? membershipId;
68 + @JSONField(name: "iap_id")
69 + String? iapId;
68 String? name; 70 String? name;
69 String? price; 71 String? price;
70 @JSONField(name: "line_price") 72 @JSONField(name: "line_price")
......
This diff is collapsed. Click to expand it.
...@@ -41,6 +41,7 @@ class Results { ...@@ -41,6 +41,7 @@ class Results {
41 PlusCode? plusCode; 41 PlusCode? plusCode;
42 dynamic rating; 42 dynamic rating;
43 int? userRatingsTotal; 43 int? userRatingsTotal;
44 + bool isSelect = false;
44 45
45 Results( 46 Results(
46 {this.geometry, 47 {this.geometry,
...@@ -58,11 +59,11 @@ class Results { ...@@ -58,11 +59,11 @@ class Results {
58 this.openingHours, 59 this.openingHours,
59 this.plusCode, 60 this.plusCode,
60 this.rating, 61 this.rating,
61 - this.userRatingsTotal}); 62 + this.userRatingsTotal,
63 + this.isSelect = false});
62 64
63 Results.fromJson(Map<String, dynamic> json) { 65 Results.fromJson(Map<String, dynamic> json) {
64 - geometry = 66 + geometry = json['geometry'] != null ? Geometry.fromJson(json['geometry']) : null;
65 - json['geometry'] != null ? Geometry.fromJson(json['geometry']) : null;
66 icon = json['icon']; 67 icon = json['icon'];
67 iconBackgroundColor = json['icon_background_color']; 68 iconBackgroundColor = json['icon_background_color'];
68 iconMaskBaseUri = json['icon_mask_base_uri']; 69 iconMaskBaseUri = json['icon_mask_base_uri'];
...@@ -79,11 +80,8 @@ class Results { ...@@ -79,11 +80,8 @@ class Results {
79 types = json['types'].cast<String>(); 80 types = json['types'].cast<String>();
80 vicinity = json['vicinity']; 81 vicinity = json['vicinity'];
81 businessStatus = json['business_status']; 82 businessStatus = json['business_status'];
82 - openingHours = json['opening_hours'] != null 83 + openingHours = json['opening_hours'] != null ? OpeningHours.fromJson(json['opening_hours']) : null;
83 - ? OpeningHours.fromJson(json['opening_hours']) 84 + plusCode = json['plus_code'] != null ? PlusCode.fromJson(json['plus_code']) : null;
84 - : null;
85 - plusCode =
86 - json['plus_code'] != null ? PlusCode.fromJson(json['plus_code']) : null;
87 rating = json['rating']; 85 rating = json['rating'];
88 userRatingsTotal = json['user_ratings_total']; 86 userRatingsTotal = json['user_ratings_total'];
89 } 87 }
...@@ -125,10 +123,8 @@ class Geometry { ...@@ -125,10 +123,8 @@ class Geometry {
125 Geometry({this.location, this.viewport}); 123 Geometry({this.location, this.viewport});
126 124
127 Geometry.fromJson(Map<String, dynamic> json) { 125 Geometry.fromJson(Map<String, dynamic> json) {
128 - location = 126 + location = json['location'] != null ? Location.fromJson(json['location']) : null;
129 - json['location'] != null ? Location.fromJson(json['location']) : null; 127 + viewport = json['viewport'] != null ? Viewport.fromJson(json['viewport']) : null;
130 - viewport =
131 - json['viewport'] != null ? Viewport.fromJson(json['viewport']) : null;
132 } 128 }
133 129
134 Map<String, dynamic> toJson() { 130 Map<String, dynamic> toJson() {
...@@ -169,10 +165,8 @@ class Viewport { ...@@ -169,10 +165,8 @@ class Viewport {
169 Viewport({this.northeast, this.southwest}); 165 Viewport({this.northeast, this.southwest});
170 166
171 Viewport.fromJson(Map<String, dynamic> json) { 167 Viewport.fromJson(Map<String, dynamic> json) {
172 - northeast = 168 + northeast = json['northeast'] != null ? Location.fromJson(json['northeast']) : null;
173 - json['northeast'] != null ? Location.fromJson(json['northeast']) : null; 169 + southwest = json['southwest'] != null ? Location.fromJson(json['southwest']) : null;
174 - southwest =
175 - json['southwest'] != null ? Location.fromJson(json['southwest']) : null;
176 } 170 }
177 171
178 Map<String, dynamic> toJson() { 172 Map<String, dynamic> toJson() {
......
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 +
8 +class PaymentSdk {
9 + PaymentSdk._privateConstructor();
10 +
11 + static final PaymentSdk _instance = PaymentSdk._privateConstructor();
12 +
13 + static PaymentSdk get instance {
14 + return _instance;
15 + }
16 +
17 + static const Set<String> _kIds = <String>{'yearly_yiyan_vip', 'monthly_yiyan_vip'};
18 +
19 + StreamSubscription<List<PurchaseDetails>>? _subscription;
20 + List<ProductDetails> products = [];
21 + Function? onPaySuccess;
22 + Function? onPending;
23 + Function? onFailed;
24 + Function? onCancel;
25 +
26 + initState({
27 + Function? onPaySuccess,
28 + Function? onPending,
29 + Function? onFailed,
30 + Function? onCancel,
31 + }) {
32 + this.onPaySuccess = onPaySuccess;
33 + this.onPending = onPending;
34 + this.onFailed = onFailed;
35 + this.onCancel = onCancel;
36 + final Stream<List<PurchaseDetails>> purchaseUpdated = InAppPurchase.instance.purchaseStream;
37 + _subscription = purchaseUpdated.listen((purchaseDetailsList) {
38 + _listenToPurchaseUpdated(purchaseDetailsList);
39 + }, onDone: () {
40 + _subscription?.cancel();
41 + }, onError: (error) {
42 + // handle error here.
43 + });
44 + }
45 +
46 + Future<List<ProductDetails>> queryProducts() async {
47 + final bool available = await InAppPurchase.instance.isAvailable();
48 + if (!available) {
49 + return [];
50 + }
51 + final ProductDetailsResponse response = await InAppPurchase.instance.queryProductDetails(_kIds);
52 + return products = response.productDetails;
53 + }
54 +
55 + buy(ProductDetails details, MembershipDataGoodsList e) {
56 + OrderApi.request.createOrder(e.id.toString()).then((value) {
57 + var orderId = value?['data']?['data']?['order_sn'];
58 + if (TextUtil.isEmpty(orderId)) {
59 + onFailed?.call();
60 + return;
61 + }
62 + final PurchaseParam purchaseParam = PurchaseParam(productDetails: details, applicationUserName: orderId);
63 + if (_isConsumable(details)) {
64 + InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam);
65 + } else {
66 + InAppPurchase.instance.buyNonConsumable(purchaseParam: purchaseParam);
67 + }
68 + });
69 + }
70 +
71 + void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async {
72 + for (var purchaseDetails in purchaseDetailsList) {
73 + if (purchaseDetails.status == PurchaseStatus.pending) {
74 + onPending?.call();
75 + } else {
76 + if (purchaseDetails.status == PurchaseStatus.error) {
77 + _handleError(purchaseDetails.error!);
78 + } else if (purchaseDetails.status == PurchaseStatus.purchased || purchaseDetails.status == PurchaseStatus.restored) {
79 + bool valid = await _verifyPurchase(purchaseDetails);
80 + if (valid) {
81 + _deliverProduct(purchaseDetails);
82 + } else {
83 + _handleInvalidPurchase(purchaseDetails);
84 + }
85 + } else {
86 + onCancel?.call();
87 + }
88 + if (purchaseDetails.pendingCompletePurchase) {
89 + await InAppPurchase.instance.completePurchase(purchaseDetails);
90 + }
91 + }
92 + }
93 + }
94 +
95 + _verifyPurchase(PurchaseDetails purchaseDetails) async {
96 + return true;
97 + }
98 +
99 + void _deliverProduct(PurchaseDetails purchaseDetails) {
100 + onPaySuccess?.call();
101 + }
102 +
103 + void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
104 + onFailed?.call();
105 + }
106 +
107 + void _handleError(IAPError iapError) {
108 + onFailed?.call();
109 + }
110 +
111 + bool _isConsumable(ProductDetails details) {
112 + return true;
113 + }
114 +
115 + void restore() {
116 + InAppPurchase.instance.restorePurchases();
117 + }
118 +
119 + void dispose() {
120 + onPaySuccess = null;
121 + onPending = null;
122 + onFailed = null;
123 + onCancel = null;
124 + _subscription?.cancel();
125 + }
126 +}
...@@ -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 'dart:async'; 1 import 'dart:async';
2 import 'dart:convert'; 2 import 'dart:convert';
3 +import 'package:Parlando/extension/widget_ext.dart';
3 import 'package:Parlando/models/nearby_response.dart' as nearby; 4 import 'package:Parlando/models/nearby_response.dart' as nearby;
4 import 'package:Parlando/routers/fluro_navigator.dart'; 5 import 'package:Parlando/routers/fluro_navigator.dart';
6 +import 'package:Parlando/util/log_utils.dart';
5 import 'package:Parlando/util/toast_utils.dart'; 7 import 'package:Parlando/util/toast_utils.dart';
6 import 'package:flutter/material.dart'; 8 import 'package:flutter/material.dart';
7 import 'package:Parlando/widgets/my_button.dart'; 9 import 'package:Parlando/widgets/my_button.dart';
...@@ -19,26 +21,17 @@ class AddressSelectPage extends StatefulWidget { ...@@ -19,26 +21,17 @@ class AddressSelectPage extends StatefulWidget {
19 } 21 }
20 22
21 class AddressSelectPageState extends State<AddressSelectPage> { 23 class AddressSelectPageState extends State<AddressSelectPage> {
22 - List<nearby.Results> _list = []; 24 + List<nearby.Results> _nearByList = [];
23 - int _index = 0;
24 final ScrollController _controller = ScrollController(); 25 final ScrollController _controller = ScrollController();
25 - LatLng _center = const LatLng(45.521563, -122.677433); 26 + LatLng? _center;
26 late GoogleMapController mapController; 27 late GoogleMapController mapController;
27 - bool isLoading = false; 28 + bool isLoading = true;
28 - int _markerIdCounter = 1;
29 Map<MarkerId, Marker> markers = <MarkerId, Marker>{}; 29 Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
30 late StreamSubscription _locationSubscription; 30 late StreamSubscription _locationSubscription;
31 - String radius = "1000"; 31 + String radiusMax = "1000";
32 String apiKey = "AIzaSyDQZsMULyO-UtiSht4_MFi1uHT4BIqasjw"; 32 String apiKey = "AIzaSyDQZsMULyO-UtiSht4_MFi1uHT4BIqasjw";
33 - nearby.NearbyPlacesResponse nearbyPlacesResponse = 33 + nearby.NearbyPlacesResponse nearbyPlacesResponse = nearby.NearbyPlacesResponse();
34 - nearby.NearbyPlacesResponse();
35 34
36 - @override
37 - void dispose() {
38 - _controller.dispose();
39 - _locationSubscription.cancel();
40 - super.dispose();
41 - }
42 35
43 @override 36 @override
44 void initState() { 37 void initState() {
...@@ -64,116 +57,168 @@ class AddressSelectPageState extends State<AddressSelectPage> { ...@@ -64,116 +57,168 @@ class AddressSelectPageState extends State<AddressSelectPage> {
64 return; 57 return;
65 } 58 }
66 } 59 }
67 - 60 + var currentLocation = await location.getLocation();
68 - _locationSubscription = 61 + _center = LatLng(currentLocation.latitude!, currentLocation.longitude!);
69 - location.onLocationChanged.listen((LocationData currentLocation) { 62 + getNearbyPlaces("");
70 - _center = LatLng(currentLocation.latitude!, currentLocation.longitude!); 63 + _goToCurrentCenter();
71 - });
72 } 64 }
73 65
74 void getNearbyPlaces(String keyword) async { 66 void getNearbyPlaces(String keyword) async {
75 - String uri = 67 + String host = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json';
76 - '${'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${_center.latitude},${_center.longitude}&radius=$radius'}&key=$apiKey&keyword=$keyword'; 68 + String location = 'location=${_center?.latitude},${_center?.longitude}';
69 + String radius = 'radius=$radiusMax';
70 + String types = 'type=point_of_interest';
71 + String uri = '${'$host?$location&$radius'}&key=$apiKey&keyword=$keyword&$types';
72 + print(uri);
77 var url = Uri.parse(uri); 73 var url = Uri.parse(uri);
78 var response = await http.post(url); 74 var response = await http.post(url);
79 - nearbyPlacesResponse = 75 + nearbyPlacesResponse = nearby.NearbyPlacesResponse.fromJson(jsonDecode(response.body));
80 - nearby.NearbyPlacesResponse.fromJson(jsonDecode(response.body)); 76 + _nearByList = nearbyPlacesResponse.results!;
81 - _list = nearbyPlacesResponse.results!; 77 + if (_nearByList.isNotEmpty) {
78 + selectItemLocation(_nearByList[0]);
79 + }
82 setState(() { 80 setState(() {
83 isLoading = false; 81 isLoading = false;
84 }); 82 });
83 + buildMarkers();
85 } 84 }
86 85
87 void _onMapCreated(GoogleMapController controller) { 86 void _onMapCreated(GoogleMapController controller) {
88 mapController = controller; 87 mapController = controller;
89 - final String markerIdVal = 'marker_id_$_markerIdCounter';
90 - _markerIdCounter++;
91 - final MarkerId markerId = MarkerId(markerIdVal);
92 - final Marker marker = Marker(
93 - markerId: markerId,
94 - position: _center,
95 - );
96 - mapController.moveCamera(CameraUpdate.newLatLng(_center));
97 - setState(() {
98 - markers[markerId] = marker;
99 - });
100 getNearbyPlaces(""); 88 getNearbyPlaces("");
101 } 89 }
102 90
91 + void _goToCurrentCenter() {
92 + if (_center != null) {
93 + mapController.moveCamera(CameraUpdate.newLatLng(_center!));
94 + }
95 + }
96 +
103 @override 97 @override
104 Widget build(BuildContext context) { 98 Widget build(BuildContext context) {
99 + var loaderView = const GFLoader().expanded(flex: 11);
100 + Widget realList = ListView.separated(
101 + controller: _controller,
102 + itemCount: _nearByList.length,
103 + separatorBuilder: (_, index) => const Divider(),
104 + itemBuilder: (_, index) {
105 + var item = _nearByList[index];
106 + return _AddressItem(
107 + isSelected: item.isSelect,
108 + data: item,
109 + onTap: () {
110 + selectItemLocation(item);
111 + },
112 + );
113 + },
114 + ).expanded(flex: 11);
115 + if (_nearByList.isEmpty) {
116 + realList = const Center(child: Text("没有找到任何地点")).expanded(flex: 11);
117 + }
118 + var listHolder = isLoading ? loaderView : realList;
119 +
120 + var searchBar = SearchBar(
121 + hintText: '搜索地址',
122 + onPressed: (text) async {
123 + isLoading = true;
124 + _controller.animateTo(0.0, duration: const Duration(milliseconds: 10), curve: Curves.ease);
125 + // 构造检索参数
126 + getNearbyPlaces(text);
127 + setState(() {
128 +
129 + });
130 + },
131 + );
132 + var map = GoogleMap(
133 + onMapCreated: _onMapCreated,
134 + initialCameraPosition: CameraPosition(target: _center ?? const LatLng(45.521563, -122.677433), zoom: 16.0),
135 + markers: Set<Marker>.of(markers.values),
136 + myLocationEnabled: true,
137 + myLocationButtonEnabled: true,
138 + ).expanded(flex: 9);
139 +
105 return Scaffold( 140 return Scaffold(
106 resizeToAvoidBottomInset: false, 141 resizeToAvoidBottomInset: false,
107 - appBar: SearchBar( 142 + appBar: searchBar,
108 - hintText: '搜索地址', 143 + body: Column(
109 - onPressed: (text) async { 144 + children: <Widget>[map, listHolder, initButton()],
110 - isLoading = true; 145 + ).safe(),
111 - _controller.animateTo(0.0,
112 - duration: const Duration(milliseconds: 10), curve: Curves.ease);
113 - _index = 0;
114 - // 构造检索参数
115 - getNearbyPlaces(text);
116 - },
117 - ),
118 - body: SafeArea(
119 - child: Column(
120 - children: <Widget>[
121 - Expanded(
122 - flex: 9,
123 - child: GoogleMap(
124 - onMapCreated: _onMapCreated,
125 - initialCameraPosition: CameraPosition(
126 - target: _center,
127 - zoom: 16.0,
128 - ),
129 - markers: Set<Marker>.of(markers.values),
130 - ),
131 - ),
132 - Expanded(
133 - flex: 11,
134 - child: isLoading
135 - ? const GFLoader()
136 - : ListView.separated(
137 - controller: _controller,
138 - itemCount: _list.length,
139 - separatorBuilder: (_, index) => const Divider(),
140 - itemBuilder: (_, index) {
141 - return _AddressItem(
142 - isSelected: _index == index,
143 - date: _list[index],
144 - onTap: () {
145 - _index = index;
146 - setState(() {});
147 - },
148 - );
149 - },
150 - ),
151 - ),
152 - MyButton(
153 - onPressed: () {
154 - if (_list.isEmpty) {
155 - Toast.show('未选择地址!');
156 - return;
157 - }
158 - NavigatorUtils.goBackWithParams(context, _list[_index]);
159 - },
160 - text: '确认选择地址',
161 - )
162 - ],
163 - ),
164 - ),
165 ); 146 );
166 } 147 }
148 +
149 + initButton() {
150 + return MyButton(
151 + onPressed: () {
152 + var selected = _nearByList.where((element) => element.isSelect);
153 + if (selected.isEmpty) {
154 + Toast.show('未选择地址!');
155 + return;
156 + }
157 +
158 + NavigatorUtils.goBackWithParams(context, selected.first);
159 + },
160 + text: '确认选择地址',
161 + );
162 + }
163 +
164 + void buildMarkers() {
165 + markers.clear();
166 + for (var value in _nearByList) {
167 + final MarkerId markerId = MarkerId(buildMarkerId(value));
168 + final Marker marker = Marker(
169 + icon: value.isSelect ? BitmapDescriptor.defaultMarker : BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue),
170 + markerId: markerId,
171 + position: buildMarkerLocation(value),
172 + );
173 + markers[markerId] = marker;
174 + }
175 + setState(() {});
176 + }
177 +
178 + String buildMarkerId(nearby.Results value) {
179 + var lat = value.geometry?.location?.lat;
180 + var lng = value.geometry?.location?.lng;
181 + return "$lat-$lng";
182 + }
183 +
184 + LatLng buildMarkerLocation(nearby.Results value) {
185 + var lat = value.geometry?.location?.lat;
186 + var lng = value.geometry?.location?.lng;
187 + return LatLng(lat ?? 0, lng ?? 0);
188 + }
189 +
190 + void selectItemLocation(nearby.Results item) {
191 + for (var element in _nearByList) {
192 + element.isSelect = false;
193 + }
194 + item.isSelect = true;
195 + var lat = item.geometry?.location?.lat;
196 + var lng = item.geometry?.location?.lng;
197 + if (lat != null && lng != null) {
198 + _center = LatLng(lat, lng);
199 + }
200 + _goToCurrentCenter();
201 + setState(() {});
202 + buildMarkers();
203 + }
204 +
205 + @override
206 + void dispose() {
207 + _controller.dispose();
208 + _locationSubscription.cancel();
209 + super.dispose();
210 + }
167 } 211 }
168 212
169 class _AddressItem extends StatelessWidget { 213 class _AddressItem extends StatelessWidget {
170 const _AddressItem({ 214 const _AddressItem({
171 Key? key, 215 Key? key,
172 - required this.date, 216 + required this.data,
173 this.isSelected = false, 217 this.isSelected = false,
174 this.onTap, 218 this.onTap,
175 }) : super(key: key); 219 }) : super(key: key);
176 - final nearby.Results date; 220 +
221 + final nearby.Results data;
177 final bool isSelected; 222 final bool isSelected;
178 final GestureTapCallback? onTap; 223 final GestureTapCallback? onTap;
179 224
...@@ -187,15 +232,8 @@ class _AddressItem extends StatelessWidget { ...@@ -187,15 +232,8 @@ class _AddressItem extends StatelessWidget {
187 height: 50.0, 232 height: 50.0,
188 child: Row( 233 child: Row(
189 children: <Widget>[ 234 children: <Widget>[
190 - Expanded( 235 + Text('${data.name}').expanded(),
191 - child: Text( 236 + Visibility(visible: isSelected, child: const Icon(Icons.done, color: Colors.blue))
192 - '${date.name} ${date.vicinity}',
193 - ),
194 - ),
195 - Visibility(
196 - visible: isSelected,
197 - child: const Icon(Icons.done, color: Colors.blue),
198 - )
199 ], 237 ],
200 ), 238 ),
201 ), 239 ),
......
...@@ -28,7 +28,7 @@ packages: ...@@ -28,7 +28,7 @@ packages:
28 name: archive 28 name: archive
29 url: "https://pub.flutter-io.cn" 29 url: "https://pub.flutter-io.cn"
30 source: hosted 30 source: hosted
31 - version: "3.3.0" 31 + version: "3.1.11"
32 args: 32 args:
33 dependency: transitive 33 dependency: transitive
34 description: 34 description:
...@@ -42,7 +42,7 @@ packages: ...@@ -42,7 +42,7 @@ packages:
42 name: async 42 name: async
43 url: "https://pub.flutter-io.cn" 43 url: "https://pub.flutter-io.cn"
44 source: hosted 44 source: hosted
45 - version: "2.9.0" 45 + version: "2.8.2"
46 boolean_selector: 46 boolean_selector:
47 dependency: transitive 47 dependency: transitive
48 description: 48 description:
...@@ -112,21 +112,21 @@ packages: ...@@ -112,21 +112,21 @@ packages:
112 name: cached_network_image 112 name: cached_network_image
113 url: "https://pub.flutter-io.cn" 113 url: "https://pub.flutter-io.cn"
114 source: hosted 114 source: hosted
115 - version: "3.2.2" 115 + version: "3.2.1"
116 cached_network_image_platform_interface: 116 cached_network_image_platform_interface:
117 dependency: transitive 117 dependency: transitive
118 description: 118 description:
119 name: cached_network_image_platform_interface 119 name: cached_network_image_platform_interface
120 url: "https://pub.flutter-io.cn" 120 url: "https://pub.flutter-io.cn"
121 source: hosted 121 source: hosted
122 - version: "2.0.0" 122 + version: "1.0.0"
123 cached_network_image_web: 123 cached_network_image_web:
124 dependency: transitive 124 dependency: transitive
125 description: 125 description:
126 name: cached_network_image_web 126 name: cached_network_image_web
127 url: "https://pub.flutter-io.cn" 127 url: "https://pub.flutter-io.cn"
128 source: hosted 128 source: hosted
129 - version: "1.0.2" 129 + version: "1.0.1"
130 camera: 130 camera:
131 dependency: "direct main" 131 dependency: "direct main"
132 description: 132 description:
...@@ -168,7 +168,14 @@ packages: ...@@ -168,7 +168,14 @@ packages:
168 name: characters 168 name: characters
169 url: "https://pub.flutter-io.cn" 169 url: "https://pub.flutter-io.cn"
170 source: hosted 170 source: hosted
171 - version: "1.2.1" 171 + version: "1.2.0"
172 + charcode:
173 + dependency: transitive
174 + description:
175 + name: charcode
176 + url: "https://pub.flutter-io.cn"
177 + source: hosted
178 + version: "1.3.1"
172 checked_yaml: 179 checked_yaml:
173 dependency: transitive 180 dependency: transitive
174 description: 181 description:
...@@ -189,7 +196,7 @@ packages: ...@@ -189,7 +196,7 @@ packages:
189 name: clock 196 name: clock
190 url: "https://pub.flutter-io.cn" 197 url: "https://pub.flutter-io.cn"
191 source: hosted 198 source: hosted
192 - version: "1.1.1" 199 + version: "1.1.0"
193 code_builder: 200 code_builder:
194 dependency: transitive 201 dependency: transitive
195 description: 202 description:
...@@ -224,7 +231,7 @@ packages: ...@@ -224,7 +231,7 @@ packages:
224 name: coverage 231 name: coverage
225 url: "https://pub.flutter-io.cn" 232 url: "https://pub.flutter-io.cn"
226 source: hosted 233 source: hosted
227 - version: "1.5.0" 234 + version: "1.2.0"
228 cross_file: 235 cross_file:
229 dependency: transitive 236 dependency: transitive
230 description: 237 description:
...@@ -238,7 +245,7 @@ packages: ...@@ -238,7 +245,7 @@ packages:
238 name: crypto 245 name: crypto
239 url: "https://pub.flutter-io.cn" 246 url: "https://pub.flutter-io.cn"
240 source: hosted 247 source: hosted
241 - version: "3.0.2" 248 + version: "3.0.1"
242 csslib: 249 csslib:
243 dependency: transitive 250 dependency: transitive
244 description: 251 description:
...@@ -336,7 +343,7 @@ packages: ...@@ -336,7 +343,7 @@ packages:
336 name: fake_async 343 name: fake_async
337 url: "https://pub.flutter-io.cn" 344 url: "https://pub.flutter-io.cn"
338 source: hosted 345 source: hosted
339 - version: "1.3.1" 346 + version: "1.3.0"
340 ffi: 347 ffi:
341 dependency: transitive 348 dependency: transitive
342 description: 349 description:
...@@ -410,6 +417,13 @@ packages: ...@@ -410,6 +417,13 @@ packages:
410 url: "https://pub.flutter-io.cn" 417 url: "https://pub.flutter-io.cn"
411 source: hosted 418 source: hosted
412 version: "1.1.2" 419 version: "1.1.2"
420 + flutter_easyloading:
421 + dependency: "direct main"
422 + description:
423 + name: flutter_easyloading
424 + url: "https://pub.flutter-io.cn"
425 + source: hosted
426 + version: "3.0.5"
413 flutter_facebook_auth: 427 flutter_facebook_auth:
414 dependency: "direct main" 428 dependency: "direct main"
415 description: 429 description:
...@@ -463,7 +477,7 @@ packages: ...@@ -463,7 +477,7 @@ packages:
463 name: flutter_native_splash 477 name: flutter_native_splash
464 url: "https://pub.flutter-io.cn" 478 url: "https://pub.flutter-io.cn"
465 source: hosted 479 source: hosted
466 - version: "2.2.10+1" 480 + version: "2.2.9"
467 flutter_plugin_android_lifecycle: 481 flutter_plugin_android_lifecycle:
468 dependency: transitive 482 dependency: transitive
469 description: 483 description:
...@@ -703,6 +717,34 @@ packages: ...@@ -703,6 +717,34 @@ packages:
703 url: "https://pub.flutter-io.cn" 717 url: "https://pub.flutter-io.cn"
704 source: hosted 718 source: hosted
705 version: "2.6.2" 719 version: "2.6.2"
720 + in_app_purchase:
721 + dependency: "direct main"
722 + description:
723 + name: in_app_purchase
724 + url: "https://pub.flutter-io.cn"
725 + source: hosted
726 + version: "3.0.8"
727 + in_app_purchase_android:
728 + dependency: transitive
729 + description:
730 + name: in_app_purchase_android
731 + url: "https://pub.flutter-io.cn"
732 + source: hosted
733 + version: "0.2.3+6"
734 + in_app_purchase_platform_interface:
735 + dependency: transitive
736 + description:
737 + name: in_app_purchase_platform_interface
738 + url: "https://pub.flutter-io.cn"
739 + source: hosted
740 + version: "1.3.2"
741 + in_app_purchase_storekit:
742 + dependency: transitive
743 + description:
744 + name: in_app_purchase_storekit
745 + url: "https://pub.flutter-io.cn"
746 + source: hosted
747 + version: "0.3.3"
706 integration_test: 748 integration_test:
707 dependency: "direct dev" 749 dependency: "direct dev"
708 description: flutter 750 description: flutter
...@@ -757,6 +799,13 @@ packages: ...@@ -757,6 +799,13 @@ packages:
757 url: "https://pub.flutter-io.cn" 799 url: "https://pub.flutter-io.cn"
758 source: hosted 800 source: hosted
759 version: "4.1.0" 801 version: "4.1.0"
802 + lint:
803 + dependency: transitive
804 + description:
805 + name: lint
806 + url: "https://pub.flutter-io.cn"
807 + source: hosted
808 + version: "1.10.0"
760 lints: 809 lints:
761 dependency: transitive 810 dependency: transitive
762 description: 811 description:
...@@ -805,21 +854,21 @@ packages: ...@@ -805,21 +854,21 @@ packages:
805 name: matcher 854 name: matcher
806 url: "https://pub.flutter-io.cn" 855 url: "https://pub.flutter-io.cn"
807 source: hosted 856 source: hosted
808 - version: "0.12.12" 857 + version: "0.12.11"
809 material_color_utilities: 858 material_color_utilities:
810 dependency: transitive 859 dependency: transitive
811 description: 860 description:
812 name: material_color_utilities 861 name: material_color_utilities
813 url: "https://pub.flutter-io.cn" 862 url: "https://pub.flutter-io.cn"
814 source: hosted 863 source: hosted
815 - version: "0.1.5" 864 + version: "0.1.4"
816 meta: 865 meta:
817 dependency: transitive 866 dependency: transitive
818 description: 867 description:
819 name: meta 868 name: meta
820 url: "https://pub.flutter-io.cn" 869 url: "https://pub.flutter-io.cn"
821 source: hosted 870 source: hosted
822 - version: "1.8.0" 871 + version: "1.7.0"
823 mime: 872 mime:
824 dependency: transitive 873 dependency: transitive
825 description: 874 description:
...@@ -868,7 +917,7 @@ packages: ...@@ -868,7 +917,7 @@ packages:
868 name: path 917 name: path
869 url: "https://pub.flutter-io.cn" 918 url: "https://pub.flutter-io.cn"
870 source: hosted 919 source: hosted
871 - version: "1.8.2" 920 + version: "1.8.1"
872 path_provider: 921 path_provider:
873 dependency: "direct main" 922 dependency: "direct main"
874 description: 923 description:
...@@ -1272,7 +1321,7 @@ packages: ...@@ -1272,7 +1321,7 @@ packages:
1272 name: source_span 1321 name: source_span
1273 url: "https://pub.flutter-io.cn" 1322 url: "https://pub.flutter-io.cn"
1274 source: hosted 1323 source: hosted
1275 - version: "1.9.0" 1324 + version: "1.8.2"
1276 sp_util: 1325 sp_util:
1277 dependency: transitive 1326 dependency: transitive
1278 description: 1327 description:
...@@ -1293,7 +1342,7 @@ packages: ...@@ -1293,7 +1342,7 @@ packages:
1293 name: sqflite 1342 name: sqflite
1294 url: "https://pub.flutter-io.cn" 1343 url: "https://pub.flutter-io.cn"
1295 source: hosted 1344 source: hosted
1296 - version: "2.1.0+1" 1345 + version: "2.0.3+1"
1297 sqflite_common: 1346 sqflite_common:
1298 dependency: transitive 1347 dependency: transitive
1299 description: 1348 description:
...@@ -1335,14 +1384,14 @@ packages: ...@@ -1335,14 +1384,14 @@ packages:
1335 name: string_scanner 1384 name: string_scanner
1336 url: "https://pub.flutter-io.cn" 1385 url: "https://pub.flutter-io.cn"
1337 source: hosted 1386 source: hosted
1338 - version: "1.1.1" 1387 + version: "1.1.0"
1339 sync_http: 1388 sync_http:
1340 dependency: transitive 1389 dependency: transitive
1341 description: 1390 description:
1342 name: sync_http 1391 name: sync_http
1343 url: "https://pub.flutter-io.cn" 1392 url: "https://pub.flutter-io.cn"
1344 source: hosted 1393 source: hosted
1345 - version: "0.3.1" 1394 + version: "0.3.0"
1346 synchronized: 1395 synchronized:
1347 dependency: transitive 1396 dependency: transitive
1348 description: 1397 description:
...@@ -1363,28 +1412,28 @@ packages: ...@@ -1363,28 +1412,28 @@ packages:
1363 name: term_glyph 1412 name: term_glyph
1364 url: "https://pub.flutter-io.cn" 1413 url: "https://pub.flutter-io.cn"
1365 source: hosted 1414 source: hosted
1366 - version: "1.2.1" 1415 + version: "1.2.0"
1367 test: 1416 test:
1368 dependency: "direct dev" 1417 dependency: "direct dev"
1369 description: 1418 description:
1370 name: test 1419 name: test
1371 url: "https://pub.flutter-io.cn" 1420 url: "https://pub.flutter-io.cn"
1372 source: hosted 1421 source: hosted
1373 - version: "1.21.4" 1422 + version: "1.21.1"
1374 test_api: 1423 test_api:
1375 dependency: transitive 1424 dependency: transitive
1376 description: 1425 description:
1377 name: test_api 1426 name: test_api
1378 url: "https://pub.flutter-io.cn" 1427 url: "https://pub.flutter-io.cn"
1379 source: hosted 1428 source: hosted
1380 - version: "0.4.12" 1429 + version: "0.4.9"
1381 test_core: 1430 test_core:
1382 dependency: transitive 1431 dependency: transitive
1383 description: 1432 description:
1384 name: test_core 1433 name: test_core
1385 url: "https://pub.flutter-io.cn" 1434 url: "https://pub.flutter-io.cn"
1386 source: hosted 1435 source: hosted
1387 - version: "0.4.16" 1436 + version: "0.4.13"
1388 timing: 1437 timing:
1389 dependency: transitive 1438 dependency: transitive
1390 description: 1439 description:
...@@ -1405,7 +1454,7 @@ packages: ...@@ -1405,7 +1454,7 @@ packages:
1405 name: typed_data 1454 name: typed_data
1406 url: "https://pub.flutter-io.cn" 1455 url: "https://pub.flutter-io.cn"
1407 source: hosted 1456 source: hosted
1408 - version: "1.3.1" 1457 + version: "1.3.0"
1409 universal_io: 1458 universal_io:
1410 dependency: transitive 1459 dependency: transitive
1411 description: 1460 description:
...@@ -1538,7 +1587,7 @@ packages: ...@@ -1538,7 +1587,7 @@ packages:
1538 name: vm_service 1587 name: vm_service
1539 url: "https://pub.flutter-io.cn" 1588 url: "https://pub.flutter-io.cn"
1540 source: hosted 1589 source: hosted
1541 - version: "9.0.0" 1590 + version: "8.2.2"
1542 wakelock: 1591 wakelock:
1543 dependency: "direct main" 1592 dependency: "direct main"
1544 description: 1593 description:
...@@ -1659,5 +1708,5 @@ packages: ...@@ -1659,5 +1708,5 @@ packages:
1659 source: hosted 1708 source: hosted
1660 version: "3.1.1" 1709 version: "3.1.1"
1661 sdks: 1710 sdks:
1662 - dart: ">=2.18.0 <3.0.0" 1711 + dart: ">=2.17.0 <3.0.0"
1663 - flutter: ">=3.3.0" 1712 + flutter: ">=3.0.0"
......
...@@ -101,6 +101,8 @@ dependencies: ...@@ -101,6 +101,8 @@ 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
...@@ -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,8 @@ dependencies: ...@@ -125,7 +130,8 @@ 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
129 http: ^0.13.5 135 http: ^0.13.5
130 136
131 dependency_overrides: 137 dependency_overrides:
......