From 99db12a2c5552bf2baeaab120c49c0b490dc2aba Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 7 Mar 2024 18:03:28 +0800 Subject: [PATCH 01/36] =?UTF-8?q?=E5=AF=B9=E6=8E=A5=20Stripe=20=E6=94=AF?= =?UTF-8?q?=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/proguard-rules.pro | 5 ++ .../flutter/askaide/askaide/MainActivity.kt | 6 +- .../app/src/main/res/values-night/styles.xml | 4 +- android/app/src/main/res/values/styles.xml | 4 +- lib/bloc/payment_bloc.dart | 5 +- lib/bloc/payment_state.dart | 2 + lib/helper/ability.dart | 9 ++- lib/main.dart | 1 + lib/page/balance/payment.dart | 76 +++++++++++++++++-- lib/page/balance/price_block.dart | 32 ++------ lib/repo/api/info.dart | 6 ++ lib/repo/api/payment.dart | 46 ++++++++++- lib/repo/api_server.dart | 17 +++++ pubspec.lock | 40 ++++++++++ pubspec.yaml | 1 + 15 files changed, 213 insertions(+), 41 deletions(-) create mode 100644 android/app/proguard-rules.pro diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 00000000..e6d1506c --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,5 @@ +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivity$g +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Args +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Error +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter +-dontwarn com.stripe.android.pushProvisioning.PushProvisioningEphemeralKeyProvider \ No newline at end of file diff --git a/android/app/src/main/kotlin/cc/aicode/flutter/askaide/askaide/MainActivity.kt b/android/app/src/main/kotlin/cc/aicode/flutter/askaide/askaide/MainActivity.kt index 899a2546..6b1dc702 100644 --- a/android/app/src/main/kotlin/cc/aicode/flutter/askaide/askaide/MainActivity.kt +++ b/android/app/src/main/kotlin/cc/aicode/flutter/askaide/askaide/MainActivity.kt @@ -1,7 +1,7 @@ package cc.aicode.flutter.askaide.askaide import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.android.FlutterFragmentActivity -class MainActivity: FlutterActivity() { - -} +class MainActivity: FlutterFragmentActivity() { +} \ No newline at end of file diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 06952be7..861f0e61 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -1,7 +1,7 @@ - diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 0d1fa8fc..f6888299 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ - diff --git a/lib/bloc/payment_bloc.dart b/lib/bloc/payment_bloc.dart index a8c96e5d..b33529ae 100644 --- a/lib/bloc/payment_bloc.dart +++ b/lib/bloc/payment_bloc.dart @@ -89,7 +89,9 @@ class PaymentBloc extends Bloc { id: e.id, title: e.name, description: '', - price: e.retailPriceText, + price: products.preferUSD + ? e.retailPriceUSDText + : e.retailPriceText, rawPrice: e.retailPrice.toDouble(), currencyCode: '', ), @@ -98,6 +100,7 @@ class PaymentBloc extends Bloc { note: products.note, localProducts: products.consume, loading: false, + preferUSD: products.preferUSD, ), ); } diff --git a/lib/bloc/payment_state.dart b/lib/bloc/payment_state.dart index 6d250aa1..52aa0d66 100644 --- a/lib/bloc/payment_state.dart +++ b/lib/bloc/payment_state.dart @@ -11,6 +11,7 @@ class PaymentAppleProductsLoaded extends PaymentState { final Object? error; final bool loading; final String? note; + final bool preferUSD; PaymentAppleProductsLoaded( this.products, { @@ -18,5 +19,6 @@ class PaymentAppleProductsLoaded extends PaymentState { required this.localProducts, this.error, required this.loading, + this.preferUSD = false, }); } diff --git a/lib/helper/ability.dart b/lib/helper/ability.dart index 84d39ba7..7d0fd61b 100644 --- a/lib/helper/ability.dart +++ b/lib/helper/ability.dart @@ -92,6 +92,11 @@ class Ability { return capabilities.otherPayEnabled; } + /// 是否支持 Stripe 支付 + bool get enableStripe { + return capabilities.stripeEnabled; + } + /// 是否支持 ApplePay bool get enableApplePay { return capabilities.applePayEnabled; @@ -113,7 +118,7 @@ class Ability { /// 是否支持支付功能 bool get enablePayment { - if (!enableApplePay && !enableOtherPay) { + if (!enableApplePay && !enableOtherPay && !enableStripe) { return false; } @@ -121,7 +126,7 @@ class Ability { return true; } - return enableOtherPay; + return true; } /// 是否用户已经登陆 diff --git a/lib/main.dart b/lib/main.dart index 5fb08e00..fc831b2f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:askaide/helper/path.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; +import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:path/path.dart'; import 'package:askaide/bloc/account_bloc.dart'; diff --git a/lib/page/balance/payment.dart b/lib/page/balance/payment.dart index 48dcac6d..6a6cf3fd 100644 --- a/lib/page/balance/payment.dart +++ b/lib/page/balance/payment.dart @@ -21,6 +21,7 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:go_router/go_router.dart'; import 'package:in_app_purchase/in_app_purchase.dart'; import 'package:quickalert/models/quickalert_type.dart'; @@ -312,20 +313,45 @@ class _PaymentScreenState extends State { return; } - if (PlatformTool.isIOS() || - PlatformTool.isAndroid() || + if (PlatformTool.isAndroid()) { + openListSelectDialog( + context, + [ + if (Ability().enableOtherPay) + SelectorItem(const Text('支付宝'), 'alipay'), + if (Ability().enableStripe) + SelectorItem(const Text('Stripe'), 'stripe'), + ], + (value) { + _startPaymentLoading(); + + if (value.value == 'alipay') { + createAppAlipay() + .onError((error, stackTrace) { + _closePaymentLoading(); + showErrorMessageEnhanced(context, error!); + }); + } else { + createStripePayment(); + } + + return true; + }, + title: '请选择支付方式', + heightFactor: 0.3, + ); + } else if (PlatformTool.isIOS() || PlatformTool.isMacOS()) { _startPaymentLoading(); try { - if (PlatformTool.isAndroid()) { - await createAppAlipay(); - } else if (PlatformTool.isIOS()) { + if (PlatformTool.isIOS()) { await createAppApplePay(); } else { await createWebOrWapAlipay(source: 'web'); } } catch (e) { _closePaymentLoading(); + // ignore: use_build_context_synchronously showErrorMessage(resolveError(context, e)); } } else { @@ -463,6 +489,46 @@ class _PaymentScreenState extends State { }); } + /// 创建 Stripe 支付 + Future createStripePayment() async { + try { + final created = await APIServer().createStripePaymentSheet( + productId: selectedProduct!.id, + ); + paymentId = created.paymentId; + + Stripe.publishableKey = created.publishableKey; + + // 调起 Stripe 支付 + await Stripe.instance.initPaymentSheet( + paymentSheetParameters: SetupPaymentSheetParameters( + paymentIntentClientSecret: created.paymentIntent, + merchantDisplayName: 'AIdea', + customerId: created.customer, + customerEphemeralKeySecret: created.ephemeralKey, + returnURL: 'flutterstripe://redirect', + // ignore: use_build_context_synchronously + style: MediaQuery.platformBrightnessOf(context) == Brightness.dark + ? ThemeMode.dark + : ThemeMode.light, + ), + ); + + // 确认支付 + await Stripe.instance.presentPaymentSheet(); + showSuccessMessage('购买成功'); + } on Exception catch (e) { + if (e is StripeException) { + showErrorMessage('支付失败:${e.error.localizedMessage}'); + } else { + // ignore: use_build_context_synchronously + showErrorMessageEnhanced(context, e); + } + } finally { + _closePaymentLoading(); + } + } + /// 创建其它付款(App) Future createAppAlipay() async { // 其它支付 diff --git a/lib/page/balance/price_block.dart b/lib/page/balance/price_block.dart index 3591414c..fefe4f03 100644 --- a/lib/page/balance/price_block.dart +++ b/lib/page/balance/price_block.dart @@ -72,31 +72,13 @@ class PriceBlock extends StatelessWidget { const SizedBox(height: 10), loading ? const Text('加载中...') - : Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - if (detail.price != product.retailPriceText) - Text( - product.retailPriceText, - style: TextStyle( - fontSize: 13, - decoration: TextDecoration.lineThrough, - color: customColors.paymentItemDescriptionColor - ?.withAlpha(200), - ), - ), - if (detail.price != product.retailPriceText) - const SizedBox(width: 10), - Text( - detail.price, - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: customColors.linkColor, - ), - ), - ], + : Text( + detail.price, + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: customColors.linkColor, + ), ), ], ), diff --git a/lib/repo/api/info.dart b/lib/repo/api/info.dart index 6df73717..d3abf0d7 100644 --- a/lib/repo/api/info.dart +++ b/lib/repo/api/info.dart @@ -5,6 +5,9 @@ class Capabilities { /// 是否支持 Apple Pay final bool applePayEnabled; + /// 是否支持 Stripe + final bool stripeEnabled; + /// 是否支持微信登录 final bool wechatSigninEnabled; @@ -67,12 +70,14 @@ class Capabilities { this.disableChat = false, this.serviceStatusPage = '', this.wechatSigninEnabled = false, + this.stripeEnabled = false, }); factory Capabilities.fromJson(Map json) { return Capabilities( wechatSigninEnabled: json['wechat_signin_enabled'] ?? false, applePayEnabled: json['apple_pay_enabled'] ?? false, + stripeEnabled: json['stripe_enabled'] ?? false, otherPayEnabled: json['other_pay_enabled'] ?? false, translateEnabled: json['translate_enabled'] ?? false, mailEnabled: json['mail_enabled'] ?? false, @@ -96,6 +101,7 @@ class Capabilities { return { 'wechat_signin_enabled': wechatSigninEnabled, 'apple_pay_enabled': applePayEnabled, + 'stripe_enabled': stripeEnabled, 'other_pay_enabled': otherPayEnabled, 'translate_enabled': translateEnabled, 'mail_enabled': mailEnabled, diff --git a/lib/repo/api/payment.dart b/lib/repo/api/payment.dart index 3dc98338..0179ca64 100644 --- a/lib/repo/api/payment.dart +++ b/lib/repo/api/payment.dart @@ -25,6 +25,7 @@ class PaymentProduct { String name; int quota; int retailPrice; + int retailPriceUSD; String expirePolicy; String expirePolicyText; bool recommend; @@ -39,15 +40,20 @@ class PaymentProduct { required this.expirePolicyText, this.recommend = false, this.description, + this.retailPriceUSD = 0, }); String get retailPriceText => '¥${(retailPrice / 100).toStringAsFixed(0)}'; + String get retailPriceUSDText => + '\$${(retailPriceUSD / 100).toStringAsFixed(2)}'; + toJson() => { 'id': id, 'name': name, 'quota': quota, 'retail_price': retailPrice, + 'retail_price_usd': retailPriceUSD, 'expire_policy': expirePolicy, 'expire_policy_text': expirePolicyText, 'recommend': recommend, @@ -60,6 +66,7 @@ class PaymentProduct { name: json['name'], quota: json['quota'], retailPrice: json['retail_price'], + retailPriceUSD: json['retail_price_usd'] ?? 0, expirePolicy: json['expire_policy'], expirePolicyText: json['expire_policy_text'], recommend: json['recommend'] ?? false, @@ -71,12 +78,14 @@ class PaymentProduct { class PaymentProducts { final List consume; final String? note; + final bool preferUSD; - PaymentProducts(this.consume, {this.note}); + PaymentProducts(this.consume, {this.note, this.preferUSD = false}); toJson() => { 'consume': consume, 'note': note, + 'prefer_usd': preferUSD, }; static PaymentProducts fromJson(Map json) { @@ -85,6 +94,7 @@ class PaymentProducts { .map((e) => PaymentProduct.fromJson(e)) .toList(), note: json['note'], + preferUSD: json['prefer_usd'] ?? false, ); } } @@ -107,3 +117,37 @@ class PaymentStatus { ); } } + +class StripePaymentCreatedResponse { + final String paymentId; + final String customer; + final String paymentIntent; + final String ephemeralKey; + final String publishableKey; + + StripePaymentCreatedResponse( + this.paymentId, + this.customer, + this.paymentIntent, + this.ephemeralKey, + this.publishableKey, + ); + + toJson() => { + 'payment_id': paymentId, + 'customer': customer, + 'payment_intent': paymentIntent, + 'ephemeral_key': ephemeralKey, + 'publishable_key': publishableKey, + }; + + static StripePaymentCreatedResponse fromJson(Map json) { + return StripePaymentCreatedResponse( + json['payment_id'], + json['customer'], + json['payment_intent'], + json['ephemeral_key'], + json['publishable_key'], + ); + } +} diff --git a/lib/repo/api_server.dart b/lib/repo/api_server.dart index fe53b0a1..e217bca9 100644 --- a/lib/repo/api_server.dart +++ b/lib/repo/api_server.dart @@ -1968,4 +1968,21 @@ class APIServer { forceRefresh: !cache, ); } + + /// 发起 Stripe 支付 + Future createStripePaymentSheet({ + required String productId, + String? source, + }) async { + return sendPostRequest( + '/v1/payment/stripe/payment-sheet', + (resp) { + return StripePaymentCreatedResponse.fromJson(resp.data); + }, + formData: { + 'product_id': productId, + 'source': source, + }, + ); + } } diff --git a/pubspec.lock b/pubspec.lock index 0a16120e..6e89336f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -703,6 +703,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.5" + flutter_stripe: + dependency: "direct main" + description: + name: flutter_stripe + sha256: dfa4f0cf2f64cf82fde57357283819688c3b985c6cd10c26f50dd4a5476e4924 + url: "https://pub.dev" + source: hosted + version: "10.1.0" flutter_svg: dependency: transitive description: @@ -745,6 +753,14 @@ packages: url: "https://pub.dev" source: hosted version: "10.7.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" frontend_server_client: dependency: transitive description: @@ -1728,6 +1744,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + stripe_android: + dependency: transitive + description: + name: stripe_android + sha256: a1ba929247d9accd9d8b201740cc005f66ad2f739ce5323679fa408d5296338c + url: "https://pub.dev" + source: hosted + version: "10.1.0" + stripe_ios: + dependency: transitive + description: + name: stripe_ios + sha256: "67994171a29301d12d6a557177d02b12f0d400edd3041ecbdad5fd5c25b43569" + url: "https://pub.dev" + source: hosted + version: "10.1.0" + stripe_platform_interface: + dependency: transitive + description: + name: stripe_platform_interface + sha256: "78d7f0b8d39df3b296283dd5eebbe936b1bd82a4b7252be4dbcbddb02a2175e1" + url: "https://pub.dev" + source: hosted + version: "10.1.0" synchronized: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 495d6db6..78f932d4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -126,6 +126,7 @@ dependencies: media_kit_libs_video: ^1.0.4 path: ^1.8.3 autoscale_tabbarview: ^1.0.2 + flutter_stripe: ^10.1.0 dev_dependencies: flutter_test: From 8b01765ff146f5778a6e207fbcac22fab20151d1 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Fri, 8 Mar 2024 11:03:20 +0800 Subject: [PATCH 02/36] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20iOS=20=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E7=BC=96=E8=AF=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Podfile | 2 +- ios/Podfile.lock | 77 +++++++++++++++---- ios/Runner.xcodeproj/project.pbxproj | 14 +--- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 2c068c40..10f3c9b4 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fd1f9b13..028ae98c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -54,9 +54,6 @@ PODS: - fluwx (0.0.1): - Flutter - WechatOpenSDK-XCFramework (~> 2.0.2) - - FMDB (2.7.5): - - FMDB/standard (= 2.7.5) - - FMDB/standard (2.7.5) - image_gallery_saver (1.5.0): - Flutter - in_app_purchase_storekit (0.0.1): @@ -105,7 +102,43 @@ PODS: - Flutter - sqflite (0.0.3): - Flutter - - FMDB (>= 2.7.5) + - FlutterMacOS + - Stripe (23.22.1): + - StripeApplePay (= 23.22.1) + - StripeCore (= 23.22.1) + - StripePayments (= 23.22.1) + - StripePaymentsUI (= 23.22.1) + - StripeUICore (= 23.22.1) + - stripe_ios (0.0.1): + - Flutter + - Stripe (~> 23.22.0) + - StripeApplePay (~> 23.22.0) + - StripeFinancialConnections (~> 23.22.0) + - StripePayments (~> 23.22.0) + - StripePaymentSheet (~> 23.22.0) + - StripePaymentsUI (~> 23.22.0) + - StripeApplePay (23.22.1): + - StripeCore (= 23.22.1) + - StripeCore (23.22.1) + - StripeFinancialConnections (23.22.1): + - StripeCore (= 23.22.1) + - StripeUICore (= 23.22.1) + - StripePayments (23.22.1): + - StripeCore (= 23.22.1) + - StripePayments/Stripe3DS2 (= 23.22.1) + - StripePayments/Stripe3DS2 (23.22.1): + - StripeCore (= 23.22.1) + - StripePaymentSheet (23.22.1): + - StripeApplePay (= 23.22.1) + - StripeCore (= 23.22.1) + - StripePayments (= 23.22.1) + - StripePaymentsUI (= 23.22.1) + - StripePaymentsUI (23.22.1): + - StripeCore (= 23.22.1) + - StripePayments (= 23.22.1) + - StripeUICore (= 23.22.1) + - StripeUICore (23.22.1): + - StripeCore (= 23.22.1) - SwiftyGif (5.4.4) - tobias (0.0.1): - Flutter @@ -140,7 +173,8 @@ DEPENDENCIES: - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`) - - sqflite (from `.symlinks/plugins/sqflite/ios`) + - sqflite (from `.symlinks/plugins/sqflite/darwin`) + - stripe_ios (from `.symlinks/plugins/stripe_ios/ios`) - tobias (from `.symlinks/plugins/tobias/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`) @@ -150,11 +184,18 @@ SPEC REPOS: trunk: - DKImagePickerController - DKPhotoGallery - - FMDB - libwebp - Mantle - SDWebImage - SDWebImageWebPCoder + - Stripe + - StripeApplePay + - StripeCore + - StripeFinancialConnections + - StripePayments + - StripePaymentSheet + - StripePaymentsUI + - StripeUICore - SwiftyGif - WechatOpenSDK-XCFramework @@ -204,7 +245,9 @@ EXTERNAL SOURCES: sign_in_with_apple: :path: ".symlinks/plugins/sign_in_with_apple/ios" sqflite: - :path: ".symlinks/plugins/sqflite/ios" + :path: ".symlinks/plugins/sqflite/darwin" + stripe_ios: + :path: ".symlinks/plugins/stripe_ios/ios" tobias: :path: ".symlinks/plugins/tobias/ios" url_launcher_ios: @@ -220,16 +263,15 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: ce3938a0df3cc1ef404671531facef740d03f920 file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808 - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433 flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 flutter_localization: f43b18844a2b3d2c71fd64f04ffd6b1e64dd54d4 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d fluwx: e9e728cfdb80e82dac5f4ff974b1901a7939dcd0 - FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a image_gallery_saver: 259eab68fb271cfd57d599904f7acdc7832e7ef2 - in_app_purchase_storekit: 9e9931234f0adcf71ae323f8c83785b96030edf1 + in_app_purchase_storekit: 0e4b3c2e43ba1e1281f4f46dd71b0593ce529892 libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 @@ -244,14 +286,23 @@ SPEC CHECKSUMS: share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440 - sqflite: 50a33e1d72bd59ee092a519a35d107502757ebed + sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec + Stripe: b65e9f748f8f51b51e015b0d72f5474dc0708788 + stripe_ios: 433385aa051f8965915d495744946ee5a5d657db + StripeApplePay: 4a2fef6cd4e1e9b2c0849919fc7b3a9c5c3684b1 + StripeCore: e1f6cd91d1487c0f6b5db81b42aec860420f75c9 + StripeFinancialConnections: d223a44613e6982cedd552c5950edc9b4901c90a + StripePayments: 76144e9e6b5fee859954238a175f859043562659 + StripePaymentSheet: a25d920bb3bb5e2580696476482dc7df9cb5e4e2 + StripePaymentsUI: 66088abec88754bbdd522ef227dfdbb2265a653e + StripeUICore: b193c7d35e9cd1b04bc9ed4a6fb8c548fcee83fa SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f tobias: 2aded9b83e3663b907360a800d8e3c13284f25c5 - url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 + url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586 volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 WechatOpenSDK-XCFramework: acdeeda129efbef9532bca8a10c24e1b4b8c7d69 -PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 +PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b COCOAPODS: 1.14.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9c81ed94..09204d39 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -162,7 +162,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -366,7 +366,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -420,8 +420,6 @@ "-framework", "\"DKPhotoGallery\"", "-framework", - "\"FMDB\"", - "-framework", "\"Foundation\"", "-framework", "\"ImageIO\"", @@ -542,7 +540,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -591,7 +589,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -647,8 +645,6 @@ "-framework", "\"DKPhotoGallery\"", "-framework", - "\"FMDB\"", - "-framework", "\"Foundation\"", "-framework", "\"ImageIO\"", @@ -768,8 +764,6 @@ "-framework", "\"DKPhotoGallery\"", "-framework", - "\"FMDB\"", - "-framework", "\"Foundation\"", "-framework", "\"ImageIO\"", diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db..5e31d3d3 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 8 Mar 2024 11:08:55 +0800 Subject: [PATCH 03/36] remove unused packages --- lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index fc831b2f..5fb08e00 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,5 @@ import 'package:askaide/helper/path.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; -import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:path/path.dart'; import 'package:askaide/bloc/account_bloc.dart'; From 14ccb0a83f9289875de7d1d070e7597b7f38c24f Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 13 Mar 2024 00:27:02 +0800 Subject: [PATCH 04/36] update --- docker-build.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docker-build.sh b/docker-build.sh index 31269646..0a5313cf 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -1,13 +1,9 @@ #!/usr/bin/env bash -VERSION=1.0.13 +VERSION=1.0.13.1 rm -fr build/web flutter build web --web-renderer canvaskit --release --dart-define=API_SERVER_URL=/ -cd scripts && go run main.go ../build/web/main.dart.js && cd .. -rm -fr build/web/fonts/ && mkdir build/web/fonts -cp -r scripts/s build/web/fonts/s - docker buildx build --platform=linux/amd64,linux/arm64 -t mylxsw/aidea-web:$VERSION . --push From 46261e87a2f2eb4db591526a69e4b59a61d22743 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 13 Mar 2024 12:48:10 +0800 Subject: [PATCH 05/36] =?UTF-8?q?Stripe=20=E6=94=AF=E4=BB=98=E5=8F=AA?= =?UTF-8?q?=E6=9C=89=E6=9F=90=E4=BA=9B=E4=BA=A7=E5=93=81=E4=B8=AD=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/balance/payment.dart | 26 ++++++++++++++++++++++++-- lib/repo/api/payment.dart | 9 +++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/page/balance/payment.dart b/lib/page/balance/payment.dart index 6a6cf3fd..edd7dbc0 100644 --- a/lib/page/balance/payment.dart +++ b/lib/page/balance/payment.dart @@ -319,8 +319,30 @@ class _PaymentScreenState extends State { [ if (Ability().enableOtherPay) SelectorItem(const Text('支付宝'), 'alipay'), - if (Ability().enableStripe) - SelectorItem(const Text('Stripe'), 'stripe'), + if (Ability().enableStripe && + state.localProducts + .firstWhere( + (e) => e.id == selectedProduct!.id) + .supportStripe) + SelectorItem( + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const Text('Stripe'), + const SizedBox(width: 5), + Text( + '(${state.localProducts.firstWhere((e) => e.id == selectedProduct!.id).retailPriceUSDText})', + style: TextStyle( + color: customColors + .paymentItemTitleColor + ?.withOpacity(0.5), + fontSize: 12, + ), + ), + ], + ), + 'stripe'), ], (value) { _startPaymentLoading(); diff --git a/lib/repo/api/payment.dart b/lib/repo/api/payment.dart index 0179ca64..6d0ace22 100644 --- a/lib/repo/api/payment.dart +++ b/lib/repo/api/payment.dart @@ -30,6 +30,7 @@ class PaymentProduct { String expirePolicyText; bool recommend; String? description; + List methods; PaymentProduct({ required this.id, @@ -41,6 +42,7 @@ class PaymentProduct { this.recommend = false, this.description, this.retailPriceUSD = 0, + this.methods = const [], }); String get retailPriceText => '¥${(retailPrice / 100).toStringAsFixed(0)}'; @@ -48,6 +50,9 @@ class PaymentProduct { String get retailPriceUSDText => '\$${(retailPriceUSD / 100).toStringAsFixed(2)}'; + /// 是否支持 Stripe 支付 + bool get supportStripe => methods.contains('stripe') || methods.isEmpty; + toJson() => { 'id': id, 'name': name, @@ -58,6 +63,7 @@ class PaymentProduct { 'expire_policy_text': expirePolicyText, 'recommend': recommend, 'description': description, + 'methods': methods, }; static PaymentProduct fromJson(Map json) { @@ -71,6 +77,9 @@ class PaymentProduct { expirePolicyText: json['expire_policy_text'], recommend: json['recommend'] ?? false, description: json['description'], + methods: ((json['methods'] ?? []) as List) + .map((e) => e.toString()) + .toList(), ); } } From 6752ed9e094f0f71cf4c6163fbbf701605cf2ec0 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 13 Mar 2024 16:19:15 +0800 Subject: [PATCH 06/36] update --- lib/page/balance/payment.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/page/balance/payment.dart b/lib/page/balance/payment.dart index edd7dbc0..ddc4589f 100644 --- a/lib/page/balance/payment.dart +++ b/lib/page/balance/payment.dart @@ -314,16 +314,17 @@ class _PaymentScreenState extends State { } if (PlatformTool.isAndroid()) { + final enableStripe = Ability().enableStripe && + state.localProducts + .firstWhere( + (e) => e.id == selectedProduct!.id) + .supportStripe; openListSelectDialog( context, [ if (Ability().enableOtherPay) SelectorItem(const Text('支付宝'), 'alipay'), - if (Ability().enableStripe && - state.localProducts - .firstWhere( - (e) => e.id == selectedProduct!.id) - .supportStripe) + if (enableStripe) SelectorItem( Row( mainAxisAlignment: From 442f49f280de1fcb5eb3f0e8d30d8c8be2caa12f Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 14 Mar 2024 00:15:44 +0800 Subject: [PATCH 07/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=89=93=E6=96=AD?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bloc/chat_event.dart | 2 + lib/bloc/chat_message_bloc.dart | 12 ++++++ lib/helper/queue.dart | 9 ++++ lib/page/chat/home_chat.dart | 5 +++ lib/page/chat/room_chat.dart | 5 +++ lib/page/component/chat/chat_input.dart | 57 +++++++++++++++++++++++-- lib/repo/openai_repo.dart | 16 +++++-- 7 files changed, 98 insertions(+), 8 deletions(-) diff --git a/lib/bloc/chat_event.dart b/lib/bloc/chat_event.dart index 648e5944..c18e0f25 100644 --- a/lib/bloc/chat_event.dart +++ b/lib/bloc/chat_event.dart @@ -32,3 +32,5 @@ class ChatMessageDeleteEvent extends ChatMessageEvent { final int? chatHistoryId; ChatMessageDeleteEvent(this.ids, {this.chatHistoryId}); } + +class ChatMessageStopEvent extends ChatMessageEvent {} diff --git a/lib/bloc/chat_message_bloc.dart b/lib/bloc/chat_message_bloc.dart index 23d61a54..4d0c38c6 100644 --- a/lib/bloc/chat_message_bloc.dart +++ b/lib/bloc/chat_message_bloc.dart @@ -28,6 +28,8 @@ class ChatMessageBloc extends BlocExt { final int roomId; final int? chatHistoryId; + GracefulQueue? currentQueue; + ChatMessageBloc( this.roomId, { required this.chatMsgRepo, @@ -39,6 +41,7 @@ class ChatMessageBloc extends BlocExt { on(_clearAllEventHandler); on(_breakContextEventHandler); on(_deleteMessageEventHandler); + on(_stopEventHandler); } Future _deleteMessageEventHandler(event, emit) async { @@ -176,6 +179,13 @@ class ChatMessageBloc extends BlocExt { )); } + /// 停止输出事件处理 + Future _stopEventHandler(event, emit) async { + if (currentQueue != null) { + currentQueue!.finish(); + } + } + /// 消息发送事件处理 Future _messageSendEventHandler(event, emit) async { if (event.message is! Message) { @@ -320,6 +330,7 @@ class ChatMessageBloc extends BlocExt { // 等待监听机器人应答消息 final queue = GracefulQueue(); + currentQueue = queue; try { RequestFailedException? error; var listener = queue.listen(const Duration(milliseconds: 10), (items) { @@ -479,6 +490,7 @@ class ChatMessageBloc extends BlocExt { queue.finish(); } finally { queue.dispose(); + currentQueue = null; } emit(ChatMessageUpdated(waitMessage)); diff --git a/lib/helper/queue.dart b/lib/helper/queue.dart index 2a262aa9..71f6c93d 100644 --- a/lib/helper/queue.dart +++ b/lib/helper/queue.dart @@ -1,6 +1,11 @@ import 'dart:async'; import 'dart:collection'; +class QueueFinishedException implements Exception { + final String message; + QueueFinishedException(this.message); +} + /// 该队列以一定的时间间隔将队列中的元素传递给回调函数,实现平滑的队列处理 class GracefulQueue { final Queue _queue = Queue(); @@ -8,6 +13,10 @@ class GracefulQueue { Timer? _timer; void add(T item) { + if (finished) { + throw QueueFinishedException('Queue is finished'); + } + _queue.add(item); } diff --git a/lib/page/chat/home_chat.dart b/lib/page/chat/home_chat.dart index 3926ca82..0d8a9d16 100644 --- a/lib/page/chat/home_chat.dart +++ b/lib/page/chat/home_chat.dart @@ -453,6 +453,11 @@ class _HomeChatPageState extends State { onVoiceRecordTappedEvent: () { audioPlayerController.stop(); }, + onStopGenerate: () { + context + .read() + .add(ChatMessageStopEvent()); + }, ); }, ), diff --git a/lib/page/chat/room_chat.dart b/lib/page/chat/room_chat.dart index e291c772..ff2428a8 100644 --- a/lib/page/chat/room_chat.dart +++ b/lib/page/chat/room_chat.dart @@ -207,6 +207,11 @@ class _RoomChatPageState extends State { onVoiceRecordTappedEvent: () { _audioPlayerController.stop(); }, + onStopGenerate: () { + context + .read() + .add(ChatMessageStopEvent()); + }, ), ); }, diff --git a/lib/page/component/chat/chat_input.dart b/lib/page/component/chat/chat_input.dart index 16109d7d..f8c6d8ff 100644 --- a/lib/page/component/chat/chat_input.dart +++ b/lib/page/component/chat/chat_input.dart @@ -29,6 +29,7 @@ class ChatInput extends StatefulWidget { final String hintText; final Function()? onVoiceRecordTappedEvent; final List Function()? leftSideToolsBuilder; + final Function()? onStopGenerate; const ChatInput({ super.key, @@ -42,13 +43,14 @@ class ChatInput extends StatefulWidget { this.leftSideToolsBuilder, this.onImageSelected, this.selectedImageFiles, + this.onStopGenerate, }); @override State createState() => _ChatInputState(); } -class _ChatInputState extends State { +class _ChatInputState extends State with TickerProviderStateMixin { final TextEditingController _textController = TextEditingController(); /// 用于监听键盘事件,实现回车发送消息,Shift+Enter换行 @@ -68,6 +70,10 @@ class _ChatInputState extends State { final maxLength = 150000; + AnimationStatus status = AnimationStatus.forward; + late AnimationController animationController; + late Animation anim; + @override void initState() { super.initState(); @@ -84,11 +90,32 @@ class _ChatInputState extends State { } }); } + + animationController = AnimationController( + vsync: this, + duration: const Duration(seconds: 1), + ); + anim = Tween(begin: 0.75, end: 1.0).animate(animationController) + ..addListener(() { + if (animationController.status != AnimationStatus.dismissed && + animationController.status != AnimationStatus.completed) { + status = animationController.status; + } + if (animationController.status == AnimationStatus.completed || + animationController.status == AnimationStatus.dismissed) { + status == AnimationStatus.forward + ? animationController.reverse() + : animationController.forward(); + } + }); + + animationController.forward(); } @override void dispose() { _textController.dispose(); + animationController.dispose(); super.dispose(); } @@ -259,9 +286,31 @@ class _ChatInputState extends State { CustomColors customColors, ) { if (!widget.enableNotifier.value) { - return LoadingAnimationWidget.beat( - color: customColors.linkColor!, - size: 20, + return InkWell( + onTap: () { + if (widget.onStopGenerate != null) { + openConfirmDialog( + context, + '确定要打断当前对话?', + () { + widget.onStopGenerate!(); + HapticFeedbackHelper.heavyImpact(); + }, + danger: true, + ); + } + }, + child: AnimatedBuilder( + animation: anim, + builder: (context, child) { + return Transform.scale( + scale: anim.value, + child: Icon( + Icons.stop_circle_outlined, + color: customColors.linkColor?.withOpacity(anim.value), + ), + ); + }), ); } diff --git a/lib/repo/openai_repo.dart b/lib/repo/openai_repo.dart index ec73166a..7c06d656 100644 --- a/lib/repo/openai_repo.dart +++ b/lib/repo/openai_repo.dart @@ -5,11 +5,13 @@ import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/env.dart'; import 'package:askaide/helper/platform.dart'; +import 'package:askaide/helper/queue.dart'; import 'package:askaide/repo/model/chat_message.dart'; import 'package:askaide/repo/model/model.dart' as mm; import 'package:dart_openai/openai.dart'; import 'package:askaide/repo/data/settings_data.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:web_socket_channel/status.dart' as status; class OpenAIRepository { final SettingDataProvider settings; @@ -296,6 +298,8 @@ class OpenAIRepository { }, )); + await channel.ready; + channel.stream.listen( (event) { final evt = jsonDecode(event); @@ -312,10 +316,14 @@ class OpenAIRepository { final res = OpenAIStreamChatCompletionModel.fromMap(evt); for (var element in res.choices) { if (element.delta.content != null) { - onData(ChatStreamRespData( - content: element.delta.content!, - role: element.delta.role, - )); + try { + onData(ChatStreamRespData( + content: element.delta.content!, + role: element.delta.role, + )); + } on QueueFinishedException { + channel.sink.close(status.goingAway); + } } } }, From 050c24c6f8f95dfc87de6b680149cb5918268715 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 14 Mar 2024 15:10:00 +0800 Subject: [PATCH 08/36] =?UTF-8?q?=E6=94=AF=E6=8C=81=20Web=20=E7=AB=AF?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=20Stripe=20=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/helper/ability.dart | 5 + lib/main.dart | 11 ++ lib/page/balance/payment.dart | 181 ++++++++++++++---- lib/page/balance/web/payment_element.dart | 17 ++ lib/page/balance/web/payment_element_web.dart | 44 +++++ lib/page/balance/web_payment_result.dart | 115 +++++++++++ lib/page/component/chat/chat_input.dart | 1 - lib/page/component/dialog.dart | 6 +- pubspec.lock | 16 ++ pubspec.yaml | 2 + 10 files changed, 363 insertions(+), 35 deletions(-) create mode 100644 lib/page/balance/web/payment_element.dart create mode 100644 lib/page/balance/web/payment_element_web.dart create mode 100644 lib/page/balance/web_payment_result.dart diff --git a/lib/helper/ability.dart b/lib/helper/ability.dart index 7d0fd61b..a3c2bf7e 100644 --- a/lib/helper/ability.dart +++ b/lib/helper/ability.dart @@ -176,4 +176,9 @@ class Ability { bool supportQiniuUploader() { return setting.stringDefault(settingAPIServerToken, '') != ''; } + + /// 获取当前主题模式 + String get themeMode { + return setting.stringDefault(settingThemeMode, 'system'); + } } diff --git a/lib/main.dart b/lib/main.dart index 5fb08e00..21a56f62 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:askaide/helper/path.dart'; +import 'package:askaide/page/balance/web_payment_result.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; import 'package:path/path.dart'; @@ -1029,6 +1030,16 @@ class MyApp extends StatefulWidget { ); }, ), + GoRoute( + name: 'web-payment-result', + path: '/payment/result', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver(WebPaymentResult( + paymentId: state.queryParameters['payment_id']!, + )); + }, + ), ], ) ], diff --git a/lib/page/balance/payment.dart b/lib/page/balance/payment.dart index ddc4589f..f3e03932 100644 --- a/lib/page/balance/payment.dart +++ b/lib/page/balance/payment.dart @@ -15,6 +15,7 @@ import 'package:askaide/page/component/loading.dart'; import 'package:askaide/page/component/dialog.dart'; import 'package:askaide/page/component/theme/custom_size.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/payment.dart'; import 'package:askaide/repo/api_server.dart'; import 'package:askaide/repo/settings_repo.dart'; import 'package:bot_toast/bot_toast.dart'; @@ -28,6 +29,9 @@ import 'package:quickalert/models/quickalert_type.dart'; import 'package:tobias/tobias.dart'; import 'package:url_launcher/url_launcher_string.dart'; +import 'web/payment_element.dart' + if (dart.library.js) 'web/payment_element_web.dart'; + class PaymentScreen extends StatefulWidget { final SettingRepository setting; const PaymentScreen({super.key, required this.setting}); @@ -183,6 +187,19 @@ class _PaymentScreenState extends State { fontSize: CustomSize.appBarTitleSize, ), ), + leading: IconButton( + icon: Icon( + Icons.arrow_back_ios, + color: customColors.weakLinkColor, + ), + onPressed: () { + if (context.canPop()) { + context.pop(); + } else { + context.go('/setting'); + } + }, + ), actions: [ if (Ability().isUserLogon()) TextButton( @@ -314,11 +331,10 @@ class _PaymentScreenState extends State { } if (PlatformTool.isAndroid()) { + final localProduct = state.localProducts + .firstWhere((e) => e.id == selectedProduct!.id); final enableStripe = Ability().enableStripe && - state.localProducts - .firstWhere( - (e) => e.id == selectedProduct!.id) - .supportStripe; + localProduct.supportStripe; openListSelectDialog( context, [ @@ -333,7 +349,7 @@ class _PaymentScreenState extends State { const Text('Stripe'), const SizedBox(width: 5), Text( - '(${state.localProducts.firstWhere((e) => e.id == selectedProduct!.id).retailPriceUSDText})', + '(${localProduct.retailPriceUSDText})', style: TextStyle( color: customColors .paymentItemTitleColor @@ -355,7 +371,7 @@ class _PaymentScreenState extends State { showErrorMessageEnhanced(context, error!); }); } else { - createStripePayment(); + createStripePayment(localProduct); } return true; @@ -388,25 +404,57 @@ class _PaymentScreenState extends State { // ); // }, // confirmText: '前往下载移动端 APP', - // ); + // ) + + final localProduct = state.localProducts + .firstWhere((e) => e.id == selectedProduct!.id); + + final enableStripe = Ability().enableStripe && + localProduct.supportStripe; + openListSelectDialog( context, [ - SelectorItem(const Text('支付宝电脑端(扫码支付)'), 'web'), - SelectorItem(const Text('支付宝手机端'), 'wap'), + SelectorItem(const Text('支付宝扫码'), 'web'), + SelectorItem(const Text('支付宝手机版'), 'wap'), + if (enableStripe) + SelectorItem( + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const Text('Stripe'), + const SizedBox(width: 5), + Text( + '(${localProduct.retailPriceUSDText})', + style: TextStyle( + color: customColors + .paymentItemTitleColor + ?.withOpacity(0.5), + fontSize: 12, + ), + ), + ], + ), + 'stripe', + ), ], (value) { _startPaymentLoading(); - createWebOrWapAlipay(source: value.value) - .onError((error, stackTrace) { - _closePaymentLoading(); - showErrorMessageEnhanced(context, error!); - }); + if (value.value != 'stripe') { + createWebOrWapAlipay(source: value.value) + .onError((error, stackTrace) { + _closePaymentLoading(); + showErrorMessageEnhanced(context, error!); + }); + } else { + createStripePayment(localProduct); + } return true; }, title: '请选择支付方式', - heightFactor: 0.3, + heightFactor: 0.4, ); } }, @@ -497,12 +545,14 @@ class _PaymentScreenState extends State { _closePaymentLoading(); } catch (e) { _closePaymentLoading(); + // ignore: use_build_context_synchronously showErrorMessage(resolveError(context, e)); } }); } } catch (e) { _closePaymentLoading(); + // ignore: use_build_context_synchronously showErrorMessage(resolveError(context, e)); } }, @@ -513,33 +563,98 @@ class _PaymentScreenState extends State { } /// 创建 Stripe 支付 - Future createStripePayment() async { + Future createStripePayment(PaymentProduct product) async { try { final created = await APIServer().createStripePaymentSheet( - productId: selectedProduct!.id, + productId: product.id, ); paymentId = created.paymentId; Stripe.publishableKey = created.publishableKey; + Stripe.urlScheme = 'flutterstripe'; - // 调起 Stripe 支付 - await Stripe.instance.initPaymentSheet( - paymentSheetParameters: SetupPaymentSheetParameters( - paymentIntentClientSecret: created.paymentIntent, - merchantDisplayName: 'AIdea', - customerId: created.customer, - customerEphemeralKeySecret: created.ephemeralKey, - returnURL: 'flutterstripe://redirect', + await Stripe.instance.applySettings(); + + if (PlatformTool.isWeb()) { + Navigator.push( // ignore: use_build_context_synchronously - style: MediaQuery.platformBrightnessOf(context) == Brightness.dark - ? ThemeMode.dark - : ThemeMode.light, - ), - ); + context, + MaterialPageRoute( + fullscreenDialog: true, + builder: (context) { + return Scaffold( + appBar: AppBar(), + body: SafeArea( + child: Column( + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.all(15), + child: Builder( + builder: (context) { + return PlatformPaymentElement( + created.paymentIntent, + ); + }, + ), + ), + ), + Container( + padding: const EdgeInsets.all(15), + child: EnhancedButton( + title: '确定付款(${product.retailPriceUSDText})', + onPressed: () async { + final cancel = BotToast.showCustomLoading( + toastBuilder: (cancel) { + return LoadingIndicator( + message: AppLocale.processingWait + .getString(context), + ); + }, + allowClick: false, + duration: const Duration(seconds: 120), + ); - // 确认支付 - await Stripe.instance.presentPaymentSheet(); - showSuccessMessage('购买成功'); + try { + await pay(created.paymentId); + } catch (e) { + Logger.instance.e('支付失败:$e'); + // ignore: use_build_context_synchronously + showErrorMessageEnhanced(context, '请填写完整的支付信息'); + } finally { + cancel(); + } + }, + ), + ) + ], + ), + ), + ); + }, + ), + ); + } else { + // 调起 Stripe 支付 + await Stripe.instance.initPaymentSheet( + paymentSheetParameters: SetupPaymentSheetParameters( + paymentIntentClientSecret: created.paymentIntent, + merchantDisplayName: 'AIdea', + customerId: created.customer, + customerEphemeralKeySecret: created.ephemeralKey, + returnURL: 'flutterstripe://redirect', + // ignore: use_build_context_synchronously + style: Ability().themeMode == 'dark' + ? ThemeMode.dark + : ThemeMode.light, + ), + ); + + // 确认支付 + await Stripe.instance.presentPaymentSheet(); + + showSuccessMessage('购买成功'); + } } on Exception catch (e) { if (e is StripeException) { showErrorMessage('支付失败:${e.error.localizedMessage}'); diff --git a/lib/page/balance/web/payment_element.dart b/lib/page/balance/web/payment_element.dart new file mode 100644 index 00000000..c56c9a0a --- /dev/null +++ b/lib/page/balance/web/payment_element.dart @@ -0,0 +1,17 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_stripe/flutter_stripe.dart'; + +Future pay(String paymentId) async { + throw UnimplementedError(); +} + +class PlatformPaymentElement extends StatelessWidget { + const PlatformPaymentElement(this.clientSecret, {super.key}); + + final String? clientSecret; + + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/lib/page/balance/web/payment_element_web.dart b/lib/page/balance/web/payment_element_web.dart new file mode 100644 index 00000000..d10b1a20 --- /dev/null +++ b/lib/page/balance/web/payment_element_web.dart @@ -0,0 +1,44 @@ +import 'package:askaide/helper/ability.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_stripe_web/flutter_stripe_web.dart'; +import 'dart:html' as html; +import 'package:stripe_js/stripe_api.dart' as js; + +Future pay(String paymentId) async { + final currentUrl = Uri.parse(html.window.location.href); + var href = Uri( + scheme: currentUrl.scheme, + host: currentUrl.host, + port: currentUrl.port, + fragment: '/payment/result?payment_id=$paymentId', + ).toString(); + + return await WebStripe.instance.confirmPaymentElement( + ConfirmPaymentElementOptions( + confirmParams: ConfirmPaymentParams( + return_url: href, + ), + ), + ); +} + +class PlatformPaymentElement extends StatelessWidget { + const PlatformPaymentElement(this.clientSecret, {super.key}); + + final String? clientSecret; + + @override + Widget build(BuildContext context) { + return PaymentElement( + autofocus: true, + enablePostalCode: true, + onCardChanged: (_) {}, + clientSecret: clientSecret ?? '', + appearance: js.ElementAppearance( + theme: Ability().themeMode == 'dark' + ? js.ElementTheme.night + : js.ElementTheme.stripe, + ), + ); + } +} diff --git a/lib/page/balance/web_payment_result.dart b/lib/page/balance/web_payment_result.dart new file mode 100644 index 00000000..b0715625 --- /dev/null +++ b/lib/page/balance/web_payment_result.dart @@ -0,0 +1,115 @@ +import 'package:askaide/bloc/payment_bloc.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/payment.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; + +class WebPaymentResult extends StatefulWidget { + final String paymentId; + const WebPaymentResult({super.key, required this.paymentId}); + + @override + State createState() => _WebPaymentResultState(); +} + +class _WebPaymentResultState extends State { + PaymentStatus? paymentStatus; + DateTime startTime = DateTime.now(); + + @override + void initState() { + super.initState(); + + updatePaymentStatus(); + } + + updatePaymentStatus() { + if (!context.mounted) { + return; + } + + if (DateTime.now().difference(startTime).inSeconds > 60) { + setState(() { + paymentStatus = PaymentStatus(false, note: '查询超时'); + }); + return; + } + + APIServer().queryPaymentStatus(widget.paymentId).then((value) { + if (!value.success) { + Future.delayed(const Duration(seconds: 3), () { + if (context.mounted) { + updatePaymentStatus(); + } + }); + } else { + setState(() { + paymentStatus = value; + }); + } + }); + } + + @override + Widget build(BuildContext context) { + var customColors = Theme.of(context).extension()!; + return Scaffold( + appBar: AppBar( + title: const Text('支付结果'), + leading: IconButton( + icon: Icon( + Icons.close, + color: customColors.weakLinkColor, + ), + onPressed: () { + if (context.canPop()) { + context.pop(); + } else { + context.go('/payment'); + } + }, + ), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: buildResult(), + ), + ), + ); + } + + List buildResult() { + if (paymentStatus == null) { + return const [ + CircularProgressIndicator(), + SizedBox(height: 20), + Text('正在查询支付结果'), + ]; + } + + if (!paymentStatus!.success) { + return [ + const Icon( + Icons.error, + color: Colors.red, + size: 100, + ), + Text(paymentStatus!.note ?? '支付失败'), + ]; + } + + return [ + const Icon( + Icons.check_circle, + color: Colors.green, + size: 100, + ), + const Text( + '支付成功', + style: TextStyle(fontSize: 24), + ), + ]; + } +} diff --git a/lib/page/component/chat/chat_input.dart b/lib/page/component/chat/chat_input.dart index f8c6d8ff..123ce304 100644 --- a/lib/page/component/chat/chat_input.dart +++ b/lib/page/component/chat/chat_input.dart @@ -15,7 +15,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localization/flutter_localization.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; class ChatInput extends StatefulWidget { diff --git a/lib/page/component/dialog.dart b/lib/page/component/dialog.dart index 672f6247..3e6820df 100644 --- a/lib/page/component/dialog.dart +++ b/lib/page/component/dialog.dart @@ -246,7 +246,11 @@ Future openModalBottomSheet( if (title != null) Text( title, - style: const TextStyle(fontSize: 16), + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: customColors.weakTextColorPlus, + ), ), if (title != null) const SizedBox(height: 10), Expanded( diff --git a/pubspec.lock b/pubspec.lock index 6e89336f..f18090ef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -711,6 +711,14 @@ packages: url: "https://pub.dev" source: hosted version: "10.1.0" + flutter_stripe_web: + dependency: "direct main" + description: + name: flutter_stripe_web + sha256: bcadbce717cacae1c9ade225394c08a15eda682b3579e50adab7f04fcd16d837 + url: "https://pub.dev" + source: hosted + version: "5.1.0" flutter_svg: dependency: transitive description: @@ -1760,6 +1768,14 @@ packages: url: "https://pub.dev" source: hosted version: "10.1.0" + stripe_js: + dependency: "direct main" + description: + name: stripe_js + sha256: d203b48167a9a533bbf72049b40c8227bf0557d79e28a7f016e77dddcac8b19b + url: "https://pub.dev" + source: hosted + version: "3.4.0" stripe_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 78f932d4..1ec1695c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -127,6 +127,8 @@ dependencies: path: ^1.8.3 autoscale_tabbarview: ^1.0.2 flutter_stripe: ^10.1.0 + flutter_stripe_web: ^5.1.0 + stripe_js: ^3.4.0 dev_dependencies: flutter_test: From 07888b1ae32050b2927a1aec43d1c5945cb6e225 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 14 Mar 2024 15:10:09 +0800 Subject: [PATCH 09/36] update --- lib/page/balance/web_payment_result.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/page/balance/web_payment_result.dart b/lib/page/balance/web_payment_result.dart index b0715625..a8195f4c 100644 --- a/lib/page/balance/web_payment_result.dart +++ b/lib/page/balance/web_payment_result.dart @@ -1,4 +1,3 @@ -import 'package:askaide/bloc/payment_bloc.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; import 'package:askaide/repo/api/payment.dart'; import 'package:askaide/repo/api_server.dart'; From 61edb11d2006a5e0af3f3bcf6265827887b05fd7 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 14 Mar 2024 17:20:17 +0800 Subject: [PATCH 10/36] =?UTF-8?q?web&pc=20=E6=94=AF=E6=8C=81=20Stripe=20?= =?UTF-8?q?=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/helper/constant.dart | 2 +- lib/main.dart | 18 + lib/page/balance/payment.dart | 364 ++++++++++++------ lib/page/balance/web/payment_element.dart | 6 +- lib/page/balance/web/payment_element_web.dart | 8 +- lib/page/balance/web_payment_proxy.dart | 134 +++++++ lib/page/balance/web_payment_result.dart | 19 +- lib/page/chat/component/room_item.dart | 1 + lib/repo/api/payment.dart | 4 + lib/repo/model/misc.dart | 6 +- pubspec.yaml | 2 +- 11 files changed, 432 insertions(+), 132 deletions(-) create mode 100644 lib/page/balance/web_payment_proxy.dart diff --git a/lib/helper/constant.dart b/lib/helper/constant.dart index 905fe920..d14cb44e 100644 --- a/lib/helper/constant.dart +++ b/lib/helper/constant.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; // 客户端应用版本号 -const clientVersion = '1.0.13'; +const clientVersion = '1.0.14'; // 本地数据库版本号 const databaseVersion = 26; diff --git a/lib/main.dart b/lib/main.dart index 21a56f62..df4b5126 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:askaide/helper/path.dart'; +import 'package:askaide/page/balance/web_payment_proxy.dart'; import 'package:askaide/page/balance/web_payment_result.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; import 'package:path/path.dart'; @@ -1037,6 +1038,23 @@ class MyApp extends StatefulWidget { pageBuilder: (context, state) { return transitionResolver(WebPaymentResult( paymentId: state.queryParameters['payment_id']!, + action: state.queryParameters['action'], + )); + }, + ), + GoRoute( + name: 'web-payment-proxy', + path: '/payment/proxy', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver(WebPaymentProxy( + setting: settingRepo, + paymentId: state.queryParameters['id']!, + paymentIntent: state.queryParameters['intent']!, + price: state.queryParameters['price']!, + publishableKey: state.queryParameters['key']!, + finishAction: + state.queryParameters['finish_action'] ?? 'close', )); }, ), diff --git a/lib/page/balance/payment.dart b/lib/page/balance/payment.dart index f3e03932..e00c2c5c 100644 --- a/lib/page/balance/payment.dart +++ b/lib/page/balance/payment.dart @@ -331,131 +331,21 @@ class _PaymentScreenState extends State { } if (PlatformTool.isAndroid()) { - final localProduct = state.localProducts - .firstWhere((e) => e.id == selectedProduct!.id); - final enableStripe = Ability().enableStripe && - localProduct.supportStripe; - openListSelectDialog( - context, - [ - if (Ability().enableOtherPay) - SelectorItem(const Text('支付宝'), 'alipay'), - if (enableStripe) - SelectorItem( - Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - const Text('Stripe'), - const SizedBox(width: 5), - Text( - '(${localProduct.retailPriceUSDText})', - style: TextStyle( - color: customColors - .paymentItemTitleColor - ?.withOpacity(0.5), - fontSize: 12, - ), - ), - ], - ), - 'stripe'), - ], - (value) { - _startPaymentLoading(); - - if (value.value == 'alipay') { - createAppAlipay() - .onError((error, stackTrace) { - _closePaymentLoading(); - showErrorMessageEnhanced(context, error!); - }); - } else { - createStripePayment(localProduct); - } - - return true; - }, - title: '请选择支付方式', - heightFactor: 0.3, - ); - } else if (PlatformTool.isIOS() || - PlatformTool.isMacOS()) { + handlePaymentForAndroid( + state, context, customColors); + } else if (PlatformTool.isIOS()) { _startPaymentLoading(); try { - if (PlatformTool.isIOS()) { - await createAppApplePay(); - } else { - await createWebOrWapAlipay(source: 'web'); - } + await createAppApplePay(); } catch (e) { _closePaymentLoading(); // ignore: use_build_context_synchronously showErrorMessage(resolveError(context, e)); } + } else if (PlatformTool.isWeb()) { + handlePaymentForWeb(state, context, customColors); } else { - // openConfirmDialog( - // context, - // '当前终端在线支付暂不可用,预计最晚 2023 年 10 月 15 日恢复,如需充值,请使用移动端 APP(支持 Android 手机、Apple 手机)。', - // () { - // launchUrlString( - // 'https://aidea.aicode.cc', - // mode: LaunchMode.externalApplication, - // ); - // }, - // confirmText: '前往下载移动端 APP', - // ) - - final localProduct = state.localProducts - .firstWhere((e) => e.id == selectedProduct!.id); - - final enableStripe = Ability().enableStripe && - localProduct.supportStripe; - - openListSelectDialog( - context, - [ - SelectorItem(const Text('支付宝扫码'), 'web'), - SelectorItem(const Text('支付宝手机版'), 'wap'), - if (enableStripe) - SelectorItem( - Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - const Text('Stripe'), - const SizedBox(width: 5), - Text( - '(${localProduct.retailPriceUSDText})', - style: TextStyle( - color: customColors - .paymentItemTitleColor - ?.withOpacity(0.5), - fontSize: 12, - ), - ), - ], - ), - 'stripe', - ), - ], - (value) { - _startPaymentLoading(); - if (value.value != 'stripe') { - createWebOrWapAlipay(source: value.value) - .onError((error, stackTrace) { - _closePaymentLoading(); - showErrorMessageEnhanced(context, error!); - }); - } else { - createStripePayment(localProduct); - } - - return true; - }, - title: '请选择支付方式', - heightFactor: 0.4, - ); + handlePaymentForPC(state, context, customColors); } }, ), @@ -498,6 +388,168 @@ class _PaymentScreenState extends State { ); } + void handlePaymentForWeb(PaymentAppleProductsLoaded state, + BuildContext context, CustomColors customColors) { + // openConfirmDialog( + // context, + // '当前终端在线支付暂不可用,预计最晚 2023 年 10 月 15 日恢复,如需充值,请使用移动端 APP(支持 Android 手机、Apple 手机)。', + // () { + // launchUrlString( + // 'https://aidea.aicode.cc', + // mode: LaunchMode.externalApplication, + // ); + // }, + // confirmText: '前往下载移动端 APP', + // ) + + final localProduct = + state.localProducts.firstWhere((e) => e.id == selectedProduct!.id); + + final enableStripe = Ability().enableStripe && localProduct.supportStripe; + + openListSelectDialog( + context, + [ + SelectorItem(const Text('支付宝扫码'), 'web'), + SelectorItem(const Text('支付宝手机版'), 'wap'), + if (enableStripe) + SelectorItem( + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Stripe'), + const SizedBox(width: 5), + Text( + '(${localProduct.retailPriceUSDText})', + style: TextStyle( + color: customColors.paymentItemTitleColor?.withOpacity(0.5), + fontSize: 12, + ), + ), + ], + ), + 'stripe', + ), + ], + (value) { + _startPaymentLoading(); + if (value.value != 'stripe') { + createWebOrWapAlipay(source: value.value) + .onError((error, stackTrace) { + _closePaymentLoading(); + showErrorMessageEnhanced(context, error!); + }); + } else { + createStripePayment(localProduct); + } + + return true; + }, + title: '请选择支付方式', + heightFactor: 0.4, + ); + } + + void handlePaymentForPC( + PaymentAppleProductsLoaded state, + BuildContext context, + CustomColors customColors, + ) async { + final localProduct = + state.localProducts.firstWhere((e) => e.id == selectedProduct!.id); + final enableStripe = Ability().enableStripe && localProduct.supportStripe; + openListSelectDialog( + context, + [ + if (Ability().enableOtherPay) SelectorItem(const Text('支付宝'), 'alipay'), + if (enableStripe) + SelectorItem( + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Stripe'), + const SizedBox(width: 5), + Text( + '(${localProduct.retailPriceUSDText})', + style: TextStyle( + color: + customColors.paymentItemTitleColor?.withOpacity(0.5), + fontSize: 12, + ), + ), + ], + ), + 'stripe'), + ], + (value) { + _startPaymentLoading(); + + if (value.value == 'alipay') { + createWebOrWapAlipay(source: 'web').onError((error, stackTrace) { + _closePaymentLoading(); + showErrorMessageEnhanced(context, error!); + }); + } else { + createStripePayment(localProduct); + } + + return true; + }, + title: '请选择支付方式', + heightFactor: 0.3, + ); + } + + void handlePaymentForAndroid( + PaymentAppleProductsLoaded state, + BuildContext context, + CustomColors customColors, + ) { + final localProduct = + state.localProducts.firstWhere((e) => e.id == selectedProduct!.id); + final enableStripe = Ability().enableStripe && localProduct.supportStripe; + openListSelectDialog( + context, + [ + if (Ability().enableOtherPay) SelectorItem(const Text('支付宝'), 'alipay'), + if (enableStripe) + SelectorItem( + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Stripe'), + const SizedBox(width: 5), + Text( + '(${localProduct.retailPriceUSDText})', + style: TextStyle( + color: + customColors.paymentItemTitleColor?.withOpacity(0.5), + fontSize: 12, + ), + ), + ], + ), + 'stripe'), + ], + (value) { + _startPaymentLoading(); + + if (value.value == 'alipay') { + createAppAlipay().onError((error, stackTrace) { + _closePaymentLoading(); + showErrorMessageEnhanced(context, error!); + }); + } else { + createStripePayment(localProduct); + } + + return true; + }, + title: '请选择支付方式', + heightFactor: 0.3, + ); + } + /// 创建苹果应用内支付 Future createAppApplePay() async { // 创建支付,服务端保存支付信息,创建支付订单 @@ -562,18 +614,33 @@ class _PaymentScreenState extends State { }); } + /// 获取当前支付来源参数 + String paymentSource() { + if (PlatformTool.isWeb()) { + return 'web'; + } else if (PlatformTool.isIOS() || PlatformTool.isAndroid()) { + return 'app'; + } + return 'pc'; + } + /// 创建 Stripe 支付 Future createStripePayment(PaymentProduct product) async { try { final created = await APIServer().createStripePaymentSheet( productId: product.id, + source: paymentSource(), ); paymentId = created.paymentId; - Stripe.publishableKey = created.publishableKey; - Stripe.urlScheme = 'flutterstripe'; + if (PlatformTool.isWeb() || + PlatformTool.isAndroid() || + PlatformTool.isIOS()) { + Stripe.publishableKey = created.publishableKey; + Stripe.urlScheme = 'flutterstripe'; - await Stripe.instance.applySettings(); + await Stripe.instance.applySettings(); + } if (PlatformTool.isWeb()) { Navigator.push( @@ -634,7 +701,7 @@ class _PaymentScreenState extends State { }, ), ); - } else { + } else if (PlatformTool.isAndroid() || PlatformTool.isIOS()) { // 调起 Stripe 支付 await Stripe.instance.initPaymentSheet( paymentSheetParameters: SetupPaymentSheetParameters( @@ -654,6 +721,61 @@ class _PaymentScreenState extends State { await Stripe.instance.presentPaymentSheet(); showSuccessMessage('购买成功'); + } else { + // PC 端支付,发起 Web 页面 + if (created.proxyUrl == '') { + showErrorMessage('支付失败:未能获取支付链接'); + return; + } + + Logger.instance.d(created.proxyUrl); + + launchUrlString( + created.proxyUrl, + mode: LaunchMode.externalApplication, + ).then((value) { + _closePaymentLoading(); + openConfirmDialog( + context, + '请确认支付是否已完成', + () async { + _startPaymentLoading(); + try { + final resp = + await APIServer().queryPaymentStatus(created.paymentId); + if (resp.success) { + showSuccessMessage(resp.note ?? '支付成功'); + _closePaymentLoading(); + } else { + // 支付失败,延迟 5s 再次查询支付状态 + await Future.delayed(const Duration(seconds: 5), () async { + try { + final value = await APIServer() + .queryPaymentStatus(created.paymentId); + + if (value.success) { + showSuccessMessage(value.note ?? '支付成功'); + } else { + showErrorMessage('支付未完成,我们接收到的状态为:${value.note}'); + } + _closePaymentLoading(); + } catch (e) { + _closePaymentLoading(); + // ignore: use_build_context_synchronously + showErrorMessage(resolveError(context, e)); + } + }); + } + } catch (e) { + _closePaymentLoading(); + // ignore: use_build_context_synchronously + showErrorMessage(resolveError(context, e)); + } + }, + confirmText: '已完成支付', + cancelText: '支付遇到问题,稍后继续', + ); + }); } } on Exception catch (e) { if (e is StripeException) { diff --git a/lib/page/balance/web/payment_element.dart b/lib/page/balance/web/payment_element.dart index c56c9a0a..17a2af2c 100644 --- a/lib/page/balance/web/payment_element.dart +++ b/lib/page/balance/web/payment_element.dart @@ -1,7 +1,11 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_stripe/flutter_stripe.dart'; -Future pay(String paymentId) async { +Future pay(String paymentId, {String? action}) async { + throw UnimplementedError(); +} + +void closeWindow() { throw UnimplementedError(); } diff --git a/lib/page/balance/web/payment_element_web.dart b/lib/page/balance/web/payment_element_web.dart index d10b1a20..0fce1f8d 100644 --- a/lib/page/balance/web/payment_element_web.dart +++ b/lib/page/balance/web/payment_element_web.dart @@ -4,13 +4,13 @@ import 'package:flutter_stripe_web/flutter_stripe_web.dart'; import 'dart:html' as html; import 'package:stripe_js/stripe_api.dart' as js; -Future pay(String paymentId) async { +Future pay(String paymentId, {String? action}) async { final currentUrl = Uri.parse(html.window.location.href); var href = Uri( scheme: currentUrl.scheme, host: currentUrl.host, port: currentUrl.port, - fragment: '/payment/result?payment_id=$paymentId', + fragment: '/payment/result?payment_id=$paymentId&action=$action', ).toString(); return await WebStripe.instance.confirmPaymentElement( @@ -22,6 +22,10 @@ Future pay(String paymentId) async { ); } +void closeWindow() { + html.window.close(); +} + class PlatformPaymentElement extends StatelessWidget { const PlatformPaymentElement(this.clientSecret, {super.key}); diff --git a/lib/page/balance/web_payment_proxy.dart b/lib/page/balance/web_payment_proxy.dart new file mode 100644 index 00000000..f82752fa --- /dev/null +++ b/lib/page/balance/web_payment_proxy.dart @@ -0,0 +1,134 @@ +import 'package:askaide/helper/logger.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/enhanced_button.dart'; +import 'package:askaide/page/component/loading.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_stripe/flutter_stripe.dart'; + +import 'web/payment_element.dart' + if (dart.library.js) 'web/payment_element_web.dart'; + +class WebPaymentProxy extends StatefulWidget { + final SettingRepository setting; + final String paymentId; + final String paymentIntent; + final String price; + final String publishableKey; + final String? finishAction; + + const WebPaymentProxy({ + super.key, + required this.setting, + required this.paymentId, + required this.paymentIntent, + required this.price, + required this.publishableKey, + this.finishAction, + }); + + @override + State createState() => _WebPaymentProxyState(); +} + +class _WebPaymentProxyState extends State { + @override + void initState() { + super.initState(); + + Stripe.publishableKey = widget.publishableKey; + Stripe.urlScheme = 'flutterstripe'; + } + + @override + Widget build(BuildContext context) { + var customColors = Theme.of(context).extension()!; + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + 'Stripe', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + elevation: 0, + ), + backgroundColor: customColors.backgroundContainerColor, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + maxWidth: CustomSize.smallWindowSize, + child: Center( + child: FutureBuilder( + future: Stripe.instance.applySettings(), + builder: (context, snapshot) { + if (snapshot.hasError) { + Logger.instance.e('Stripe 初始化失败:${snapshot.error}'); + return Center( + child: Text( + snapshot.error.toString(), + style: const TextStyle(color: Colors.red), + ), + ); + } + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.all(15), + child: Builder( + builder: (context) { + return PlatformPaymentElement( + widget.paymentIntent, + ); + }, + ), + ), + ), + Container( + padding: const EdgeInsets.all(15), + child: EnhancedButton( + title: '确定付款(${widget.price})', + onPressed: () async { + final cancel = BotToast.showCustomLoading( + toastBuilder: (cancel) { + return LoadingIndicator( + message: + AppLocale.processingWait.getString(context), + ); + }, + allowClick: false, + duration: const Duration(seconds: 120), + ); + + try { + await pay( + widget.paymentId, + action: widget.finishAction, + ); + } catch (e) { + Logger.instance.e('支付失败:$e'); + // ignore: use_build_context_synchronously + showErrorMessageEnhanced(context, '请填写完整的支付信息'); + } finally { + cancel(); + } + }, + ), + ) + ], + ); + }), + ), + ), + ); + } +} diff --git a/lib/page/balance/web_payment_result.dart b/lib/page/balance/web_payment_result.dart index a8195f4c..c07f5003 100644 --- a/lib/page/balance/web_payment_result.dart +++ b/lib/page/balance/web_payment_result.dart @@ -3,10 +3,17 @@ import 'package:askaide/repo/api/payment.dart'; import 'package:askaide/repo/api_server.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'web/payment_element.dart' + if (dart.library.js) 'web/payment_element_web.dart'; class WebPaymentResult extends StatefulWidget { final String paymentId; - const WebPaymentResult({super.key, required this.paymentId}); + final String? action; + const WebPaymentResult({ + super.key, + required this.paymentId, + this.action, + }); @override State createState() => _WebPaymentResultState(); @@ -62,10 +69,14 @@ class _WebPaymentResultState extends State { color: customColors.weakLinkColor, ), onPressed: () { - if (context.canPop()) { - context.pop(); + if (widget.action != null && widget.action == 'close') { + closeWindow(); } else { - context.go('/payment'); + if (context.canPop()) { + context.pop(); + } else { + context.go('/payment'); + } } }, ), diff --git a/lib/page/chat/component/room_item.dart b/lib/page/chat/component/room_item.dart index 7627fb4c..c47736dd 100644 --- a/lib/page/chat/component/room_item.dart +++ b/lib/page/chat/component/room_item.dart @@ -238,6 +238,7 @@ class RoomItem extends StatelessWidget { if (room.avatarUrl != null && room.avatarUrl!.startsWith('http')) { return SizedBox( width: 70, + height: 70, child: ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), diff --git a/lib/repo/api/payment.dart b/lib/repo/api/payment.dart index 6d0ace22..defd219d 100644 --- a/lib/repo/api/payment.dart +++ b/lib/repo/api/payment.dart @@ -133,6 +133,7 @@ class StripePaymentCreatedResponse { final String paymentIntent; final String ephemeralKey; final String publishableKey; + final String proxyUrl; StripePaymentCreatedResponse( this.paymentId, @@ -140,6 +141,7 @@ class StripePaymentCreatedResponse { this.paymentIntent, this.ephemeralKey, this.publishableKey, + this.proxyUrl, ); toJson() => { @@ -148,6 +150,7 @@ class StripePaymentCreatedResponse { 'payment_intent': paymentIntent, 'ephemeral_key': ephemeralKey, 'publishable_key': publishableKey, + 'proxy_url': proxyUrl, }; static StripePaymentCreatedResponse fromJson(Map json) { @@ -157,6 +160,7 @@ class StripePaymentCreatedResponse { json['payment_intent'], json['ephemeral_key'], json['publishable_key'], + json['proxy_url'] ?? '', ); } } diff --git a/lib/repo/model/misc.dart b/lib/repo/model/misc.dart index abf76ba9..8f3f4dad 100644 --- a/lib/repo/model/misc.dart +++ b/lib/repo/model/misc.dart @@ -343,6 +343,7 @@ class SignInResp { String token; bool isNewUser; int reward; + bool needBindPhone; SignInResp({ required this.id, @@ -352,6 +353,7 @@ class SignInResp { this.phone, this.isNewUser = false, this.reward = 0, + this.needBindPhone = false, }); toJson() => { @@ -362,10 +364,9 @@ class SignInResp { 'token': token, 'is_new_user': isNewUser, 'reward': reward, + 'need_bind_phone': needBindPhone, }; - bool get needBindPhone => phone == null || phone!.isEmpty; - static SignInResp fromJson(Map json) { return SignInResp( id: json['id'], @@ -375,6 +376,7 @@ class SignInResp { token: json['token'], isNewUser: json['is_new_user'] ?? false, reward: json['reward'] ?? 0, + needBindPhone: json['need_bind_phone'] ?? false, ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 1ec1695c..db432ef0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. # 应用正式发布时,需要同步修改 lib/helper/constant.dart 中的 VERSION 值 -version: 1.0.13+1 +version: 1.0.14+1 environment: sdk: '>=3.0.0 <4.0.0' From d83444877d47ddd201e1b9e998b274b7f972769e Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 14 Mar 2024 17:27:16 +0800 Subject: [PATCH 11/36] =?UTF-8?q?Stripe=20=E6=94=AF=E4=BB=98=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E9=A1=B5=E9=9D=A2=E5=8E=BB=E6=8E=89=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/balance/web_payment_proxy.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/page/balance/web_payment_proxy.dart b/lib/page/balance/web_payment_proxy.dart index f82752fa..e454f713 100644 --- a/lib/page/balance/web_payment_proxy.dart +++ b/lib/page/balance/web_payment_proxy.dart @@ -53,7 +53,7 @@ class _WebPaymentProxyState extends State { appBar: AppBar( toolbarHeight: CustomSize.toolbarHeight, title: const Text( - 'Stripe', + '', style: TextStyle(fontSize: CustomSize.appBarTitleSize), ), centerTitle: true, From 7cf488709d871f8105bc5d26fcbf3594b35ccbed Mon Sep 17 00:00:00 2001 From: mylxsw Date: Fri, 15 Mar 2024 10:29:44 +0800 Subject: [PATCH 12/36] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20android=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99=20AAPT:=20error:=20resource=20android:color/system=5F?= =?UTF-8?q?background=5Fdark=20not=20found.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pubspec.lock | 40 ++++++++++++++++++++-------------------- pubspec.yaml | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index f18090ef..09527594 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -659,10 +659,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: a64c5323ac83ed2b7940d2b6288d160aa1753ff271ba9d9b2a86770414aa3eab + sha256: cb44f7831b23a6bdd0f501718b0d2e8045cbc625a15f668af37ddb80314821db url: "https://pub.dev" source: hosted - version: "0.6.20+1" + version: "0.6.21" flutter_math_fork: dependency: "direct main" description: @@ -691,10 +691,10 @@ packages: dependency: "direct main" description: name: flutter_slidable - sha256: "19ed4813003a6ff4e9c6bcce37e792a2a358919d7603b2b31ff200229191e44c" + sha256: "673403d2eeef1f9e8483bd6d8d92aae73b1d8bd71f382bc3930f699c731bc27c" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.0" flutter_sticky_header: dependency: "direct main" description: @@ -707,10 +707,10 @@ packages: dependency: "direct main" description: name: flutter_stripe - sha256: dfa4f0cf2f64cf82fde57357283819688c3b985c6cd10c26f50dd4a5476e4924 + sha256: bee4046750d813dc77ef1cdc954c8a0d70a21a7e089b86edf3929aebe33921fe url: "https://pub.dev" source: hosted - version: "10.1.0" + version: "10.1.1" flutter_stripe_web: dependency: "direct main" description: @@ -877,10 +877,10 @@ packages: dependency: transitive description: name: in_app_purchase_android - sha256: c94aebe986723b6f4e4d8551d160c6602e73d0b38bf86a59fb054dfeb44bc1e5 + sha256: "996da8020228658c71eddb30f2a2e723d87d5eef77d8007f9206969605e8f803" url: "https://pub.dev" source: hosted - version: "0.3.1" + version: "0.3.2" in_app_purchase_platform_interface: dependency: transitive description: @@ -893,10 +893,10 @@ packages: dependency: transitive description: name: in_app_purchase_storekit - sha256: "601ad13be730ca447a0a80badc0dcb60af0f28cd03a18aaf5314cedab87c06a0" + sha256: e0f860e760488dbd666e0f27e239d128cba744607fc62434dc76c19d1c292439 url: "https://pub.dev" source: hosted - version: "0.3.12" + version: "0.3.13+1" intl: dependency: "direct main" description: @@ -989,10 +989,10 @@ packages: dependency: "direct main" description: name: loading_animation_widget - sha256: "1901682600273a966c34cf44a85fc5355da92a8d08a8a43c11adc4e471993e3a" + sha256: ee3659035528d19145d50cf0107632bf647e7306c88b6a32f35f3bed63f6d728 url: "https://pub.dev" source: hosted - version: "1.2.0+4" + version: "1.2.1" loading_more_list: dependency: "direct main" description: @@ -1030,10 +1030,10 @@ packages: dependency: "direct main" description: name: markdown - sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90" + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 url: "https://pub.dev" source: hosted - version: "7.2.1" + version: "7.2.2" markdown_widget: dependency: "direct main" description: @@ -1756,10 +1756,10 @@ packages: dependency: transitive description: name: stripe_android - sha256: a1ba929247d9accd9d8b201740cc005f66ad2f739ce5323679fa408d5296338c + sha256: "717a541c025f8a8adbb2cbd8e136b424b4910c4812cc08f5c273bef9ca1ee538" url: "https://pub.dev" source: hosted - version: "10.1.0" + version: "10.1.1" stripe_ios: dependency: transitive description: @@ -2052,10 +2052,10 @@ packages: dependency: transitive description: name: web - sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.5.1" web_socket_channel: dependency: "direct main" description: @@ -2076,10 +2076,10 @@ packages: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.3.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index db432ef0..3cf72e3c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -126,7 +126,7 @@ dependencies: media_kit_libs_video: ^1.0.4 path: ^1.8.3 autoscale_tabbarview: ^1.0.2 - flutter_stripe: ^10.1.0 + flutter_stripe: ^10.1.1 flutter_stripe_web: ^5.1.0 stripe_js: ^3.4.0 From 97b9392b1407ec3bc90b4ef3364cfe08787e5b00 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Mon, 18 Mar 2024 00:39:38 +0800 Subject: [PATCH 13/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=89=88=E6=9D=83?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/setting/custom_home_models.dart | 2 +- lib/page/setting/setting_screen.dart | 30 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/page/setting/custom_home_models.dart b/lib/page/setting/custom_home_models.dart index 83b6b4e4..0a49b3e1 100644 --- a/lib/page/setting/custom_home_models.dart +++ b/lib/page/setting/custom_home_models.dart @@ -113,7 +113,7 @@ class _CustomHomeModelsPageState extends State { child: Column( children: [ const MessageBox( - message: '用于设置聊一聊中的常用模型。', + message: '用于设置聊一聊中的常用模型。模型 3 为可选项,长按可重置', type: MessageBoxType.info, ), const SizedBox(height: 10), diff --git a/lib/page/setting/setting_screen.dart b/lib/page/setting/setting_screen.dart index 5b0b450e..7f637a3c 100644 --- a/lib/page/setting/setting_screen.dart +++ b/lib/page/setting/setting_screen.dart @@ -27,6 +27,7 @@ import 'package:askaide/repo/settings_repo.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localization/flutter_localization.dart'; import 'package:go_router/go_router.dart'; @@ -324,6 +325,35 @@ class _SettingScreenState extends State { ), // 社交媒体图标 _buildSocialIcons(context), + // 版权信息 + CustomSettingsSection( + child: Column( + children: [ + Text( + 'Copyright © 2023-${DateTime.now().year}', + style: TextStyle( + color: customColors.weakTextColor, + ), + ), + GestureDetector( + onTap: () { + launchUrlString( + 'https://aidea.aicode.cc', + mode: LaunchMode.externalApplication, + ); + }, + child: Text( + 'Gulu Artificial Intelligence Technology Co., Ltd.', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12, + ), + ), + ), + const SizedBox(height: 15), + ], + ), + ), ]); }, ), From c20cdef8fc623b4b5e8a281cfcafb3bd8c7a0238 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Mon, 18 Mar 2024 14:00:24 +0800 Subject: [PATCH 14/36] =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B0=8F=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/stripe.png | Bin 0 -> 7976 bytes assets/wechat-pay.png | Bin 0 -> 6371 bytes assets/zhifubao.png | Bin 0 -> 9709 bytes lib/page/balance/payment.dart | 123 ++++++++++++++++++++++++++++------ pubspec.yaml | 3 + 5 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 assets/stripe.png create mode 100644 assets/wechat-pay.png create mode 100644 assets/zhifubao.png diff --git a/assets/stripe.png b/assets/stripe.png new file mode 100644 index 0000000000000000000000000000000000000000..aa2a7804aa734fd0e8bafe557e72eeae41f8a85c GIT binary patch literal 7976 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 literal 0 HcmV?d00001 diff --git a/assets/zhifubao.png b/assets/zhifubao.png new file mode 100644 index 0000000000000000000000000000000000000000..ab696f32614635bc40a6dc67d84ef830d6fd7951 GIT binary patch literal 9709 zcmVStO&>uS)ve<0AYj>5AR{$W90N^4L=L-RlQUJ&DC0@ZjPh;=*jPLSYvv5M~MFBAl0-BNIsH z15C~g000{K(ZT*WKal6<?_01!^k@7iDG<<3=fuAC~28EsPoqkpK{9G%|Vj005J}`Hw&=0RYXHq~ibpyyzHQsFW8>#s~laM4*8xut5h5 z!4#~(4xGUqyucR%VFpA%3?#rj5JCpzfE)^;7?wd9RKPme1hudO8lVxH;SjXJF*pt9 z;1XPc>u?taU>Kgl7`%oF1VP9M6Ja4bh!J9r*dopd7nzO(B4J20l7OTj>4+3jBE`sZ zqynizYLQ(?Bl0bB6giDtK>Co|$RIL`{EECsF_eL_Q3KQhbwIhO9~z3rpmWi5G!I>X zmZEFX8nhlgfVQHi(M#xcbO3#dj$?q)F%D*o*1Pf{>6$SWH+$s3q(pv=X`qR|$iJF~TPzlc-O$C3+J1 z#CT#lv5;6stS0Uu9wDA3UMCI{Uz12A4#|?_P6{CkNG+sOq(0IRX`DyT~9-sA|ffUF>wk++Z!kWZ5P$;0Hg6gtI-;!FvmBvPc55=u2?Kjj3apE5$3psG>L zsh-pbs)#zDT1jo7c2F-(3)vyY4>O^>2$gY-Gd%Qm(Z8e zYv>2*=jns=cMJ`N4THx>VkjAF8G9M07`GWOnM|ey)0dgZR4~^v8<}UA514ONSSt1^ zd=-((5|uiYR+WC0=c-gyb5%dpd8!Lkt5pxHURHgkMpd&=fR^vEcAI*_=wwAG2sV%zY%w@v@XU~7=xdm1xY6*0;iwVIXu6TaXrs|dqbIl~ z?uTdNHFy_3W~^@g_pF#!K2~{F^;XxcN!DEJEbDF7 zS8PxlSDOr*I-AS3sI8l=#CDr)-xT5$k15hA^;2%zG3@;83hbKf2JJcaVfH2VZT8O{ z%p4LO);n}Nd~$Sk%yw*Wyz8XlG{dRHsl(}4XB%gsbDi@w7p6;)%MzD%mlsoQr;4X; zpL)xc%+^yMd)ZNTI#eJ*$O)i@o$z8)e??LqN_gLa_%;TM>o2SC_ zkmoO6c3xRt`@J4dvz#WL)-Y|z+r(Soy~}%GIzByR`p)SCKE^%*pL(B%zNWq+-#xw~ ze%5}Oeh2)X`#bu}{g3#+;d$~F@lFL`0l@*~0lk45fwKc^10MvL1f>Tx1&sx}1}_Xg z6+#RN4Ot&@lW)Km@*DYMGu&q^n$Z=?2%QyL8~QNJCQKgI5srq>2;UHXZ>IT7>CCnW zh~P(Th`1kV8JQRPeH1AwGO8}>QM6NZadh`A)~w`N`)9q5@sFvDxjWlxwsLl7tZHmh zY-8-3xPZ8-xPf?w_(k!T5_A(J3GIpG#Ms0=iQ{tu=WLoYoaCBRmULsT<=mpV7v|~C z%bs^USv6UZd^m-e5|^?+<%1wXP%juy<)>~<9TW0|n}ttBzM_qyQL(qUN<5P0omQ3h zINdvaL;7fjPeygdGYL;pD|wL_lDQ-EO;$wK-mK5raoH_7l$?~Dqf!lNmb5F^Ft;eT zPi8AClMUo~=55LwlZVRpxOiFd;3B_8yA~shQx|tGF!j;$toK>JuS&gYLDkTP@C~gS@r~shUu{a>bfJ1` z^^VQ7&C1OKHDNXFTgC{M|V%fo{xK_dk6MK@9S!GZ*1JJzrV5xZBjOk z9!NTH<(q(S+MDf~ceQX@Dh|Ry<-sT4rhI$jQ0Sq~!`#Eo-%($2E^vo}is5J@NVEf|KK?WT&2;PCq@=ncR8z zO#GQ^T~S@VXG71PKNocFOt)Y6$@AXlk6rM*aP%VgV%sIRORYVwJx6|U{ozQjTW{-S z_si{9Jg#)~P3t?+@6&(!YQWWV*Z9{iU7vZq@5byKw{9lg9JnRA_4s!7?H6|n?o8ZW zdXIRo{Jz@#>IeD{>VLHUv1Pz*;P_y`V9&!@5AO~Mho1hF|I>%z(nrik)gwkDjgOrl z9~%uCz4Bzvli{bbrxVZ0epdf^>vOB;-~HnIOV3#R*zgPai_gEVd8zYq@2jb=I>#f& zAH2?aJ@KaetJA0Vt^ibO4W}3~3(XWB3^m{6u2+;sdgRE4v z91}IBBpOSy`Sgrp-pAbn3g8wPYN!dfGh*#n84+QBW+Yv zws7CuRowQK89cURD);4@=&81e;6iFMlox3l6lH?T!}JH=;L&%Fuoy4o=72d(gyPp# zlCbzS8U6D!%O~;TS~I|Ylky5(Wry{(Wl9XGOZByHFDXl8`<}6 zC5v;@p*RnWsxFk#L{Jb#IZ&7fhng67+eS9Mx{o_6iXbx;y#B%47*H@iKV+pyBU=t} z`wl= z>0{PrWQceMYfNYKp(@bpfet&&n#|#wmauf?=`>Hx@Bj4!3I<^5L%gtk9~Wht!IY$r zDyJ%n0)9VOEHGsppMCNZDzZ}hf35NP-6#G+Rp7KD*!CIMZ{N>FS!P*6>tZ=|(KHcF zegRZBGVNbp;_;i7aNSX>81;@v+4fnV5`2DHf<5{UmpuLk&u3vNW|gFmn;PRoXO4)IT|4tC5h z;~8sLpXFY8>$njn+XR%;%dH53(Q(B{`b-Bl-{4A1W3!n$@Qnlp8===9BLT`ts3yZJ?ZC+uwm^!fI1W=rIwa8C8|QqP9+8n88B; zD3G5oH`iELNot6>rLKdLU3E-1R#`a5<|NmY9Ph4;JcR-?QZer=VwH% zYYC6X2klN)sFp5f7zPcaI(6u9LTOQCV(Ib7h&0wRAd(GW@1;QP?4issMn1gT3#B=c zwJ{dvE&Y*ffLY(F(Mcg5zSb==#dc6h*`CDlaf9LCcHY4kz{}#HwIPH@QsxL zMkg{f&{RdwNYn`tg(1>RbaYNe7mUuZ&;_G2EOf!>3=3T_I>SO2jLxvo1*0=8V&-|NT7h_(<~!lo04boM;@6k6=J__XL#Wpr4W`c41cc=7qlaV5iqgV!n#caKj7N|4x!0VE>5RZg8ryB|~;9K*^8qPo5f1iV$i5A*5QA@R2m)23VrYkP#B7A| z2R=~20LAuVfyD$<@*-Vjyk(he518mA8DQO<*q(FiVd(8i48g>G(yImx zVAXB$?nz?Of+0biws9AX&fwIwL$gDiw~0X91>@HwYOE|mAJ3`Ejv8=x#Md)^ zJaM1HBpbw&{l^brqFKTRP6ZSN?Az3=Elx^R>iXFu~fud4Vrw6fBfN!fJ)3i($#s@Y{HKAJo=C zeo^%L6)ABSOpsHqlBXNi&Wx;yXLkWUFe-^t(*IPuObLMoV34G_aOv^DmP$y+bO+%qj`wZt`n^ zN#n_PmeLm&l4!$p5I;aKe1BPF?QE|GOo=zTK%4}lAbG)EE^ze%9>mb426|+me}jw< zxhh^nP=>&Jk|8+>QjOwGj@J^s-45d>!PN`HZ{w&H{=O&hIEq@&qDM>wqbQQ0*Wm<$ z0x>~pK9o-um%x-fD9VDuOsTtavhT$22fGWpT~eE+ts7eGU~xcAyX>=U=>oe0a3O*- z%3(;7I2Kd#$eGwx6};_m)#}Ki%`WWX6EP*DgA z%V6F_m^}dsqg2<#=7joosBMSCt+LN@txd{{Si7O211v4b2$c%y>5!f*7dIM1zoQpS z`EcXn@Y`^E;ScXaQf^|31x83P230Pg%K`=C;F}l1H|D{DvXQHll$$2US>wL=w;qpd zwfs>H>^KU$8(>c(v^EpiZ&$JylZUZ8+wrIhblYIne3)Pk|1&)N7Bn1%qB77Dv@A+g z1*58Rm$WuOS}uHV4cxg3O0%PRmf>Scf-{QcxGFHeIAW1Vw)d;yqhqkY9&iE~kdqDs0I+q#3wvSX$FRK$S{i|5$j$~+ z3fLN9$y~T_M)>FZs0I#v2Iiu~9$g>;!30MZOBGzU3ZA|;n%znqa?@pQvi@vYdA+g^ zp7|KwKL(xkfDeAXCbDxpv=z`GMNQn*QIN0-3Mqi5$mDj}Y}k7Hi1aO?`J@*9_#XI; z@bJ3u+xfH}X5R%_W-&Y_IN=o(QVh^i3+K;=&9@H!{eC|jX_KXHLx(JTyIiv54(>mh zWfB8kW-8>TLrFH|n8NAp$S`N39FcO(UjR)$_h{I>bl8G1sLPg z;l(|$yIu@zj&8*2t089pJNRsqbP2$OT+ z^deY2Lj;v*-1Ib5?STBV;@y+sF)YD!xq%e8e~4AVwj=P(-$Qc^7z&|e3iy3}qeiqa zs4~aNObtxL5$EI^`v5oKgCCpW>@rw=rnn~(W%Mb@h6&T5t_^TOvRUS6(eiDL6d|vY z3@S9$!Mf$}+;;|k-N&^s|878mlHxw0!~;c<5y)W&dLXj^E;s|$&Vq~Q^i8nig$BH` z7ykOG{M*tJ_(K|GrHM@|!NlVTSuk#&M3e2jOXdpw@j(rI`9W~Hpd>#r>X|@a;FY}> zoE?A<$|i|h;DXa-wG;0&msUIc{UB^P0DBtXU~9n3p9iO`u zoBDsv?s}MW7hr(W0`Mk?SWYH5;k^dN$S8uFm%@gniD%<^w+jC6Q+V?*?5agZ9z~YtdFfyrS@%L{f@!tE@)_`E zKUQ50n0+toJqm@n3Gtkb2!kpSdTuKejEA|!aMv0*XL7uI_C-EA20LqIIu0#CZ8qB*CRyNKrfs-z!&!VA=qthsBQ$jQn|_;Mez(N7!5#y@dFIaFYg0HgfOz_Of5^V1{@!d* z12HPzFngaMsET;Rt<~_=_79&Pgh`1=8{v?3uV z$&i&5C@rTALofr)Q7Q`IojrZdztM)Gi1E(W4A-xP$F7X5y|=4i-6Jq#0<2#IS4NOF z8%xUaVST=cr^YHi!CITt2!5jy>=wWnf?yN?zeL6L$D%3lWH9(?lqn{-{hjS7+;9mz z`pwAN>+!(({{}8Qyx9(K?uLiA!nNnZbxTH1{k}cZ+!-@9SB7*3gD9v z%Klh&rlg44U6477Ccg$1>^;!k0GFO0xmWGk*IW{Z}p+1bN0A5LS?~n00u)G3#tchEO<7A8muyjIqC)~OYHeMfjo8S2(y!tK_ zl!$x8AE>Qcln;dyV1EN#`3TIpN5oTSi~OANAhbD*LCnwtarHuYb-UbAiC&?|V1ULJ zK!w-tfD6uyyv;TL2`|0{`IEjFQ5gKWI2U{x?5>6HRl-m6;gZ>K?c&I4;l-MeuCFlz zwjL3$bbow(F3g_?ZH;n45|QA(Oii_rodMhKjE-1te;!_Z9rDWtH^2KenZp$2LeV&I z`QZ;+;M{xR(#NDk{AeH~!Q`YtW1X0r2jb6H0m+hIZA>uH7!2Zxw$#Fkxp3g;u(Uk# zb{}~Q9(nS+MDSSa2__c~oLx5}D8fs1ymHI)5%~{_eo9 z+ja!b|Bc*DMdtXYP6Vq-*cu@tAAYq4ZeAXpwtu(@?t2+bnUIqn*=JQ%2_?0+0Y+Fk z6IPrC|G02qA6}doMu?^#I$Gepy9ammZ#x3Ze+Hz*FHAF72d~KrxZsj=;K6m#3yS*o zAK|GNA#;-WZK8E!s6m^M4d{WaLb!Sn+<88X%Zbi8A|!Ods46r!!O~fPM9zm{_QfETtKbxPnm?Xz7qi zu=Rn^ivMl@41W2lM8ne!26J=*dV(hX_CPSVk_G2iz-=pG_4M%D?T^D2xZpQXQwMpa zGP1-voI_Q`c-mzHl3{WoTy-|wzA}0@MFCHYwjDP730~O&#!M*8PAst;PjH^o?gW=r=87vSWLbXW(x`9k9G+l6E@qbt97o~D zSHnFQMYUsb0X%7;KEl$aAI)pxik0XIl%JJ2Py^ENDno6d{ao)ej1 zAYl9OKzjo$nhXE_b@20l!^FHUxN1L(KV_JMR1{1ACAGq&GKtpu-im0n96b&-!+*aI|NQ~9G)P_l z!3sB@YJ9#d?*zJ`ummQh0svX@gjqKW%`$jj*d4a6@{oRIEA`<|xr1 zC>(1yc&w0C02j@KbEnE9EBD0mCst+pFSNZ?ZOj-bvoRVS@@q2j(j4-;^gKyFT{ca& z!l@{P$@$^=M!bHBazAE+{Y~(34eYFeL#^PqBN0C)$juCYx011fK^0qAmksbqrPK{e z#UL1XTpd+r|Eu3x7l~vB2qut}bLFtYpZ@lmx5t0@**QC`iFhPiS;yvmgca%t9SI|73std1(`eMm~ft1!aM4uT=?1y{@s*3 za2kou*hK?eZdiFbPs|#JPc^8pbQ-UmR!mcSw?6dioQTs6*=g|Q)3`s$2+e%Q6SlXde#46J<>`}L6$BY9SN-W`r!{( zGIL@s`&?d7chta#N1?I>|IAYE_xp6Q=*Z~eaKhp#Jkjf6-`hvTimvQw5Oo+;NHLOp z(WA8NuP3M2teertDykwbf^H{lypi&8IaKuq7DUEfb@GE>19Lj=HM977Wiwmsy%I;O zi)L)0D6(4acEH`2aNokoRCV@1cEE~m{OF{r0cE+ozIHZuZ2XW1Qj7_+i-t}N2>SZk zZE)69HZ8B43Bh`2K1hSU8yqTB^#)QGTjI%s4@5ms%rX_D{0=89pT^O3bGW4>i(hv3aN`@5T+!m7!qzR~N;b;t4XUJ`>Wn;I zzdQ}Rep%)EHA$%{&8GS6$vj=2&l6>N?4LVc_C&CC2Lk1Xk?lF`xOxQR9G*QR4NJ;q{T%<3ZKXC(0v { return; } + // 根据当前平台不通,调用不同的支付方式 if (PlatformTool.isAndroid()) { handlePaymentForAndroid( - state, context, customColors); + state, + context, + customColors, + ); } else if (PlatformTool.isIOS()) { _startPaymentLoading(); try { @@ -410,23 +414,39 @@ class _PaymentScreenState extends State { openListSelectDialog( context, [ - SelectorItem(const Text('支付宝扫码'), 'web'), - SelectorItem(const Text('支付宝手机版'), 'wap'), + SelectorItem( + const PaymentMethodItem( + title: Text('支付宝扫码'), + image: 'assets/zhifubao.png', + ), + 'web', + ), + SelectorItem( + const PaymentMethodItem( + title: Text('支付宝手机版'), + image: 'assets/zhifubao.png', + ), + 'wap', + ), if (enableStripe) SelectorItem( - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Stripe'), - const SizedBox(width: 5), - Text( - '(${localProduct.retailPriceUSDText})', - style: TextStyle( - color: customColors.paymentItemTitleColor?.withOpacity(0.5), - fontSize: 12, + PaymentMethodItem( + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Stripe'), + const SizedBox(width: 5), + Text( + '(${localProduct.retailPriceUSDText})', + style: TextStyle( + color: + customColors.paymentItemTitleColor?.withOpacity(0.5), + fontSize: 12, + ), ), - ), - ], + ], + ), + image: 'assets/stripe.png', ), 'stripe', ), @@ -450,6 +470,7 @@ class _PaymentScreenState extends State { ); } + /// 处理 PC 端支付 void handlePaymentForPC( PaymentAppleProductsLoaded state, BuildContext context, @@ -461,10 +482,25 @@ class _PaymentScreenState extends State { openListSelectDialog( context, [ - if (Ability().enableOtherPay) SelectorItem(const Text('支付宝'), 'alipay'), + // SelectorItem( + // const PaymentMethodItem( + // title: Text('微信支付'), + // image: 'assets/wechat-pay.png', + // ), + // 'alipay', + // ), + if (Ability().enableOtherPay) + SelectorItem( + const PaymentMethodItem( + title: Text('支付宝'), + image: 'assets/zhifubao.png', + ), + 'alipay', + ), if (enableStripe) SelectorItem( - Row( + PaymentMethodItem( + title: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Stripe'), @@ -479,7 +515,10 @@ class _PaymentScreenState extends State { ), ], ), - 'stripe'), + image: 'assets/stripe.png', + ), + 'stripe', + ), ], (value) { _startPaymentLoading(); @@ -496,7 +535,7 @@ class _PaymentScreenState extends State { return true; }, title: '请选择支付方式', - heightFactor: 0.3, + heightFactor: 0.4, ); } @@ -511,10 +550,18 @@ class _PaymentScreenState extends State { openListSelectDialog( context, [ - if (Ability().enableOtherPay) SelectorItem(const Text('支付宝'), 'alipay'), + if (Ability().enableOtherPay) + SelectorItem( + const PaymentMethodItem( + title: Text('支付宝'), + image: 'assets/zhifubao.png', + ), + 'alipay', + ), if (enableStripe) SelectorItem( - Row( + PaymentMethodItem( + title: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Stripe'), @@ -529,7 +576,10 @@ class _PaymentScreenState extends State { ), ], ), - 'stripe'), + image: 'assets/stripe.png', + ), + 'stripe', + ), ], (value) { _startPaymentLoading(); @@ -840,3 +890,32 @@ class _PaymentScreenState extends State { print("-----------------"); } } + +/// 支付方式选择项 +class PaymentMethodItem extends StatelessWidget { + final Widget title; + final String? image; + + const PaymentMethodItem({super.key, required this.title, this.image}); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (image != null) ...[ + ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Image.asset( + image!, + width: 20, + height: 20, + ), + ), + const SizedBox(width: 10), + ], + title, + ], + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 3cf72e3c..7ac201f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -194,6 +194,9 @@ flutter: - assets/xiaohongshu.png - assets/play.png - assets/text-to-video.gif + - assets/wechat-pay.png + - assets/zhifubao.png + - assets/stripe.png # - images/a_dot_ham.jpeg From 30b5cd9eb59dde6157e4106916a7102050889cd5 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 20 Mar 2024 00:16:17 +0800 Subject: [PATCH 15/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B8=A0=E9=81=93?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bloc/channel_bloc.dart | 56 +++++ lib/bloc/channel_event.dart | 31 +++ lib/bloc/channel_state.dart | 25 ++ lib/main.dart | 62 +++++ lib/page/admin/channels.dart | 202 +++++++++++++++ lib/page/admin/channels_add.dart | 321 ++++++++++++++++++++++++ lib/page/admin/channels_edit.dart | 355 +++++++++++++++++++++++++++ lib/page/setting/setting_screen.dart | 12 + lib/repo/api/admin/channels.dart | 155 ++++++++++++ lib/repo/api/admin/models.dart | 184 ++++++++++++++ lib/repo/api_server.dart | 100 ++++++++ 11 files changed, 1503 insertions(+) create mode 100644 lib/bloc/channel_bloc.dart create mode 100644 lib/bloc/channel_event.dart create mode 100644 lib/bloc/channel_state.dart create mode 100644 lib/page/admin/channels.dart create mode 100644 lib/page/admin/channels_add.dart create mode 100644 lib/page/admin/channels_edit.dart create mode 100644 lib/repo/api/admin/channels.dart create mode 100644 lib/repo/api/admin/models.dart diff --git a/lib/bloc/channel_bloc.dart b/lib/bloc/channel_bloc.dart new file mode 100644 index 00000000..360dedc1 --- /dev/null +++ b/lib/bloc/channel_bloc.dart @@ -0,0 +1,56 @@ +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; + +part 'channel_event.dart'; +part 'channel_state.dart'; + +class ChannelBloc extends Bloc { + ChannelBloc() : super(ChannelInitial()) { + /// 加载所有渠道 + on((event, emit) async { + final channels = await APIServer().adminChannels(); + emit(ChannelsLoaded(channels)); + }); + + /// 加载单个渠道 + on((event, emit) async { + final channel = await APIServer().adminChannel(id: event.channelId); + emit(ChannelLoaded(channel)); + }); + + /// 创建渠道 + on((event, emit) async { + try { + await APIServer().adminCreateChannel(event.req); + emit(ChannelOperationResult(true, '创建成功')); + } catch (e) { + emit(ChannelOperationResult(false, e.toString())); + } + }); + + /// 更新渠道 + on((event, emit) async { + try { + await APIServer().adminUpdateChannel( + id: event.channelId, + req: event.req, + ); + emit(ChannelOperationResult(true, '更新成功')); + } catch (e) { + emit(ChannelOperationResult(false, e.toString())); + } + }); + + /// 删除渠道 + on((event, emit) async { + try { + await APIServer().adminDeleteChannel(id: event.channelId); + emit(ChannelOperationResult(true, '删除成功')); + } catch (e) { + emit(ChannelOperationResult(false, e.toString())); + } + }); + } +} diff --git a/lib/bloc/channel_event.dart b/lib/bloc/channel_event.dart new file mode 100644 index 00000000..a9897db0 --- /dev/null +++ b/lib/bloc/channel_event.dart @@ -0,0 +1,31 @@ +part of 'channel_bloc.dart'; + +@immutable +sealed class ChannelEvent {} + +class ChannelsLoadEvent extends ChannelEvent {} + +class ChannelLoadEvent extends ChannelEvent { + final int channelId; + + ChannelLoadEvent(this.channelId); +} + +class ChannelCreateEvent extends ChannelEvent { + final AdminChannelAddReq req; + + ChannelCreateEvent(this.req); +} + +class ChannelUpdateEvent extends ChannelEvent { + final int channelId; + final AdminChannelUpdateReq req; + + ChannelUpdateEvent(this.channelId, this.req); +} + +class ChannelDeleteEvent extends ChannelEvent { + final int channelId; + + ChannelDeleteEvent(this.channelId); +} diff --git a/lib/bloc/channel_state.dart b/lib/bloc/channel_state.dart new file mode 100644 index 00000000..5d51476d --- /dev/null +++ b/lib/bloc/channel_state.dart @@ -0,0 +1,25 @@ +part of 'channel_bloc.dart'; + +@immutable +sealed class ChannelState {} + +final class ChannelInitial extends ChannelState {} + +class ChannelsLoaded extends ChannelState { + final List channels; + + ChannelsLoaded(this.channels); +} + +class ChannelLoaded extends ChannelState { + final AdminChannel channel; + + ChannelLoaded(this.channel); +} + +class ChannelOperationResult extends ChannelState { + final bool success; + final String message; + + ChannelOperationResult(this.success, this.message); +} diff --git a/lib/main.dart b/lib/main.dart index df4b5126..3725abf3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,8 @@ +import 'package:askaide/bloc/channel_bloc.dart'; import 'package:askaide/helper/path.dart'; +import 'package:askaide/page/admin/channels.dart'; +import 'package:askaide/page/admin/channels_add.dart'; +import 'package:askaide/page/admin/channels_edit.dart'; import 'package:askaide/page/balance/web_payment_proxy.dart'; import 'package:askaide/page/balance/web_payment_result.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; @@ -1058,6 +1062,64 @@ class MyApp extends StatefulWidget { )); }, ), + + /// 管理员接口 + GoRoute( + name: 'admin-channels', + path: '/admin/channels', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ChannelBloc(), + ), + ], + child: ChannelsPage(setting: settingRepo), + ), + ); + }, + ), + GoRoute( + name: 'admin-channels-create', + path: '/admin/channels/create', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ChannelBloc(), + ), + ], + child: ChannelAddPage(setting: settingRepo), + ), + ); + }, + ), + GoRoute( + name: 'admin-channels-edit', + path: '/admin/channels/edit/:id', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + final channelId = int.parse(state.pathParameters['id']!); + + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ChannelBloc(), + ), + ], + child: ChannelEditPage( + setting: settingRepo, + channelId: channelId, + ), + ), + ); + }, + ), ], ) ], diff --git a/lib/page/admin/channels.dart b/lib/page/admin/channels.dart new file mode 100644 index 00000000..f6c76348 --- /dev/null +++ b/lib/page/admin/channels.dart @@ -0,0 +1,202 @@ +import 'package:askaide/bloc/channel_bloc.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_initicon/flutter_initicon.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:go_router/go_router.dart'; + +class ChannelsPage extends StatefulWidget { + final SettingRepository setting; + const ChannelsPage({ + super.key, + required this.setting, + }); + + @override + State createState() => _ChannelsPageState(); +} + +class _ChannelsPageState extends State { + @override + void initState() { + context.read().add(ChannelsLoadEvent()); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '渠道管理', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + actions: [ + IconButton( + icon: const Icon(Icons.add), + onPressed: () { + context.push('/admin/channels/create').then((value) { + context.read().add(ChannelsLoadEvent()); + }); + }, + ), + ], + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: RefreshIndicator( + color: customColors.linkColor, + onRefresh: () async { + context.read().add(ChannelsLoadEvent()); + }, + displacement: 20, + child: BlocConsumer( + listenWhen: (previous, current) => + current is ChannelOperationResult, + listener: (context, state) { + if (state is ChannelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.read().add(ChannelsLoadEvent()); + } else { + showErrorMessage(state.message); + } + } + }, + buildWhen: (previous, current) => current is ChannelsLoaded, + builder: (context, state) { + if (state is ChannelsLoaded) { + return SafeArea( + top: false, + child: ListView.builder( + padding: const EdgeInsets.all(5), + itemCount: state.channels.length, + itemBuilder: (context, index) { + final channel = state.channels[index]; + + return buildChannelItem(context, customColors, channel); + }, + ), + ); + } + + return const Center( + child: CircularProgressIndicator(), + ); + }, + ), + ), + ), + ); + } + + Widget buildChannelItem( + BuildContext context, + CustomColors customColors, + AdminChannel channel, + ) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(customColors.borderRadius ?? 8), + ), + child: Slidable( + endActionPane: ActionPane( + motion: const ScrollMotion(), + children: [ + const SizedBox(width: 10), + SlidableAction( + label: AppLocale.delete.getString(context), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(customColors.borderRadius ?? 8), + bottomLeft: Radius.circular(customColors.borderRadius ?? 8), + topRight: Radius.circular(customColors.borderRadius ?? 8), + bottomRight: Radius.circular(customColors.borderRadius ?? 8), + ), + backgroundColor: Colors.red, + icon: Icons.delete, + onPressed: (_) { + openConfirmDialog( + context, + AppLocale.confirmToDeleteRoom.getString(context), + () => context + .read() + .add(ChannelDeleteEvent(channel.id!)), + danger: true, + ); + }, + ), + ], + ), + child: Material( + borderRadius: + BorderRadius.all(Radius.circular(customColors.borderRadius ?? 8)), + color: customColors.columnBlockBackgroundColor, + child: InkWell( + borderRadius: BorderRadius.all( + Radius.circular(customColors.borderRadius ?? 8)), + onTap: () { + context.push('/admin/channels/edit/${channel.id}').then((value) { + context.read().add(ChannelsLoadEvent()); + }); + }, + child: Stack( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 渠道头像 + Initicon( + text: channel.name.split('、').join(' '), + size: 50, + backgroundColor: Colors.grey.withAlpha(100), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8), + ), + ), + // 渠道名称 + Expanded( + child: Container( + padding: const EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + channel.name, + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/page/admin/channels_add.dart b/lib/page/admin/channels_add.dart new file mode 100644 index 00000000..0e39d1aa --- /dev/null +++ b/lib/page/admin/channels_add.dart @@ -0,0 +1,321 @@ +import 'package:askaide/bloc/channel_bloc.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/column_block.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/enhanced_button.dart'; +import 'package:askaide/page/component/enhanced_input.dart'; +import 'package:askaide/page/component/enhanced_textfield.dart'; +import 'package:askaide/page/component/item_selector_search.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:go_router/go_router.dart'; + +class ChannelAddPage extends StatefulWidget { + final SettingRepository setting; + const ChannelAddPage({ + super.key, + required this.setting, + }); + + @override + State createState() => _ChannelAddPageState(); +} + +class _ChannelAddPageState extends State { + // 渠道类型 + List channelTypes = []; + + final TextEditingController nameController = TextEditingController(); + final TextEditingController typeController = TextEditingController(); + final TextEditingController serverController = TextEditingController(); + final TextEditingController secretController = TextEditingController(); + + /// 当前选中的渠道类型 + String? selectedChannelType; + + /// 用于控制是否显示高级选项 + bool showAdvancedOptions = false; + + /// 是否使用代理 + bool usingProxy = false; + + /// 是否是 Azure API + bool openaiAzure = false; + + /// OpenAI Azure API 版本 + final TextEditingController azureAPIVersionController = + TextEditingController(); + + @override + void dispose() { + nameController.dispose(); + typeController.dispose(); + serverController.dispose(); + secretController.dispose(); + azureAPIVersionController.dispose(); + + super.dispose(); + } + + @override + void initState() { + // 加载渠道类型 + APIServer().adminChannelTypes().then((value) { + if (context.mounted) { + setState(() { + channelTypes = value.where((e) => e.dynamicType).toList(); + }); + } + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '新增渠道', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: BlocListener( + listenWhen: (previous, current) => current is ChannelOperationResult, + listener: (context, state) { + if (state is ChannelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.pop(); + } else { + showErrorMessage(state.message); + } + } + }, + child: Container( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + ColumnBlock( + children: [ + EnhancedTextField( + labelText: '渠道名称', + customColors: customColors, + controller: nameController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入渠道名称', + maxLength: 100, + showCounter: false, + ), + EnhancedInput( + title: Text( + '类型', + style: TextStyle( + color: customColors.textfieldLabelColor, + fontSize: 16, + ), + ), + value: Text( + buildSelectedChannelTypeText(), + style: TextStyle( + color: customColors.textfieldValueColor, + fontSize: 16, + ), + ), + onPressed: () { + openListSelectDialog( + context, + channelTypes + .map((e) => SelectorItem(Text(e.text), e.name)) + .toList(), + (value) { + setState(() { + selectedChannelType = value.value; + }); + return true; + }, + heightFactor: 0.5, + value: selectedChannelType, + ); + }, + ), + EnhancedTextField( + labelText: '服务器', + customColors: customColors, + controller: serverController, + textAlignVertical: TextAlignVertical.top, + hintText: 'https://api.openai.com/v1', + maxLength: 255, + showCounter: false, + ), + EnhancedTextField( + labelText: '鉴权密钥', + customColors: customColors, + controller: secretController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入鉴权密钥', + maxLength: 255, + obscureText: true, + showCounter: false, + ), + ], + ), + // 高级选项 + if (showAdvancedOptions) + ColumnBlock( + innerPanding: 5, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '使用代理', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: usingProxy, + onChanged: (value) { + setState(() { + usingProxy = value; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Azure 模式', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: openaiAzure, + onChanged: (value) { + setState(() { + openaiAzure = value; + }); + }, + ), + ], + ), + EnhancedTextField( + labelText: 'API 版本', + customColors: customColors, + controller: azureAPIVersionController, + textAlignVertical: TextAlignVertical.top, + hintText: '2023-05-15', + maxLength: 30, + showCounter: false, + ), + ], + ), + const SizedBox(height: 15), + Row( + children: [ + EnhancedButton( + title: showAdvancedOptions + ? AppLocale.simpleMode.getString(context) + : AppLocale.professionalMode.getString(context), + width: 120, + backgroundColor: Colors.transparent, + color: customColors.weakLinkColor, + fontSize: 15, + icon: Icon( + showAdvancedOptions + ? Icons.unfold_less + : Icons.unfold_more, + color: customColors.weakLinkColor, + size: 15, + ), + onPressed: () { + setState(() { + showAdvancedOptions = !showAdvancedOptions; + }); + }, + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: EnhancedButton( + title: AppLocale.save.getString(context), + onPressed: onSubmit, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + + /// 提交 + void onSubmit() { + if (nameController.text.isEmpty) { + showErrorMessage('请输入渠道名称'); + return; + } + + if (selectedChannelType == null) { + showErrorMessage('请选择渠道类型'); + return; + } + + if (serverController.text.isEmpty) { + showErrorMessage('请输入服务器地址'); + return; + } + + if (!serverController.text.startsWith('http://') && + !serverController.text.startsWith('https://')) { + showErrorMessage('服务器地址格式不正确'); + return; + } + + final req = AdminChannelAddReq( + name: nameController.text, + type: selectedChannelType!, + server: serverController.text, + secret: secretController.text, + meta: AdminChannelMeta( + usingProxy: usingProxy, + openaiAzure: openaiAzure, + openaiAzureAPIVersion: azureAPIVersionController.text, + ), + ); + + context.read().add(ChannelCreateEvent(req)); + } + + /// 生成选中的渠道类型文本 + String buildSelectedChannelTypeText() { + if (selectedChannelType == null) { + return '请选择'; + } + + return channelTypes + .firstWhere((element) => element.name == selectedChannelType) + .text; + } +} diff --git a/lib/page/admin/channels_edit.dart b/lib/page/admin/channels_edit.dart new file mode 100644 index 00000000..0c503197 --- /dev/null +++ b/lib/page/admin/channels_edit.dart @@ -0,0 +1,355 @@ +import 'package:askaide/bloc/channel_bloc.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/column_block.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/enhanced_button.dart'; +import 'package:askaide/page/component/enhanced_input.dart'; +import 'package:askaide/page/component/enhanced_textfield.dart'; +import 'package:askaide/page/component/item_selector_search.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; + +class ChannelEditPage extends StatefulWidget { + final SettingRepository setting; + final int channelId; + const ChannelEditPage({ + super.key, + required this.setting, + required this.channelId, + }); + + @override + State createState() => _ChannelEditPageState(); +} + +class _ChannelEditPageState extends State { + // 渠道类型 + List channelTypes = []; + + final TextEditingController nameController = TextEditingController(); + final TextEditingController typeController = TextEditingController(); + final TextEditingController serverController = TextEditingController(); + final TextEditingController secretController = TextEditingController(); + + /// 当前选中的渠道类型 + String? selectedChannelType; + + /// 用于控制是否显示高级选项 + bool showAdvancedOptions = false; + + /// 是否使用代理 + bool usingProxy = false; + + /// 是否是 Azure API + bool openaiAzure = false; + + /// OpenAI Azure API 版本 + final TextEditingController azureAPIVersionController = + TextEditingController(); + + /// 是否锁定编辑 + bool editLocked = true; + + @override + void dispose() { + nameController.dispose(); + typeController.dispose(); + serverController.dispose(); + secretController.dispose(); + azureAPIVersionController.dispose(); + + super.dispose(); + } + + @override + void initState() { + // 加载渠道类型 + APIServer().adminChannelTypes().then((value) { + if (context.mounted) { + setState(() { + channelTypes = value.where((e) => e.dynamicType).toList(); + }); + } + }); + + // 加载渠道信息 + context.read().add(ChannelLoadEvent(widget.channelId)); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '编辑渠道', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: BlocListener( + listenWhen: (previous, current) => + current is ChannelOperationResult || current is ChannelLoaded, + listener: (context, state) { + if (state is ChannelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context + .read() + .add(ChannelLoadEvent(widget.channelId)); + } else { + showErrorMessage(state.message); + } + } else if (state is ChannelLoaded) { + nameController.text = state.channel.name; + selectedChannelType = state.channel.type; + serverController.text = state.channel.server ?? ''; + secretController.text = state.channel.secret ?? ''; + usingProxy = state.channel.meta?.usingProxy ?? false; + openaiAzure = state.channel.meta?.openaiAzure ?? false; + azureAPIVersionController.text = + state.channel.meta?.openaiAzureAPIVersion ?? ''; + + setState(() { + editLocked = false; + }); + } + }, + child: Container( + padding: const EdgeInsets.all(10), + child: Column( + children: [ + ColumnBlock( + children: [ + EnhancedTextField( + labelText: '渠道名称', + customColors: customColors, + controller: nameController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入渠道名称', + maxLength: 100, + showCounter: false, + ), + EnhancedInput( + title: Text( + '类型', + style: TextStyle( + color: customColors.textfieldLabelColor, + fontSize: 16, + ), + ), + value: Text( + buildSelectedChannelTypeText(), + style: TextStyle( + color: customColors.textfieldValueColor, + fontSize: 16, + ), + ), + onPressed: () { + openListSelectDialog( + context, + channelTypes + .map((e) => SelectorItem(Text(e.text), e.name)) + .toList(), + (value) { + setState(() { + selectedChannelType = value.value; + }); + return true; + }, + heightFactor: 0.5, + value: selectedChannelType, + ); + }, + ), + EnhancedTextField( + labelText: '服务器', + customColors: customColors, + controller: serverController, + textAlignVertical: TextAlignVertical.top, + hintText: 'https://api.openai.com/v1', + maxLength: 255, + showCounter: false, + ), + EnhancedTextField( + labelText: '鉴权密钥', + customColors: customColors, + controller: secretController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入鉴权密钥', + maxLength: 255, + obscureText: true, + showCounter: false, + ), + ], + ), + // 高级选项 + if (showAdvancedOptions) + ColumnBlock( + innerPanding: 5, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '使用代理', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: usingProxy, + onChanged: (value) { + setState(() { + usingProxy = value; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Azure 模式', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: openaiAzure, + onChanged: (value) { + setState(() { + openaiAzure = value; + }); + }, + ), + ], + ), + EnhancedTextField( + labelText: 'API 版本', + customColors: customColors, + controller: azureAPIVersionController, + textAlignVertical: TextAlignVertical.top, + hintText: '2023-05-15', + maxLength: 30, + showCounter: false, + ), + ], + ), + const SizedBox(height: 15), + Row( + children: [ + EnhancedButton( + title: showAdvancedOptions + ? AppLocale.simpleMode.getString(context) + : AppLocale.professionalMode.getString(context), + width: 120, + backgroundColor: Colors.transparent, + color: customColors.weakLinkColor, + fontSize: 15, + icon: Icon( + showAdvancedOptions + ? Icons.unfold_less + : Icons.unfold_more, + color: customColors.weakLinkColor, + size: 15, + ), + onPressed: () { + setState(() { + showAdvancedOptions = !showAdvancedOptions; + }); + }, + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: EnhancedButton( + title: AppLocale.save.getString(context), + onPressed: onSubmit, + icon: editLocked + ? const Icon(Icons.lock, + color: Colors.white, size: 16) + : const Icon(Icons.lock_open, + color: Colors.white, size: 16), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + + /// 提交 + void onSubmit() { + if (editLocked) { + return; + } + + if (nameController.text.isEmpty) { + showErrorMessage('请输入渠道名称'); + return; + } + + if (selectedChannelType == null) { + showErrorMessage('请选择渠道类型'); + return; + } + + if (serverController.text.isEmpty) { + showErrorMessage('请输入服务器地址'); + return; + } + + if (!serverController.text.startsWith('http://') && + !serverController.text.startsWith('https://')) { + showErrorMessage('服务器地址格式不正确'); + return; + } + + final req = AdminChannelUpdateReq( + name: nameController.text, + type: selectedChannelType!, + server: serverController.text, + secret: secretController.text, + meta: AdminChannelMeta( + usingProxy: usingProxy, + openaiAzure: openaiAzure, + openaiAzureAPIVersion: azureAPIVersionController.text, + ), + ); + + context.read().add(ChannelUpdateEvent(widget.channelId, req)); + } + + /// 生成选中的渠道类型文本 + String buildSelectedChannelTypeText() { + if (selectedChannelType == null) { + return '请选择'; + } + + return channelTypes + .firstWhere((element) => element.name == selectedChannelType) + .text; + } +} diff --git a/lib/page/setting/setting_screen.dart b/lib/page/setting/setting_screen.dart index 7f637a3c..bba71a9a 100644 --- a/lib/page/setting/setting_screen.dart +++ b/lib/page/setting/setting_screen.dart @@ -282,6 +282,18 @@ class _SettingScreenState extends State { SettingsSection( title: const Text('实验室'), tiles: [ + if (userHasLabPermission(state)) + SettingsTile( + title: const Text('渠道管理'), + trailing: Icon( + CupertinoIcons.chevron_forward, + size: MediaQuery.of(context).textScaleFactor * 18, + color: Colors.grey, + ), + onPressed: (context) { + context.push('/admin/channels'); + }, + ), if (userHasLabPermission(state)) SettingsTile( title: const Text('模型 Gallery'), diff --git a/lib/repo/api/admin/channels.dart b/lib/repo/api/admin/channels.dart new file mode 100644 index 00000000..309fdd59 --- /dev/null +++ b/lib/repo/api/admin/channels.dart @@ -0,0 +1,155 @@ +class AdminChannel { + int? id; + String name; + String type; + String? server; + String? secret; + + AdminChannelMeta? meta; + + AdminChannel({ + this.id, + required this.name, + required this.type, + this.server, + this.secret, + this.meta, + }); + + factory AdminChannel.fromJson(Map json) { + return AdminChannel( + id: json['id'], + name: json['name'], + type: json['type'], + server: json['server'], + secret: json['secret'], + meta: + json['meta'] != null ? AdminChannelMeta.fromJson(json['meta']) : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'type': type, + 'server': server, + 'secret': secret, + 'meta': meta?.toJson(), + }; + } +} + +class AdminChannelMeta { + bool? usingProxy; + bool? openaiAzure; + String? openaiAzureAPIVersion; + + AdminChannelMeta({ + this.usingProxy, + this.openaiAzure, + this.openaiAzureAPIVersion, + }); + + factory AdminChannelMeta.fromJson(Map json) { + return AdminChannelMeta( + usingProxy: json['using_proxy'], + openaiAzure: json['openai_azure'], + openaiAzureAPIVersion: json['openai_azure_api_version'], + ); + } + + Map toJson() { + return { + 'using_proxy': usingProxy, + 'openai_azure': openaiAzure, + 'openai_azure_api_version': openaiAzureAPIVersion, + }; + } +} + +class AdminChannelAddReq { + String name; + String type; + String? server; + String? secret; + + AdminChannelMeta? meta; + + AdminChannelAddReq({ + required this.name, + required this.type, + this.server, + this.secret, + this.meta, + }); + + Map toJson() { + return { + 'name': name, + 'type': type, + 'server': server, + 'secret': secret, + 'meta': meta?.toJson(), + }; + } +} + +class AdminChannelUpdateReq { + String? name; + String? type; + String? server; + String? secret; + + AdminChannelMeta? meta; + + AdminChannelUpdateReq({ + this.name, + this.type, + this.server, + this.secret, + this.meta, + }); + + Map toJson() { + return { + 'name': name, + 'type': type, + 'server': server, + 'secret': secret, + 'meta': meta?.toJson(), + }; + } +} + +class AdminChannelType { + String name; + String? display; + bool dynamicType; + + String get text { + return display ?? name; + } + + AdminChannelType({ + required this.name, + this.display, + required this.dynamicType, + }); + + factory AdminChannelType.fromJson(Map json) { + return AdminChannelType( + name: json['name'], + display: json['display'], + dynamicType: json['dynamic'] ?? false, + ); + } + + Map toJson() { + return { + 'name': name, + 'display': display, + 'dynamic': dynamicType, + }; + } +} diff --git a/lib/repo/api/admin/models.dart b/lib/repo/api/admin/models.dart new file mode 100644 index 00000000..e917f1e0 --- /dev/null +++ b/lib/repo/api/admin/models.dart @@ -0,0 +1,184 @@ +class AdminModel { + String modelId; + String name; + String? shortName; + String? description; + String? avatarUrl; + int status; + AdminModelMeta? meta; + List providers; + + AdminModel({ + required this.modelId, + required this.name, + this.shortName, + this.description, + this.avatarUrl, + required this.status, + this.meta, + required this.providers, + }); + + factory AdminModel.fromJson(Map json) { + return AdminModel( + modelId: json['modelId'], + name: json['name'], + shortName: json['shortName'], + description: json['description'], + avatarUrl: json['avatarUrl'], + status: json['status'], + meta: json['meta'] != null ? AdminModelMeta.fromJson(json['meta']) : null, + providers: ((json['providers'] ?? []) as List) + .map((e) => AdminModelProvider.fromJson(e)) + .toList(), + ); + } + + Map toJson() { + return { + 'modelId': modelId, + 'name': name, + 'shortName': shortName, + 'description': description, + 'avatarUrl': avatarUrl, + 'status': status, + 'meta': meta?.toJson(), + 'providers': providers.map((e) => e.toJson()).toList(), + }; + } +} + +class AdminModelMeta { + bool? vision; + bool? restricted; + int? maxContext; + int? inputPrice; + int? outputPrice; + + AdminModelMeta({ + this.vision, + this.restricted, + this.maxContext, + this.inputPrice, + this.outputPrice, + }); + + factory AdminModelMeta.fromJson(Map json) { + return AdminModelMeta( + vision: json['vision'], + restricted: json['restricted'], + maxContext: json['maxContext'], + inputPrice: json['inputPrice'], + outputPrice: json['outputPrice'], + ); + } + + Map toJson() { + return { + 'vision': vision, + 'restricted': restricted, + 'maxContext': maxContext, + 'inputPrice': inputPrice, + 'outputPrice': outputPrice, + }; + } +} + +class AdminModelProvider { + int? id; + String? name; + String? modelRewrite; + String? prompt; + + AdminModelProvider({ + this.id, + this.name, + this.modelRewrite, + this.prompt, + }); + + factory AdminModelProvider.fromJson(Map json) { + return AdminModelProvider( + id: json['id'], + name: json['name'], + modelRewrite: json['modelRewrite'], + prompt: json['prompt'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'modelRewrite': modelRewrite, + 'prompt': prompt, + }; + } +} + +class AdminModelAddReq { + String modelId; + String name; + String? shortName; + String? description; + String? avatarUrl; + int status; + AdminModelMeta? meta; + List? providers; + + AdminModelAddReq({ + required this.modelId, + required this.name, + this.shortName, + this.description, + this.avatarUrl, + required this.status, + this.meta, + this.providers, + }); + + Map toJson() { + return { + 'modelId': modelId, + 'name': name, + 'shortName': shortName, + 'description': description, + 'avatarUrl': avatarUrl, + 'status': status, + 'meta': meta?.toJson(), + 'providers': providers?.map((e) => e.toJson()).toList(), + }; + } +} + +class AdminModelUpdateReq { + String name; + String? shortName; + String? description; + String? avatarUrl; + int status; + AdminModelMeta? meta; + List? providers; + + AdminModelUpdateReq({ + required this.name, + this.shortName, + this.description, + this.avatarUrl, + required this.status, + this.meta, + this.providers, + }); + + Map toJson() { + return { + 'name': name, + 'shortName': shortName, + 'description': description, + 'avatarUrl': avatarUrl, + 'status': status, + 'meta': meta?.toJson(), + 'providers': providers?.map((e) => e.toJson()).toList(), + }; + } +} diff --git a/lib/repo/api_server.dart b/lib/repo/api_server.dart index e217bca9..0224c965 100644 --- a/lib/repo/api_server.dart +++ b/lib/repo/api_server.dart @@ -8,6 +8,8 @@ import 'package:askaide/helper/http.dart'; import 'package:askaide/helper/logger.dart'; import 'package:askaide/helper/platform.dart'; import 'package:askaide/page/component/global_alert.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api/admin/models.dart'; import 'package:askaide/repo/api/article.dart'; import 'package:askaide/repo/api/creative.dart'; import 'package:askaide/repo/api/image_model.dart'; @@ -1985,4 +1987,102 @@ class APIServer { }, ); } + + /// 管理员接口:渠道类型 + Future> adminChannelTypes() async { + return sendGetRequest('/v1/admin/channel-types', (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminChannelType.fromJson(item)); + } + + return res; + }); + } + + /// 管理员接口:返回所有渠道 + Future> adminChannels() async { + return sendGetRequest('/v1/admin/channels', (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminChannel.fromJson(item)); + } + + return res; + }); + } + + /// 管理员接口:返回指定渠道 + Future adminChannel({required int id}) async { + return sendGetRequest('/v1/admin/channels/$id', (resp) { + return AdminChannel.fromJson(resp.data['data']); + }); + } + + /// 管理员接口:创建渠道 + Future adminCreateChannel(AdminChannelAddReq req) async { + return sendPostJSONRequest( + '/v1/admin/channels', + (resp) {}, + data: req.toJson(), + ); + } + + /// 管理员接口:更新渠道 + Future adminUpdateChannel( + {required int id, required AdminChannelUpdateReq req}) { + return sendPutJSONRequest( + '/v1/admin/channels/$id', + (resp) {}, + data: req.toJson(), + ); + } + + /// 管理员接口:删除渠道 + Future adminDeleteChannel({required int id}) { + return sendDeleteRequest('/v1/admin/channels/$id', (resp) {}); + } + + /// 管理员接口:返回所有模型 + Future> adminModels() async { + return sendGetRequest('/v1/admin/models', (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminModel.fromJson(item)); + } + + return res; + }); + } + + /// 管理员接口:返回指定模型 + Future adminModel({required String modelId}) async { + return sendGetRequest('/v1/admin/models/$modelId', (resp) { + return AdminModel.fromJson(resp.data['data']); + }); + } + + /// 管理员接口:创建模型 + Future adminCreateModel(AdminModelAddReq req) async { + return sendPostJSONRequest( + '/v1/admin/models', + (resp) {}, + data: req.toJson(), + ); + } + + /// 管理员接口:更新模型 + Future adminUpdateModel( + {required String modelId, required AdminModelUpdateReq req}) { + return sendPutJSONRequest( + '/v1/admin/models/$modelId', + (resp) {}, + data: req.toJson(), + ); + } + + /// 管理员接口:删除模型 + Future adminDeleteModel({required String modelId}) { + return sendDeleteRequest('/v1/admin/models/$modelId', (resp) {}); + } } From 7018bd1bba4f79045dd3cad6c4851bb77722caf1 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 20 Mar 2024 15:13:28 +0800 Subject: [PATCH 16/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=90=8E=E5=8F=B0,=E6=94=AF=E6=8C=81=E6=A8=A1=E5=9E=8B\?= =?UTF-8?q?=E6=B8=A0=E9=81=93=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bloc/model_bloc.dart | 56 ++ lib/bloc/model_event.dart | 31 + lib/bloc/model_state.dart | 25 + lib/main.dart | 69 ++ lib/page/admin/channels.dart | 35 + lib/page/admin/channels_edit.dart | 2 - lib/page/admin/dashboard.dart | 102 +++ lib/page/admin/models.dart | 295 +++++++++ lib/page/admin/models_add.dart | 650 ++++++++++++++++++ lib/page/admin/models_edit.dart | 734 +++++++++++++++++++++ lib/page/chat/group/edit.dart | 1 - lib/page/chat/room_create.dart | 1 - lib/page/chat/room_edit.dart | 1 - lib/page/component/avatar_selector.dart | 2 - lib/page/component/enhanced_textfield.dart | 25 +- lib/page/setting/setting_screen.dart | 50 +- lib/repo/api/admin/channels.dart | 4 + lib/repo/api/admin/models.dart | 46 +- lib/repo/api_server.dart | 48 +- 19 files changed, 2100 insertions(+), 77 deletions(-) create mode 100644 lib/bloc/model_bloc.dart create mode 100644 lib/bloc/model_event.dart create mode 100644 lib/bloc/model_state.dart create mode 100644 lib/page/admin/dashboard.dart create mode 100644 lib/page/admin/models.dart create mode 100644 lib/page/admin/models_add.dart create mode 100644 lib/page/admin/models_edit.dart diff --git a/lib/bloc/model_bloc.dart b/lib/bloc/model_bloc.dart new file mode 100644 index 00000000..e0cf4bd4 --- /dev/null +++ b/lib/bloc/model_bloc.dart @@ -0,0 +1,56 @@ +import 'package:askaide/repo/api/admin/models.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; + +part 'model_event.dart'; +part 'model_state.dart'; + +class ModelBloc extends Bloc { + ModelBloc() : super(ModelInitial()) { + /// 加载所有模型 + on((event, emit) async { + final channels = await APIServer().adminModels(); + emit(ModelsLoaded(channels)); + }); + + /// 加载单个模型 + on((event, emit) async { + final channel = await APIServer().adminModel(modelId: event.modelId); + emit(ModelLoaded(channel)); + }); + + /// 创建模型 + on((event, emit) async { + try { + await APIServer().adminCreateModel(event.req); + emit(ModelOperationResult(true, '创建成功')); + } catch (e) { + emit(ModelOperationResult(false, e.toString())); + } + }); + + /// 更新模型 + on((event, emit) async { + try { + await APIServer().adminUpdateModel( + modelId: event.modelId, + req: event.req, + ); + emit(ModelOperationResult(true, '更新成功')); + } catch (e) { + emit(ModelOperationResult(false, e.toString())); + } + }); + + /// 删除模型 + on((event, emit) async { + try { + await APIServer().adminDeleteModel(modelId: event.modelId); + emit(ModelOperationResult(true, '删除成功')); + } catch (e) { + emit(ModelOperationResult(false, e.toString())); + } + }); + } +} diff --git a/lib/bloc/model_event.dart b/lib/bloc/model_event.dart new file mode 100644 index 00000000..b15f9134 --- /dev/null +++ b/lib/bloc/model_event.dart @@ -0,0 +1,31 @@ +part of 'model_bloc.dart'; + +@immutable +sealed class ModelEvent {} + +class ModelsLoadEvent extends ModelEvent {} + +class ModelLoadEvent extends ModelEvent { + final String modelId; + + ModelLoadEvent(this.modelId); +} + +class ModelCreateEvent extends ModelEvent { + final AdminModelAddReq req; + + ModelCreateEvent(this.req); +} + +class ModelUpdateEvent extends ModelEvent { + final String modelId; + final AdminModelUpdateReq req; + + ModelUpdateEvent(this.modelId, this.req); +} + +class ModelDeleteEvent extends ModelEvent { + final String modelId; + + ModelDeleteEvent(this.modelId); +} diff --git a/lib/bloc/model_state.dart b/lib/bloc/model_state.dart new file mode 100644 index 00000000..150c3113 --- /dev/null +++ b/lib/bloc/model_state.dart @@ -0,0 +1,25 @@ +part of 'model_bloc.dart'; + +@immutable +sealed class ModelState {} + +final class ModelInitial extends ModelState {} + +class ModelsLoaded extends ModelState { + final List models; + + ModelsLoaded(this.models); +} + +class ModelLoaded extends ModelState { + final AdminModel model; + + ModelLoaded(this.model); +} + +class ModelOperationResult extends ModelState { + final bool success; + final String message; + + ModelOperationResult(this.success, this.message); +} diff --git a/lib/main.dart b/lib/main.dart index 3725abf3..5b15a6f5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,13 @@ import 'package:askaide/bloc/channel_bloc.dart'; +import 'package:askaide/bloc/model_bloc.dart'; import 'package:askaide/helper/path.dart'; import 'package:askaide/page/admin/channels.dart'; import 'package:askaide/page/admin/channels_add.dart'; import 'package:askaide/page/admin/channels_edit.dart'; +import 'package:askaide/page/admin/dashboard.dart'; +import 'package:askaide/page/admin/models.dart'; +import 'package:askaide/page/admin/models_add.dart'; +import 'package:askaide/page/admin/models_edit.dart'; import 'package:askaide/page/balance/web_payment_proxy.dart'; import 'package:askaide/page/balance/web_payment_result.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; @@ -1064,6 +1069,70 @@ class MyApp extends StatefulWidget { ), /// 管理员接口 + GoRoute( + name: 'admin-dashboard', + path: '/admin/dashboard', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + AdminDashboardPage(setting: settingRepo), + ); + }, + ), + GoRoute( + name: 'admin-models', + path: '/admin/models', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ModelBloc(), + ), + ], + child: AdminModelsPage(setting: settingRepo), + ), + ); + }, + ), + GoRoute( + name: 'admin-models-create', + path: '/admin/models/create', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ModelBloc(), + ), + ], + child: AdminModelCreatePage(setting: settingRepo), + ), + ); + }, + ), + GoRoute( + name: 'admin-models-edit', + path: '/admin/models/edit/:id', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ModelBloc(), + ), + ], + child: AdminModelEditPage( + setting: settingRepo, + modelId: state.pathParameters['id']!, + ), + ), + ); + }, + ), GoRoute( name: 'admin-channels', path: '/admin/channels', diff --git a/lib/page/admin/channels.dart b/lib/page/admin/channels.dart index f6c76348..4e2b254b 100644 --- a/lib/page/admin/channels.dart +++ b/lib/page/admin/channels.dart @@ -5,6 +5,7 @@ import 'package:askaide/page/component/dialog.dart'; import 'package:askaide/page/component/theme/custom_size.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api_server.dart'; import 'package:askaide/repo/settings_repo.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -25,10 +26,22 @@ class ChannelsPage extends StatefulWidget { } class _ChannelsPageState extends State { + // 渠道类型 + List channelTypes = []; + @override void initState() { context.read().add(ChannelsLoadEvent()); + // 加载渠道类型 + APIServer().adminChannelTypes().then((value) { + if (context.mounted) { + setState(() { + channelTypes = value; + }); + } + }); + super.initState(); } @@ -192,6 +205,28 @@ class _ChannelsPageState extends State { ), ], ), + Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + channelTypes + .firstWhere((e) => e.name == channel.type) + .text, + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: customColors.weakTextColor, + ), + ), + ], + ), + ), + ), ], ), ), diff --git a/lib/page/admin/channels_edit.dart b/lib/page/admin/channels_edit.dart index 0c503197..bb0ca01d 100644 --- a/lib/page/admin/channels_edit.dart +++ b/lib/page/admin/channels_edit.dart @@ -16,8 +16,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localization/flutter_localization.dart'; -import 'package:go_router/go_router.dart'; -import 'package:provider/provider.dart'; class ChannelEditPage extends StatefulWidget { final SettingRepository setting; diff --git a/lib/page/admin/dashboard.dart b/lib/page/admin/dashboard.dart new file mode 100644 index 00000000..7310760b --- /dev/null +++ b/lib/page/admin/dashboard.dart @@ -0,0 +1,102 @@ +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:settings_ui/settings_ui.dart'; + +class AdminDashboardPage extends StatefulWidget { + final SettingRepository setting; + const AdminDashboardPage({super.key, required this.setting}); + + @override + State createState() => _AdminDashboardPageState(); +} + +class _AdminDashboardPageState extends State { + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return BackgroundContainer( + setting: widget.setting, + child: Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + 'Dashboard', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: Colors.transparent, + body: Column( + children: [ + Expanded( + child: SettingsList( + platform: DevicePlatform.iOS, + lightTheme: const SettingsThemeData( + settingsListBackground: Colors.transparent, + settingsSectionBackground: Color.fromARGB(255, 255, 255, 255), + ), + darkTheme: const SettingsThemeData( + settingsListBackground: Colors.transparent, + settingsSectionBackground: Color.fromARGB(255, 27, 27, 27), + titleTextColor: Color.fromARGB(255, 239, 239, 239), + ), + sections: [ + SettingsSection( + title: const Text('创作岛'), + tiles: [ + SettingsTile( + title: const Text('Gallery'), + trailing: const Icon( + CupertinoIcons.chevron_forward, + size: 18, + color: Colors.grey, + ), + onPressed: (context) { + context.push('/creative-island/models'); + }, + ), + ], + ), + SettingsSection( + title: const Text('系统设置'), + tiles: [ + SettingsTile( + title: const Text('渠道管理'), + trailing: const Icon( + CupertinoIcons.chevron_forward, + size: 18, + color: Colors.grey, + ), + onPressed: (context) { + context.push('/admin/channels'); + }, + ), + SettingsTile( + title: const Text('大语言模型管理'), + trailing: const Icon( + CupertinoIcons.chevron_forward, + size: 18, + color: Colors.grey, + ), + onPressed: (context) { + context.push('/admin/models'); + }, + ), + ], + ), + ], + contentPadding: const EdgeInsets.all(0), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/page/admin/models.dart b/lib/page/admin/models.dart new file mode 100644 index 00000000..263ce52b --- /dev/null +++ b/lib/page/admin/models.dart @@ -0,0 +1,295 @@ +import 'package:askaide/bloc/model_bloc.dart'; +import 'package:askaide/helper/constant.dart'; +import 'package:askaide/helper/image.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api/admin/models.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_initicon/flutter_initicon.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:go_router/go_router.dart'; + +class AdminModelsPage extends StatefulWidget { + final SettingRepository setting; + const AdminModelsPage({ + super.key, + required this.setting, + }); + + @override + State createState() => _AdminModelsPageState(); +} + +class _AdminModelsPageState extends State { + // 渠道 + List channels = []; + + /// 查找渠道 + AdminChannel searchChannel(AdminModelProvider provider) { + return channels.firstWhere( + (e) { + if (e.id == null && (provider.id == null || provider.id == 0)) { + return provider.name == e.type; + } + + return provider.id == e.id; + }, + orElse: () { + return AdminChannel( + id: provider.id, + name: '未知', + type: 'unknown', + ); + }, + ); + } + + @override + void initState() { + // 加载渠道 + APIServer().adminChannelsAgg().then((value) { + if (context.mounted) { + setState(() { + channels = value; + }); + + // 加载模型列表 + context.read().add(ModelsLoadEvent()); + } + }); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '大语言模型管理', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + actions: [ + IconButton( + icon: const Icon(Icons.add), + onPressed: () { + context.push('/admin/models/create').then((value) { + context.read().add(ModelsLoadEvent()); + }); + }, + ), + ], + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: RefreshIndicator( + color: customColors.linkColor, + onRefresh: () async { + context.read().add(ModelsLoadEvent()); + }, + displacement: 20, + child: BlocConsumer( + listenWhen: (previous, current) => current is ModelOperationResult, + listener: (context, state) { + if (state is ModelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.read().add(ModelsLoadEvent()); + } else { + showErrorMessage(state.message); + } + } + }, + buildWhen: (previous, current) => current is ModelsLoaded, + builder: (context, state) { + if (state is ModelsLoaded) { + return SafeArea( + top: false, + child: ListView.builder( + padding: const EdgeInsets.all(5), + itemCount: state.models.length, + itemBuilder: (context, index) { + final mod = state.models[index]; + + return buildModelItem(context, customColors, mod); + }, + ), + ); + } + + return const Center( + child: CircularProgressIndicator(), + ); + }, + ), + ), + ), + ); + } + + Widget buildModelItem( + BuildContext context, + CustomColors customColors, + AdminModel mod, + ) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(customColors.borderRadius ?? 8), + ), + child: Slidable( + endActionPane: ActionPane( + motion: const ScrollMotion(), + children: [ + const SizedBox(width: 10), + SlidableAction( + label: AppLocale.delete.getString(context), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(customColors.borderRadius ?? 8), + bottomLeft: Radius.circular(customColors.borderRadius ?? 8), + topRight: Radius.circular(customColors.borderRadius ?? 8), + bottomRight: Radius.circular(customColors.borderRadius ?? 8), + ), + backgroundColor: Colors.red, + icon: Icons.delete, + onPressed: (_) { + openConfirmDialog( + context, + AppLocale.confirmToDeleteRoom.getString(context), + () => context + .read() + .add(ModelDeleteEvent(mod.modelId)), + danger: true, + ); + }, + ), + ], + ), + child: Material( + borderRadius: + BorderRadius.all(Radius.circular(customColors.borderRadius ?? 8)), + color: customColors.columnBlockBackgroundColor, + child: InkWell( + borderRadius: BorderRadius.all( + Radius.circular(customColors.borderRadius ?? 8)), + onTap: () { + context + .push( + '/admin/models/edit/${Uri.encodeComponent(mod.modelId)}') + .then((value) { + context.read().add(ModelsLoadEvent()); + }); + }, + child: Stack( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 头像 + buildAvatar(mod), + // 名称 + Expanded( + child: Container( + padding: const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + mod.name, + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + ), + Text( + mod.description ?? '', + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: customColors.weakTextColor, + ), + ), + ], + ), + ), + ), + ], + ), + Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.0, + alignment: Alignment.centerRight, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + mod.providers + .map((e) => searchChannel(e).display) + .join('|'), + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: customColors.weakTextColor, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } + + Widget buildAvatar(AdminModel mod) { + if (mod.avatarUrl != null && mod.avatarUrl!.startsWith('http')) { + return SizedBox( + width: 70, + height: 70, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8), + ), + child: CachedNetworkImage( + imageUrl: imageURL(mod.avatarUrl!, qiniuImageTypeAvatar), + fit: BoxFit.fill, + ), + ), + ); + } + + return Initicon( + text: mod.name.split('、').join(' '), + size: 70, + backgroundColor: Colors.grey.withAlpha(100), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8), + ), + ); + } +} diff --git a/lib/page/admin/models_add.dart b/lib/page/admin/models_add.dart new file mode 100644 index 00000000..adf047bf --- /dev/null +++ b/lib/page/admin/models_add.dart @@ -0,0 +1,650 @@ +import 'dart:io'; + +import 'package:askaide/bloc/model_bloc.dart'; +import 'package:askaide/helper/upload.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/avatar_selector.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/column_block.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/enhanced_button.dart'; +import 'package:askaide/page/component/enhanced_input.dart'; +import 'package:askaide/page/component/enhanced_textfield.dart'; +import 'package:askaide/page/component/image.dart'; +import 'package:askaide/page/component/item_selector_search.dart'; +import 'package:askaide/page/component/loading.dart'; +import 'package:askaide/page/component/random_avatar.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/page/component/weak_text_button.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api/admin/models.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:go_router/go_router.dart'; +import 'package:quickalert/models/quickalert_type.dart'; + +class AdminModelCreatePage extends StatefulWidget { + final SettingRepository setting; + const AdminModelCreatePage({ + super.key, + required this.setting, + }); + + @override + State createState() => _AdminModelCreatePageState(); +} + +class _AdminModelCreatePageState extends State { + final TextEditingController nameController = TextEditingController(); + final TextEditingController modelIdController = TextEditingController(); + final TextEditingController shortNameController = TextEditingController(); + final TextEditingController descriptionController = TextEditingController(); + final TextEditingController maxContextController = TextEditingController(); + final TextEditingController inputPriceController = TextEditingController(); + final TextEditingController outputPriceController = TextEditingController(); + final TextEditingController promptController = TextEditingController(); + + /// 用于控制是否显示高级选项 + bool showAdvancedOptions = false; + + /// 视觉能力 + bool supportVision = false; + + /// 受限模型 + bool restricted = false; + + /// 模型状态 + bool modelEnabled = true; + + /// 模型头像 + String? avatarUrl; + List avatarPresets = []; + + // 模型渠道 + List modelChannels = []; + // 选择的渠道 + List providers = []; + + @override + void dispose() { + nameController.dispose(); + modelIdController.dispose(); + shortNameController.dispose(); + descriptionController.dispose(); + maxContextController.dispose(); + inputPriceController.dispose(); + outputPriceController.dispose(); + promptController.dispose(); + + super.dispose(); + } + + @override + void initState() { + // 加载预设头像 + APIServer().avatars().then((value) { + avatarPresets = value; + }); + // 加载模型渠道 + APIServer().adminChannelsAgg().then((value) { + modelChannels = value; + }); + + // 初始值设置 + maxContextController.value = const TextEditingValue(text: '3500'); + inputPriceController.value = const TextEditingValue(text: '1'); + outputPriceController.value = const TextEditingValue(text: '1'); + providers.add(AdminModelProvider()); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '新增模型', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: SingleChildScrollView( + child: BlocListener( + listenWhen: (previous, current) => current is ModelOperationResult, + listener: (context, state) { + if (state is ModelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.pop(); + } else { + showErrorMessage(state.message); + } + } + }, + child: Container( + padding: const EdgeInsets.only( + left: 10, right: 10, top: 10, bottom: 20), + child: Column( + children: [ + ColumnBlock( + children: [ + EnhancedTextField( + labelText: '唯一标识', + customColors: customColors, + controller: modelIdController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入模型唯一标识', + maxLength: 100, + showCounter: false, + ), + EnhancedTextField( + labelText: '名称', + customColors: customColors, + controller: nameController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入模型名称', + maxLength: 100, + showCounter: false, + ), + EnhancedInput( + padding: const EdgeInsets.only(top: 10, bottom: 5), + title: Text( + '头像', + style: TextStyle( + color: customColors.textfieldLabelColor, + fontSize: 16, + ), + ), + value: Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 45, + height: 45, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + image: avatarUrl == null + ? null + : DecorationImage( + image: (avatarUrl!.startsWith('http') + ? CachedNetworkImageProviderEnhanced( + avatarUrl!) + : FileImage(File( + avatarUrl!))) as ImageProvider, + fit: BoxFit.cover, + ), + ), + child: avatarUrl == null + ? const Center( + child: Icon( + Icons.interests, + color: Colors.grey, + ), + ) + : const SizedBox(), + ), + ], + ), + onPressed: () { + openModalBottomSheet( + context, + (context) { + return AvatarSelector( + onSelected: (selected) { + setState(() { + avatarUrl = selected.url; + }); + context.pop(); + }, + usage: AvatarUsage.user, + defaultAvatarUrl: avatarUrl, + externalAvatarUrls: [ + ...avatarPresets, + ], + ); + }, + heightFactor: 0.8, + ); + }, + ), + EnhancedTextField( + labelText: '描述', + customColors: customColors, + controller: descriptionController, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + maxLength: 255, + showCounter: false, + maxLines: 3, + ), + ], + ), + ColumnBlock( + children: [ + EnhancedTextField( + labelText: '输入价格', + customColors: customColors, + controller: inputPriceController, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + textDirection: TextDirection.rtl, + suffixIcon: Container( + width: 110, + alignment: Alignment.center, + child: Text( + '智慧果/1K Token', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12), + ), + ), + ), + EnhancedTextField( + labelText: '输出价格', + customColors: customColors, + controller: outputPriceController, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + textDirection: TextDirection.rtl, + suffixIcon: Container( + width: 110, + alignment: Alignment.center, + child: Text( + '智慧果/1K Token', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12), + ), + ), + ), + EnhancedTextField( + labelText: '输入限制', + customColors: customColors, + controller: maxContextController, + textAlignVertical: TextAlignVertical.top, + hintText: '最大上下文减掉预期的输出长度', + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + textDirection: TextDirection.rtl, + suffixIcon: Container( + width: 50, + alignment: Alignment.center, + child: Text( + 'Token', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12), + ), + ), + ), + ], + ), + ...providers.map((e) { + return Container( + margin: + const EdgeInsets.only(bottom: 10, left: 5, right: 5), + child: Slidable( + endActionPane: ActionPane( + motion: const ScrollMotion(), + children: [ + const SizedBox(width: 10), + SlidableAction( + label: AppLocale.delete.getString(context), + borderRadius: BorderRadius.circular( + customColors.borderRadius ?? 8), + backgroundColor: Colors.red, + icon: Icons.delete, + onPressed: (_) { + if (providers.length == 1) { + showErrorMessage('至少需要一个渠道'); + return; + } + + openConfirmDialog( + context, + AppLocale.confirmToDeleteRoom + .getString(context), + () { + setState(() { + providers + .removeWhere((item) => item == e); + }); + }, + danger: true, + ); + }, + ), + ], + ), + child: ColumnBlock( + margin: const EdgeInsets.all(0), + children: [ + EnhancedInput( + title: Text( + '渠道', + style: TextStyle( + color: customColors.textfieldLabelColor, + fontSize: 16, + ), + ), + value: Text( + buildChannelName(e), + style: TextStyle( + color: customColors.textfieldValueColor, + fontSize: 16, + ), + ), + onPressed: () { + openListSelectDialog( + context, + >[ + ...modelChannels + .map( + (e) => SelectorItem( + Text( + '${e.id == null ? '【系统】' : ''}${e.name}'), + e, + ), + ) + .toList(), + ], + (value) { + setState(() { + e.id = value.value.id; + if (value.value.id == null) { + e.name = value.value.type; + } + }); + return true; + }, + heightFactor: 0.5, + value: e, + ); + }, + ), + EnhancedTextField( + labelText: '模型重写', + customColors: customColors, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + maxLength: 100, + showCounter: false, + initValue: e.modelRewrite, + onChanged: (value) { + e.modelRewrite = value; + }, + ), + ], + ), + ), + ); + }).toList(), + const SizedBox(width: 10), + WeakTextButton( + title: '添加渠道', + icon: Icons.add, + onPressed: () { + setState(() { + providers.add(AdminModelProvider()); + }); + }, + ), + // 高级选项 + if (showAdvancedOptions) + ColumnBlock( + innerPanding: 5, + children: [ + EnhancedTextField( + labelText: '简称', + customColors: customColors, + controller: shortNameController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入模型简称', + maxLength: 100, + showCounter: false, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '启用', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: modelEnabled, + onChanged: (value) { + setState(() { + modelEnabled = value; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '视觉能力', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: supportVision, + onChanged: (value) { + setState(() { + supportVision = value; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + const Text( + '受限模型', + style: TextStyle(fontSize: 16), + ), + const SizedBox(width: 5), + InkWell( + onTap: () { + showBeautyDialog( + context, + type: QuickAlertType.info, + text: '受限模型是指因政策因素,不能在中国大陆地区使用的模型。', + confirmBtnText: + AppLocale.gotIt.getString(context), + showCancelBtn: false, + ); + }, + child: Icon( + Icons.help_outline, + size: 16, + color: customColors.weakLinkColor + ?.withAlpha(150), + ), + ), + ], + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: restricted, + onChanged: (value) { + setState(() { + restricted = value; + }); + }, + ), + ], + ), + EnhancedTextField( + labelPosition: LabelPosition.top, + labelText: '系统提示语', + customColors: customColors, + controller: promptController, + textAlignVertical: TextAlignVertical.top, + hintText: '全局系统提示语', + maxLength: 2000, + maxLines: 3, + ), + ], + ), + const SizedBox(height: 15), + Row( + children: [ + EnhancedButton( + title: showAdvancedOptions + ? AppLocale.simpleMode.getString(context) + : AppLocale.professionalMode.getString(context), + width: 120, + backgroundColor: Colors.transparent, + color: customColors.weakLinkColor, + fontSize: 15, + icon: Icon( + showAdvancedOptions + ? Icons.unfold_less + : Icons.unfold_more, + color: customColors.weakLinkColor, + size: 15, + ), + onPressed: () { + setState(() { + showAdvancedOptions = !showAdvancedOptions; + }); + }, + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: EnhancedButton( + title: AppLocale.save.getString(context), + onPressed: onSubmit, + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ); + } + + /// 提交 + void onSubmit() async { + if (nameController.text.isEmpty) { + showErrorMessage('请输入模型名称'); + return; + } + + if (modelIdController.text.isEmpty) { + showErrorMessage('请输入模型唯一标识'); + return; + } + + final ps = providers.where((e) => e.id != null || e.name != null).toList(); + if (ps.isEmpty) { + showErrorMessage('至少需要一个渠道'); + return; + } + + if (avatarUrl != null && + (!avatarUrl!.startsWith('http://') && + !avatarUrl!.startsWith('https://'))) { + final cancel = BotToast.showCustomLoading( + toastBuilder: (cancel) { + return const LoadingIndicator( + message: '正在上传头像,请稍后...', + ); + }, + allowClick: false, + ); + + try { + final res = await ImageUploader(widget.setting) + .upload(avatarUrl!, usage: 'avatar'); + avatarUrl = res.url; + } catch (e) { + showErrorMessage('上传头像失败'); + cancel(); + return; + } finally { + cancel(); + } + } + + final model = AdminModelAddReq( + name: nameController.text, + modelId: modelIdController.text, + description: descriptionController.text, + shortName: shortNameController.text, + meta: AdminModelMeta( + maxContext: int.parse(maxContextController.text), + inputPrice: int.parse(inputPriceController.text), + outputPrice: int.parse(outputPriceController.text), + prompt: promptController.text, + vision: supportVision, + restricted: restricted, + ), + status: modelEnabled ? 1 : 2, + providers: ps, + avatarUrl: avatarUrl, + ); + + // ignore: use_build_context_synchronously + context.read().add(ModelCreateEvent(model)); + } + + /// 渠道名称 + String buildChannelName(AdminModelProvider provider) { + if (provider.id != null) { + return modelChannels.firstWhere((e) => e.id == provider.id).name; + } + + if (provider.name != null) { + return modelChannels + .firstWhere( + (e) => e.type == provider.name! && e.id == null, + orElse: () => AdminChannel(name: '未知', type: ''), + ) + .display; + } + + return '请选择'; + } +} diff --git a/lib/page/admin/models_edit.dart b/lib/page/admin/models_edit.dart new file mode 100644 index 00000000..cefc5e38 --- /dev/null +++ b/lib/page/admin/models_edit.dart @@ -0,0 +1,734 @@ +import 'dart:io'; + +import 'package:askaide/bloc/model_bloc.dart'; +import 'package:askaide/helper/upload.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/avatar_selector.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/column_block.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/enhanced_button.dart'; +import 'package:askaide/page/component/enhanced_input.dart'; +import 'package:askaide/page/component/enhanced_textfield.dart'; +import 'package:askaide/page/component/image.dart'; +import 'package:askaide/page/component/item_selector_search.dart'; +import 'package:askaide/page/component/loading.dart'; +import 'package:askaide/page/component/random_avatar.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/page/component/weak_text_button.dart'; +import 'package:askaide/repo/api/admin/channels.dart'; +import 'package:askaide/repo/api/admin/models.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:go_router/go_router.dart'; +import 'package:quickalert/models/quickalert_type.dart'; + +class AdminModelEditPage extends StatefulWidget { + final SettingRepository setting; + final String modelId; + const AdminModelEditPage({ + super.key, + required this.setting, + required this.modelId, + }); + + @override + State createState() => _AdminModelEditPageState(); +} + +class _AdminModelEditPageState extends State { + final TextEditingController nameController = TextEditingController(); + final TextEditingController modelIdController = TextEditingController(); + final TextEditingController shortNameController = TextEditingController(); + final TextEditingController descriptionController = TextEditingController(); + final TextEditingController maxContextController = TextEditingController(); + final TextEditingController inputPriceController = TextEditingController(); + final TextEditingController outputPriceController = TextEditingController(); + final TextEditingController promptController = TextEditingController(); + + /// 用于控制是否显示高级选项 + bool showAdvancedOptions = false; + + /// 视觉能力 + bool supportVision = false; + + /// 受限模型 + bool restricted = false; + + /// 模型状态 + bool modelEnabled = true; + + /// 模型头像 + String? avatarUrl; + List avatarPresets = []; + + // 模型渠道 + List modelChannels = []; + // 选择的渠道 + List providers = []; + + /// 是否锁定编辑 + bool editLocked = true; + + @override + void dispose() { + nameController.dispose(); + modelIdController.dispose(); + shortNameController.dispose(); + descriptionController.dispose(); + maxContextController.dispose(); + inputPriceController.dispose(); + outputPriceController.dispose(); + promptController.dispose(); + + super.dispose(); + } + + @override + void initState() { + // 加载预设头像 + APIServer().avatars().then((value) { + avatarPresets = value; + }); + // 加载模型渠道 + APIServer().adminChannelsAgg().then((value) { + setState(() { + modelChannels = value; + }); + + // 加载模型 + context.read().add(ModelLoadEvent(widget.modelId)); + }); + + // 初始值设置 + maxContextController.value = const TextEditingValue(text: '3500'); + inputPriceController.value = const TextEditingValue(text: '1'); + outputPriceController.value = const TextEditingValue(text: '1'); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '编辑模型', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: SingleChildScrollView( + child: BlocListener( + listenWhen: (previous, current) => + current is ModelOperationResult || current is ModelLoaded, + listener: (context, state) { + if (state is ModelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.read().add(ModelLoadEvent(widget.modelId)); + } else { + showErrorMessage(state.message); + } + } + + if (state is ModelLoaded) { + modelIdController.value = + TextEditingValue(text: state.model.modelId); + nameController.value = TextEditingValue(text: state.model.name); + if (state.model.description != null) { + descriptionController.value = + TextEditingValue(text: state.model.description!); + } + + if (state.model.avatarUrl != null) { + avatarUrl = state.model.avatarUrl; + } + + modelEnabled = state.model.status == 1; + + if (state.model.providers.isNotEmpty) { + providers = state.model.providers; + } + + if (state.model.meta != null) { + if (state.model.meta!.maxContext != null) { + maxContextController.value = TextEditingValue( + text: state.model.meta!.maxContext.toString()); + } + + if (state.model.meta!.inputPrice != null) { + inputPriceController.value = TextEditingValue( + text: state.model.meta!.inputPrice.toString()); + } + + if (state.model.meta!.outputPrice != null) { + outputPriceController.value = TextEditingValue( + text: state.model.meta!.outputPrice.toString()); + } + + promptController.value = + TextEditingValue(text: state.model.meta!.prompt ?? ''); + supportVision = state.model.meta!.vision ?? false; + restricted = state.model.meta!.restricted ?? false; + } + } + + setState(() { + editLocked = false; + }); + }, + child: Container( + padding: const EdgeInsets.only( + left: 10, right: 10, top: 10, bottom: 20), + child: Column( + children: [ + ColumnBlock( + children: [ + EnhancedTextField( + labelText: '唯一标识', + customColors: customColors, + controller: modelIdController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入模型唯一标识', + maxLength: 100, + showCounter: false, + readOnly: true, + ), + EnhancedTextField( + labelText: '名称', + customColors: customColors, + controller: nameController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入模型名称', + maxLength: 100, + showCounter: false, + ), + EnhancedInput( + padding: const EdgeInsets.only(top: 10, bottom: 5), + title: Text( + '头像', + style: TextStyle( + color: customColors.textfieldLabelColor, + fontSize: 16, + ), + ), + value: Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 45, + height: 45, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + image: avatarUrl == null + ? null + : DecorationImage( + image: (avatarUrl!.startsWith('http') + ? CachedNetworkImageProviderEnhanced( + avatarUrl!) + : FileImage(File( + avatarUrl!))) as ImageProvider, + fit: BoxFit.cover, + ), + ), + child: avatarUrl == null + ? const Center( + child: Icon( + Icons.interests, + color: Colors.grey, + ), + ) + : const SizedBox(), + ), + ], + ), + onPressed: () { + openModalBottomSheet( + context, + (context) { + return AvatarSelector( + onSelected: (selected) { + setState(() { + avatarUrl = selected.url; + }); + context.pop(); + }, + usage: AvatarUsage.user, + defaultAvatarUrl: avatarUrl, + externalAvatarUrls: [ + ...avatarPresets, + ], + ); + }, + heightFactor: 0.8, + ); + }, + ), + EnhancedTextField( + labelText: '描述', + customColors: customColors, + controller: descriptionController, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + maxLength: 255, + showCounter: false, + maxLines: 3, + ), + ], + ), + ColumnBlock( + children: [ + EnhancedTextField( + labelText: '输入价格', + customColors: customColors, + controller: inputPriceController, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + textDirection: TextDirection.rtl, + suffixIcon: Container( + width: 110, + alignment: Alignment.center, + child: Text( + '智慧果/1K Token', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12), + ), + ), + ), + EnhancedTextField( + labelText: '输出价格', + customColors: customColors, + controller: outputPriceController, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + textDirection: TextDirection.rtl, + suffixIcon: Container( + width: 110, + alignment: Alignment.center, + child: Text( + '智慧果/1K Token', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12), + ), + ), + ), + EnhancedTextField( + labelText: '输入限制', + customColors: customColors, + controller: maxContextController, + textAlignVertical: TextAlignVertical.top, + hintText: '最大上下文减掉预期的输出长度', + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + textDirection: TextDirection.rtl, + suffixIcon: Container( + width: 50, + alignment: Alignment.center, + child: Text( + 'Token', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12), + ), + ), + ), + ], + ), + for (var i = 0; i < providers.length; i++) + Container( + margin: + const EdgeInsets.only(bottom: 10, left: 5, right: 5), + child: Slidable( + endActionPane: ActionPane( + motion: const ScrollMotion(), + children: [ + const SizedBox(width: 10), + SlidableAction( + label: AppLocale.delete.getString(context), + borderRadius: BorderRadius.circular( + customColors.borderRadius ?? 8), + backgroundColor: Colors.red, + icon: Icons.delete, + onPressed: (_) { + if (providers.length == 1) { + showErrorMessage('至少需要一个渠道'); + return; + } + + openConfirmDialog( + context, + AppLocale.confirmToDeleteRoom + .getString(context), + () { + setState(() { + providers.removeAt(i); + }); + }, + danger: true, + ); + }, + ), + ], + ), + child: ColumnBlock( + margin: const EdgeInsets.all(0), + children: [ + EnhancedInput( + title: Text( + '渠道', + style: TextStyle( + color: customColors.textfieldLabelColor, + fontSize: 16, + ), + ), + value: Text( + buildChannelName(providers[i]), + style: TextStyle( + color: customColors.textfieldValueColor, + fontSize: 16, + ), + ), + onPressed: () { + openListSelectDialog( + context, + >[ + ...modelChannels + .map( + (e) => SelectorItem( + Text( + '${e.id == null ? '【系统】' : ''}${e.name}'), + e, + ), + ) + .toList(), + ], + (value) { + setState(() { + providers[i].id = value.value.id; + if (value.value.id == null) { + providers[i].name = value.value.type; + } + }); + return true; + }, + heightFactor: 0.5, + value: providers[i], + ); + }, + ), + EnhancedTextField( + labelText: '模型重写', + labelFontSize: 12, + customColors: customColors, + textAlignVertical: TextAlignVertical.top, + hintText: '可选', + maxLength: 100, + showCounter: false, + initValue: providers[i].modelRewrite, + onChanged: (value) { + setState(() { + providers[i].modelRewrite = value; + }); + }, + labelHelpWidget: InkWell( + onTap: () { + showBeautyDialog( + context, + type: QuickAlertType.info, + text: + '渠道对应的模型标识和这里的 ID 不一致时,调用渠道接口时将会自动将模型替换为这里配置的值。', + confirmBtnText: + AppLocale.gotIt.getString(context), + showCancelBtn: false, + ); + }, + child: Icon( + Icons.help_outline, + size: 16, + color: customColors.weakLinkColor + ?.withAlpha(150), + ), + ), + ), + ], + ), + ), + ), + const SizedBox(width: 10), + WeakTextButton( + title: '添加渠道', + icon: Icons.add, + onPressed: () { + setState(() { + providers.add(AdminModelProvider()); + }); + }, + ), + // 高级选项 + if (showAdvancedOptions) + ColumnBlock( + innerPanding: 5, + children: [ + EnhancedTextField( + labelText: '简称', + customColors: customColors, + controller: shortNameController, + textAlignVertical: TextAlignVertical.top, + hintText: '请输入模型简称', + maxLength: 100, + showCounter: false, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '启用', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: modelEnabled, + onChanged: (value) { + setState(() { + modelEnabled = value; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '视觉能力', + style: TextStyle(fontSize: 16), + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: supportVision, + onChanged: (value) { + setState(() { + supportVision = value; + }); + }, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + const Text( + '受限模型', + style: TextStyle(fontSize: 16), + ), + const SizedBox(width: 5), + InkWell( + onTap: () { + showBeautyDialog( + context, + type: QuickAlertType.info, + text: '受限模型是指因政策因素,不能在中国大陆地区使用的模型。', + confirmBtnText: + AppLocale.gotIt.getString(context), + showCancelBtn: false, + ); + }, + child: Icon( + Icons.help_outline, + size: 16, + color: customColors.weakLinkColor + ?.withAlpha(150), + ), + ), + ], + ), + CupertinoSwitch( + activeColor: customColors.linkColor, + value: restricted, + onChanged: (value) { + setState(() { + restricted = value; + }); + }, + ), + ], + ), + EnhancedTextField( + labelPosition: LabelPosition.top, + labelText: '系统提示语', + customColors: customColors, + controller: promptController, + textAlignVertical: TextAlignVertical.top, + hintText: '全局系统提示语', + maxLength: 2000, + maxLines: 3, + ), + ], + ), + const SizedBox(height: 15), + Row( + children: [ + EnhancedButton( + title: showAdvancedOptions + ? AppLocale.simpleMode.getString(context) + : AppLocale.professionalMode.getString(context), + width: 120, + backgroundColor: Colors.transparent, + color: customColors.weakLinkColor, + fontSize: 15, + icon: Icon( + showAdvancedOptions + ? Icons.unfold_less + : Icons.unfold_more, + color: customColors.weakLinkColor, + size: 15, + ), + onPressed: () { + setState(() { + showAdvancedOptions = !showAdvancedOptions; + }); + }, + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: EnhancedButton( + title: AppLocale.save.getString(context), + onPressed: onSubmit, + icon: editLocked + ? const Icon(Icons.lock, + color: Colors.white, size: 16) + : const Icon(Icons.lock_open, + color: Colors.white, size: 16), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ); + } + + /// 提交 + void onSubmit() async { + if (editLocked) { + return; + } + + if (nameController.text.isEmpty) { + showErrorMessage('请输入模型名称'); + return; + } + + final ps = providers.where((e) => e.id != null || e.name != null).toList(); + if (ps.isEmpty) { + showErrorMessage('至少需要一个渠道'); + return; + } + + if (avatarUrl != null && + (!avatarUrl!.startsWith('http://') && + !avatarUrl!.startsWith('https://'))) { + final cancel = BotToast.showCustomLoading( + toastBuilder: (cancel) { + return const LoadingIndicator( + message: '正在上传头像,请稍后...', + ); + }, + allowClick: false, + ); + + try { + final res = await ImageUploader(widget.setting) + .upload(avatarUrl!, usage: 'avatar'); + avatarUrl = res.url; + } catch (e) { + showErrorMessage('上传头像失败'); + cancel(); + return; + } finally { + cancel(); + } + } + + final model = AdminModelUpdateReq( + name: nameController.text, + description: descriptionController.text, + shortName: shortNameController.text, + meta: AdminModelMeta( + maxContext: int.parse(maxContextController.text), + inputPrice: int.parse(inputPriceController.text), + outputPrice: int.parse(outputPriceController.text), + prompt: promptController.text, + vision: supportVision, + restricted: restricted, + ), + status: modelEnabled ? 1 : 2, + providers: ps, + avatarUrl: avatarUrl, + ); + + setState(() { + editLocked = true; + }); + + // ignore: use_build_context_synchronously + context.read().add(ModelUpdateEvent(widget.modelId, model)); + } + + /// 渠道名称 + String buildChannelName(AdminModelProvider provider) { + if (provider.id != null) { + return modelChannels.firstWhere((e) => e.id == provider.id).name; + } + + if (provider.name != null) { + return modelChannels + .firstWhere( + (e) => e.type == provider.name! && e.id == null, + orElse: () => AdminChannel(name: '未知', type: ''), + ) + .display; + } + + return '请选择'; + } +} diff --git a/lib/page/chat/group/edit.dart b/lib/page/chat/group/edit.dart index 9fb3a064..b62b99e3 100644 --- a/lib/page/chat/group/edit.dart +++ b/lib/page/chat/group/edit.dart @@ -238,7 +238,6 @@ class _GroupEditPageState extends State { context.pop(); }, usage: AvatarUsage.room, - randomSeed: randomSeed, defaultAvatarUrl: _avatarUrl, externalAvatarUrls: [ ...avatarPresets, diff --git a/lib/page/chat/room_create.dart b/lib/page/chat/room_create.dart index 73d384f5..ac413a09 100644 --- a/lib/page/chat/room_create.dart +++ b/lib/page/chat/room_create.dart @@ -347,7 +347,6 @@ class _RoomCreatePageState extends State { context.pop(); }, usage: AvatarUsage.room, - randomSeed: randomSeed, defaultAvatarId: _avatarId, defaultAvatarUrl: _avatarUrl, externalAvatarUrls: [ diff --git a/lib/page/chat/room_edit.dart b/lib/page/chat/room_edit.dart index 56a8d325..b88dbe65 100644 --- a/lib/page/chat/room_edit.dart +++ b/lib/page/chat/room_edit.dart @@ -236,7 +236,6 @@ class _RoomEditPageState extends State { context.pop(); }, usage: AvatarUsage.room, - randomSeed: randomSeed, defaultAvatarId: _avatarId, defaultAvatarUrl: _avatarUrl, externalAvatarIds: diff --git a/lib/page/component/avatar_selector.dart b/lib/page/component/avatar_selector.dart index 5528b276..8e2d4929 100644 --- a/lib/page/component/avatar_selector.dart +++ b/lib/page/component/avatar_selector.dart @@ -27,7 +27,6 @@ class Avatar { class AvatarSelector extends StatefulWidget { final Function(Avatar selected) onSelected; - final int randomSeed; final int? defaultAvatarId; final String? defaultAvatarUrl; @@ -40,7 +39,6 @@ class AvatarSelector extends StatefulWidget { const AvatarSelector({ super.key, required this.onSelected, - required this.randomSeed, this.defaultAvatarId, this.defaultAvatarUrl, required this.usage, diff --git a/lib/page/component/enhanced_textfield.dart b/lib/page/component/enhanced_textfield.dart index 7a027862..d6484f44 100644 --- a/lib/page/component/enhanced_textfield.dart +++ b/lib/page/component/enhanced_textfield.dart @@ -186,13 +186,24 @@ class _EnhancedTextFieldState extends State { width: widget.labelWidth ?? 80, child: widget.labelWidget != null ? widget.labelWidget! - : Text( - widget.labelText!, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: widget.labelFontSize ?? 16, - color: widget.customColors.textfieldLabelColor, - ), + : Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Text( + widget.labelText!, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: widget.labelFontSize ?? 16, + color: widget.customColors.textfieldLabelColor, + ), + ), + ), + if (widget.labelHelpWidget != null) ...[ + const SizedBox(width: 5), + widget.labelHelpWidget!, + ] + ], ), ), const SizedBox(width: 10), diff --git a/lib/page/setting/setting_screen.dart b/lib/page/setting/setting_screen.dart index bba71a9a..065e4b8c 100644 --- a/lib/page/setting/setting_screen.dart +++ b/lib/page/setting/setting_screen.dart @@ -27,7 +27,6 @@ import 'package:askaide/repo/settings_repo.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localization/flutter_localization.dart'; import 'package:go_router/go_router.dart'; @@ -69,11 +68,28 @@ class _SettingScreenState extends State { ), ), actions: [ + BlocBuilder( + buildWhen: (previous, current) => current is AccountLoaded, + builder: (context, state) { + if (state is AccountLoaded && state.user != null) { + return IconButton( + onPressed: () { + context.push('/admin/dashboard'); + }, + icon: const Icon(Icons.developer_board_outlined), + tooltip: '管理后台', + ); + } + + return const SizedBox(); + }, + ), IconButton( onPressed: () { context.push('/notifications'); }, icon: const Icon(Icons.notifications_outlined), + tooltip: '消息通知', ), ], child: BlocBuilder( @@ -282,36 +298,12 @@ class _SettingScreenState extends State { SettingsSection( title: const Text('实验室'), tiles: [ - if (userHasLabPermission(state)) - SettingsTile( - title: const Text('渠道管理'), - trailing: Icon( - CupertinoIcons.chevron_forward, - size: MediaQuery.of(context).textScaleFactor * 18, - color: Colors.grey, - ), - onPressed: (context) { - context.push('/admin/channels'); - }, - ), - if (userHasLabPermission(state)) - SettingsTile( - title: const Text('模型 Gallery'), - trailing: Icon( - CupertinoIcons.chevron_forward, - size: MediaQuery.of(context).textScaleFactor * 18, - color: Colors.grey, - ), - onPressed: (context) { - context.push('/creative-island/models'); - }, - ), if (userHasLabPermission(state)) SettingsTile( title: const Text('画板'), - trailing: Icon( + trailing: const Icon( CupertinoIcons.chevron_forward, - size: MediaQuery.of(context).textScaleFactor * 18, + size: 18, color: Colors.grey, ), onPressed: (context) { @@ -324,9 +316,9 @@ class _SettingScreenState extends State { // 诊断 SettingsTile( title: Text(AppLocale.diagnostic.getString(context)), - trailing: Icon( + trailing: const Icon( CupertinoIcons.chevron_forward, - size: MediaQuery.of(context).textScaleFactor * 18, + size: 18, color: Colors.grey, ), onPressed: (context) { diff --git a/lib/repo/api/admin/channels.dart b/lib/repo/api/admin/channels.dart index 309fdd59..2ce364c6 100644 --- a/lib/repo/api/admin/channels.dart +++ b/lib/repo/api/admin/channels.dart @@ -7,6 +7,10 @@ class AdminChannel { AdminChannelMeta? meta; + String get display { + return name; + } + AdminChannel({ this.id, required this.name, diff --git a/lib/repo/api/admin/models.dart b/lib/repo/api/admin/models.dart index e917f1e0..9a32e642 100644 --- a/lib/repo/api/admin/models.dart +++ b/lib/repo/api/admin/models.dart @@ -21,11 +21,11 @@ class AdminModel { factory AdminModel.fromJson(Map json) { return AdminModel( - modelId: json['modelId'], + modelId: json['model_id'], name: json['name'], - shortName: json['shortName'], + shortName: json['short_name'], description: json['description'], - avatarUrl: json['avatarUrl'], + avatarUrl: json['avatar_url'], status: json['status'], meta: json['meta'] != null ? AdminModelMeta.fromJson(json['meta']) : null, providers: ((json['providers'] ?? []) as List) @@ -36,11 +36,11 @@ class AdminModel { Map toJson() { return { - 'modelId': modelId, + 'model_id': modelId, 'name': name, - 'shortName': shortName, + 'short_name': shortName, 'description': description, - 'avatarUrl': avatarUrl, + 'avatar_url': avatarUrl, 'status': status, 'meta': meta?.toJson(), 'providers': providers.map((e) => e.toJson()).toList(), @@ -54,6 +54,7 @@ class AdminModelMeta { int? maxContext; int? inputPrice; int? outputPrice; + String? prompt; AdminModelMeta({ this.vision, @@ -61,15 +62,17 @@ class AdminModelMeta { this.maxContext, this.inputPrice, this.outputPrice, + this.prompt, }); factory AdminModelMeta.fromJson(Map json) { return AdminModelMeta( vision: json['vision'], restricted: json['restricted'], - maxContext: json['maxContext'], - inputPrice: json['inputPrice'], - outputPrice: json['outputPrice'], + maxContext: json['max_context'], + inputPrice: json['input_price'], + outputPrice: json['output_price'], + prompt: json['prompt'], ); } @@ -77,9 +80,10 @@ class AdminModelMeta { return { 'vision': vision, 'restricted': restricted, - 'maxContext': maxContext, - 'inputPrice': inputPrice, - 'outputPrice': outputPrice, + 'max_context': maxContext, + 'input_price': inputPrice, + 'output_price': outputPrice, + 'prompt': prompt, }; } } @@ -88,21 +92,18 @@ class AdminModelProvider { int? id; String? name; String? modelRewrite; - String? prompt; AdminModelProvider({ this.id, this.name, this.modelRewrite, - this.prompt, }); factory AdminModelProvider.fromJson(Map json) { return AdminModelProvider( id: json['id'], name: json['name'], - modelRewrite: json['modelRewrite'], - prompt: json['prompt'], + modelRewrite: json['model_rewrite'], ); } @@ -110,8 +111,7 @@ class AdminModelProvider { return { 'id': id, 'name': name, - 'modelRewrite': modelRewrite, - 'prompt': prompt, + 'model_rewrite': modelRewrite, }; } } @@ -139,11 +139,11 @@ class AdminModelAddReq { Map toJson() { return { - 'modelId': modelId, + 'model_id': modelId, 'name': name, - 'shortName': shortName, + 'short_name': shortName, 'description': description, - 'avatarUrl': avatarUrl, + 'avatar_url': avatarUrl, 'status': status, 'meta': meta?.toJson(), 'providers': providers?.map((e) => e.toJson()).toList(), @@ -173,9 +173,9 @@ class AdminModelUpdateReq { Map toJson() { return { 'name': name, - 'shortName': shortName, + 'short_name': shortName, 'description': description, - 'avatarUrl': avatarUrl, + 'avatar_url': avatarUrl, 'status': status, 'meta': meta?.toJson(), 'providers': providers?.map((e) => e.toJson()).toList(), diff --git a/lib/repo/api_server.dart b/lib/repo/api_server.dart index 0224c965..8d45bc36 100644 --- a/lib/repo/api_server.dart +++ b/lib/repo/api_server.dart @@ -1990,7 +1990,7 @@ class APIServer { /// 管理员接口:渠道类型 Future> adminChannelTypes() async { - return sendGetRequest('/v1/admin/channel-types', (resp) { + return sendCachedGetRequest('/v1/admin/channel-types', (resp) { var res = []; for (var item in resp.data['data']) { res.add(AdminChannelType.fromJson(item)); @@ -2000,6 +2000,24 @@ class APIServer { }); } + /// 管理员接口:返回聚合后的渠道列表 + Future> adminChannelsAgg() async { + final channels = await sendGetRequest('/v1/admin/channels', (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminChannel.fromJson(item)); + } + + return res; + }); + + final channelTypes = await adminChannelTypes(); + channels.addAll( + channelTypes.map((e) => AdminChannel(name: e.text, type: e.name))); + + return channels; + } + /// 管理员接口:返回所有渠道 Future> adminChannels() async { return sendGetRequest('/v1/admin/channels', (resp) { @@ -2045,19 +2063,26 @@ class APIServer { /// 管理员接口:返回所有模型 Future> adminModels() async { - return sendGetRequest('/v1/admin/models', (resp) { - var res = []; - for (var item in resp.data['data']) { - res.add(AdminModel.fromJson(item)); - } + return sendGetRequest( + '/v1/admin/models', + (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminModel.fromJson(item)); + } - return res; - }); + return res; + }, + queryParameters: { + 'sort': 'id:desc', + }, + ); } /// 管理员接口:返回指定模型 Future adminModel({required String modelId}) async { - return sendGetRequest('/v1/admin/models/$modelId', (resp) { + return sendGetRequest('/v1/admin/models/${Uri.encodeComponent(modelId)}', + (resp) { return AdminModel.fromJson(resp.data['data']); }); } @@ -2075,7 +2100,7 @@ class APIServer { Future adminUpdateModel( {required String modelId, required AdminModelUpdateReq req}) { return sendPutJSONRequest( - '/v1/admin/models/$modelId', + '/v1/admin/models/${Uri.encodeComponent(modelId)}', (resp) {}, data: req.toJson(), ); @@ -2083,6 +2108,7 @@ class APIServer { /// 管理员接口:删除模型 Future adminDeleteModel({required String modelId}) { - return sendDeleteRequest('/v1/admin/models/$modelId', (resp) {}); + return sendDeleteRequest( + '/v1/admin/models/${Uri.encodeComponent(modelId)}', (resp) {}); } } From 1b984961ec6d82375d16328a70d63f4ab19357a1 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 20 Mar 2024 18:13:06 +0800 Subject: [PATCH 17/36] =?UTF-8?q?=E8=81=8A=E5=A4=A9=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E5=88=87=E6=8D=A2=E4=BD=BF=E7=94=A8=E7=9A=84?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bloc/chat_event.dart | 4 +- lib/bloc/chat_message_bloc.dart | 16 +++- lib/helper/model_resolver.dart | 4 + lib/page/chat/component/model_switcher.dart | 53 +++++++++++ lib/page/chat/home_chat.dart | 55 +++++++++--- lib/page/chat/room_chat.dart | 47 +++++++++- lib/page/chat/room_create.dart | 2 + lib/page/component/chat/chat_input.dart | 4 +- lib/page/component/chat/chat_preview.dart | 14 ++- lib/page/component/model_item.dart | 97 +++++++++++++-------- lib/repo/openai_repo.dart | 11 ++- 11 files changed, 246 insertions(+), 61 deletions(-) create mode 100644 lib/page/chat/component/model_switcher.dart diff --git a/lib/bloc/chat_event.dart b/lib/bloc/chat_event.dart index c18e0f25..9dc61b22 100644 --- a/lib/bloc/chat_event.dart +++ b/lib/bloc/chat_event.dart @@ -13,8 +13,10 @@ class ChatMessageSendEvent extends ChatMessageEvent { final Message message; final int? index; final bool isResent; + final String? tempModel; - ChatMessageSendEvent(this.message, {this.index, this.isResent = false}); + ChatMessageSendEvent(this.message, + {this.index, this.isResent = false, this.tempModel}); } class ChatMessageGetRecentEvent extends ChatMessageEvent { diff --git a/lib/bloc/chat_message_bloc.dart b/lib/bloc/chat_message_bloc.dart index 4d0c38c6..cc36bed6 100644 --- a/lib/bloc/chat_message_bloc.dart +++ b/lib/bloc/chat_message_bloc.dart @@ -4,6 +4,7 @@ import 'package:askaide/bloc/bloc_manager.dart'; import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/error.dart'; +import 'package:askaide/helper/logger.dart'; import 'package:askaide/helper/model_resolver.dart'; import 'package:askaide/helper/queue.dart'; import 'package:askaide/lang/lang.dart'; @@ -267,10 +268,17 @@ class ChatMessageBloc extends BlocExt { } // 发送当前用户消息 - message.model = room.model; + message.model ??= room.model; message.userId = APIServer().localUserID(); message.status = 0; + // 模型切换 + String? tempModel = event.tempModel; + String? originalModel = message.model; + + Logger.instance + .d('发送消息, originalModel: $originalModel, tempModel: $tempModel'); + // 聊天历史记录中,所有发送状态为 pending 状态的消息,全部设置为失败 await chatMsgRepo.fixMessageStatus(roomId); @@ -289,7 +297,9 @@ class ChatMessageBloc extends BlocExt { ]); } } else { + message.model = tempModel ?? message.model; sentMessageId = await chatMsgRepo.sendMessage(roomId, message); + message.model = originalModel; } // 更新 Room 最后活跃时间 @@ -311,7 +321,7 @@ class ChatMessageBloc extends BlocExt { '', ts: DateTime.now(), type: MessageType.text, - model: room.model, + model: tempModel ?? originalModel, roomId: roomId, userId: APIServer().localUserID(), refId: sentMessageId, @@ -389,6 +399,7 @@ class ChatMessageBloc extends BlocExt { await ModelResolver.instance .request( room: room, + tempModel: tempModel, contextMessages: messages.sublist(0, messages.length - 1), onMessage: queue.add, maxTokens: room.maxTokens, @@ -470,6 +481,7 @@ class ChatMessageBloc extends BlocExt { roomId: roomId, userId: APIServer().localUserID(), chatHistoryId: localChatHistoryId, + model: tempModel ?? originalModel, ), ); } else { diff --git a/lib/helper/model_resolver.dart b/lib/helper/model_resolver.dart index 9e1b35e7..c96345a1 100644 --- a/lib/helper/model_resolver.dart +++ b/lib/helper/model_resolver.dart @@ -47,6 +47,7 @@ class ModelResolver { required List contextMessages, required Function(ChatStreamRespData value) onMessage, int? maxTokens, + String? tempModel, }) async { if (room.modelCategory() == modelTypeDeepAI) { return await _deepAIModel( @@ -72,6 +73,7 @@ class ModelResolver { contextMessages: contextMessages, onMessage: onMessage, maxTokens: maxTokens, + tempModel: tempModel, ); } } @@ -151,6 +153,7 @@ class ModelResolver { required List contextMessages, required Function(ChatStreamRespData value) onMessage, int? maxTokens, + String? tempModel, }) async { // 图像模式 if (OpenAIRepository.isImageModel(room.modelName())) { @@ -167,6 +170,7 @@ class ModelResolver { _buildRequestContext(room, contextMessages), onMessage, model: room.modelName(), + tempModel: tempModel, maxTokens: maxTokens, roomId: room.isLocalRoom ? null : room.id, ); diff --git a/lib/page/chat/component/model_switcher.dart b/lib/page/chat/component/model_switcher.dart new file mode 100644 index 00000000..fcf1fbae --- /dev/null +++ b/lib/page/chat/component/model_switcher.dart @@ -0,0 +1,53 @@ +import 'package:askaide/helper/haptic_feedback.dart'; +import 'package:askaide/page/chat/room_create.dart'; +import 'package:askaide/page/component/random_avatar.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:flutter/material.dart'; +import 'package:askaide/repo/model/model.dart' as mm; +import 'package:flutter_initicon/flutter_initicon.dart'; + +class ModelSwitcher extends StatelessWidget { + final mm.Model? value; + final Function(mm.Model? selected) onSelected; + + const ModelSwitcher({ + super.key, + required this.onSelected, + this.value, + }); + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return IconButton( + onPressed: () async { + HapticFeedbackHelper.mediumImpact(); + openSelectModelDialog( + context, + (selected) { + onSelected(selected.id == '' ? null : selected); + }, + initValue: value?.uid(), + enableClear: true, + ); + }, + icon: value == null + ? const Icon(Icons.alternate_email) + : value!.avatarUrl == null + ? Initicon( + text: value!.name.split('、').join(' '), + size: 25, + backgroundColor: Colors.grey.withAlpha(100), + borderRadius: BorderRadius.circular(8), + ) + : RemoteAvatar( + avatarUrl: value!.avatarUrl!, + size: 25, + ), + color: customColors.chatInputPanelText, + splashRadius: 20, + tooltip: '切换对话模型', + ); + } +} diff --git a/lib/page/chat/home_chat.dart b/lib/page/chat/home_chat.dart index 0d8a9d16..46474c03 100644 --- a/lib/page/chat/home_chat.dart +++ b/lib/page/chat/home_chat.dart @@ -8,6 +8,7 @@ import 'package:askaide/helper/global_store.dart'; import 'package:askaide/helper/model.dart'; import 'package:askaide/helper/upload.dart'; import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/chat/component/model_switcher.dart'; import 'package:askaide/page/chat/room_chat.dart'; import 'package:askaide/page/component/audio_player.dart'; import 'package:askaide/page/component/background_container.dart'; @@ -100,6 +101,9 @@ class _HomeChatPageState extends State { // 当前聊天所使用的模型(v2) HomeModelV2? currentModelV2; + /// 当前选择的模型 + mm.Model? tempModel; + @override void initState() { // 设置当前聊天 ID,当没有值时,会在第一个聊天消息发送后自动设置新值 @@ -441,7 +445,9 @@ class _HomeChatPageState extends State { handleSubmit(value); FocusManager.instance.primaryFocus?.unfocus(); }, - enableImageUpload: enableImageUpload, + enableImageUpload: tempModel == null + ? enableImageUpload + : (tempModel?.supportVision ?? false), onImageSelected: (files) { setState(() { selectedImageFiles = files; @@ -458,6 +464,18 @@ class _HomeChatPageState extends State { .read() .add(ChatMessageStopEvent()); }, + leftSideToolsBuilder: () { + return [ + ModelSwitcher( + onSelected: (selected) { + setState(() { + tempModel = selected; + }); + }, + value: tempModel, + ), + ]; + }, ); }, ), @@ -507,18 +525,28 @@ class _HomeChatPageState extends State { } final messages = loadedMessages.map((e) { - if (loadedState.chatHistory != null && - loadedState.chatHistory!.model != null) { - if (currentModelV2 != null) { - e.senderName = currentModelV2!.name; - e.avatarUrl = currentModelV2!.avatarUrl; - } else { - final mod = supportModels - .where((e) => e.id == loadedState.chatHistory!.model!) - .firstOrNull; - if (mod != null) { - e.senderName = mod.shortName; - e.avatarUrl = mod.avatarUrl; + if (e.model != null && !e.model!.startsWith('v2@')) { + final mod = supportModels.where((m) => m.id == e.model).firstOrNull; + if (mod != null) { + e.senderName = mod.shortName; + e.avatarUrl = mod.avatarUrl; + } + } + + if (e.avatarUrl == null || e.senderName == null) { + if (loadedState.chatHistory != null && + loadedState.chatHistory!.model != null) { + if (currentModelV2 != null) { + e.senderName = currentModelV2!.name; + e.avatarUrl = currentModelV2!.avatarUrl; + } else { + final mod = supportModels + .where((e) => e.id == loadedState.chatHistory!.model!) + .firstOrNull; + if (mod != null) { + e.senderName = mod.shortName; + e.avatarUrl = mod.avatarUrl; + } } } } @@ -633,6 +661,7 @@ class _HomeChatPageState extends State { ), index: index, isResent: isResent, + tempModel: tempModel?.id, ), ); diff --git a/lib/page/chat/room_chat.dart b/lib/page/chat/room_chat.dart index ff2428a8..a1c77909 100644 --- a/lib/page/chat/room_chat.dart +++ b/lib/page/chat/room_chat.dart @@ -6,6 +6,7 @@ import 'package:askaide/helper/image.dart'; import 'package:askaide/helper/model.dart'; import 'package:askaide/helper/upload.dart'; import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/chat/component/model_switcher.dart'; import 'package:askaide/page/component/audio_player.dart'; import 'package:askaide/page/component/background_container.dart'; import 'package:askaide/page/component/chat/chat_share.dart'; @@ -67,6 +68,12 @@ class _RoomChatPageState extends State { List selectedImageFiles = []; + /// 当前选择的模型 + mm.Model? tempModel; + + // 全量模型列表 + List supportModels = []; + @override void initState() { super.initState(); @@ -93,6 +100,13 @@ class _RoomChatPageState extends State { audioLoadding = loading; }); }; + + // 加载模型列表,用于查询模型名称 + ModelAggregate.models().then((value) { + setState(() { + supportModels = value; + }); + }); } @override @@ -194,8 +208,10 @@ class _RoomChatPageState extends State { _handleSubmit(value); FocusManager.instance.primaryFocus?.unfocus(); }, - enableImageUpload: roomModel != null && - roomModel!.supportVision, + enableImageUpload: tempModel == null + ? (roomModel != null && + roomModel!.supportVision) + : (tempModel?.supportVision ?? false), onImageSelected: (files) { setState(() { selectedImageFiles = files; @@ -212,6 +228,18 @@ class _RoomChatPageState extends State { .read() .add(ChatMessageStopEvent()); }, + leftSideToolsBuilder: () { + return [ + ModelSwitcher( + onSelected: (selected) { + setState(() { + tempModel = selected; + }); + }, + value: tempModel, + ), + ]; + }, ), ); }, @@ -298,8 +326,18 @@ class _RoomChatPageState extends State { } final messages = loadedMessages.map((e) { - e.avatarUrl = room.room.avatarUrl; - e.senderName = room.room.name; + if (e.model != null && !e.model!.startsWith('v2@')) { + final mod = + supportModels.where((m) => m.id == e.model).firstOrNull; + if (mod != null) { + e.senderName = mod.shortName; + e.avatarUrl = mod.avatarUrl; + } + } + if (e.avatarUrl == null || e.senderName == null) { + e.avatarUrl = room.room.avatarUrl; + e.senderName = room.room.name; + } return MessageWithState( e, @@ -514,6 +552,7 @@ class _RoomChatPageState extends State { ), index: index, isResent: isResent, + tempModel: tempModel?.id, ), ); diff --git a/lib/page/chat/room_create.dart b/lib/page/chat/room_create.dart index ac413a09..bf1eb6fb 100644 --- a/lib/page/chat/room_create.dart +++ b/lib/page/chat/room_create.dart @@ -611,6 +611,7 @@ void openSelectModelDialog( Function(mm.Model selected) onSelected, { String? initValue, List? reservedModels, + bool enableClear = false, }) { openModalBottomSheet( context, @@ -637,6 +638,7 @@ void openSelectModelDialog( context.pop(); }, initValue: initValue, + enableClear: enableClear, ); }); }, diff --git a/lib/page/component/chat/chat_input.dart b/lib/page/component/chat/chat_input.dart index 123ce304..b772ba95 100644 --- a/lib/page/component/chat/chat_input.dart +++ b/lib/page/component/chat/chat_input.dart @@ -223,6 +223,8 @@ class _ChatInputState extends State with TickerProviderStateMixin { // 聊天功能按钮 Row( children: [ + if (widget.leftSideToolsBuilder != null) + ...widget.leftSideToolsBuilder!(), if (widget.enableNotifier.value && widget.enableImageUpload && Ability().supportImageUploader && @@ -230,8 +232,6 @@ class _ChatInputState extends State with TickerProviderStateMixin { Ability().supportWebSocket) _buildImageUploadButton( context, setting, customColors), - if (widget.leftSideToolsBuilder != null) - ...widget.leftSideToolsBuilder!(), ], ), // 聊天输入框 diff --git a/lib/page/component/chat/chat_preview.dart b/lib/page/component/chat/chat_preview.dart index 595e60bc..11874b8b 100644 --- a/lib/page/component/chat/chat_preview.dart +++ b/lib/page/component/chat/chat_preview.dart @@ -12,6 +12,7 @@ import 'package:askaide/page/component/chat/chat_share.dart'; import 'package:askaide/page/component/chat/file_upload.dart'; import 'package:askaide/page/component/chat/message_state_manager.dart'; import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/random_avatar.dart'; import 'package:askaide/page/component/theme/custom_size.dart'; import 'package:askaide/repo/api_server.dart'; import 'package:bot_toast/bot_toast.dart'; @@ -547,8 +548,17 @@ class _ChatPreviewState extends State { } } - if (widget.robotAvatar != null && message.role == Role.receiver) { - return widget.robotAvatar!; + if (widget.robotAvatar != null) { + if (message.role == Role.receiver && message.avatarUrl != null) { + return RemoteAvatar( + avatarUrl: message.avatarUrl!, + size: 30, + ); + } + + if (message.role == Role.receiver) { + return widget.robotAvatar!; + } } return const SizedBox(); diff --git a/lib/page/component/model_item.dart b/lib/page/component/model_item.dart index 9fe02516..0d18088e 100644 --- a/lib/page/component/model_item.dart +++ b/lib/page/component/model_item.dart @@ -10,17 +10,34 @@ class ModelItem extends StatelessWidget { final List models; final Function(Model selected) onSelected; final String? initValue; + final bool enableClear; const ModelItem({ super.key, required this.models, required this.onSelected, this.initValue, + this.enableClear = false, }); @override Widget build(BuildContext context) { final customColors = Theme.of(context).extension()!; + + if (enableClear) { + models.insert( + 0, + Model( + '', + '重置', + '', + avatarUrl: null, + tag: null, + category: '', + ), + ); + } + return models.isNotEmpty ? Padding( padding: const EdgeInsets.only(top: 15), @@ -37,48 +54,58 @@ class ModelItem extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.min, children: [ - _buildAvatar(avatarUrl: item.avatarUrl, size: 40), - const SizedBox(width: 20), + if (item.avatarUrl != null) ...[ + _buildAvatar(avatarUrl: item.avatarUrl, size: 40), + const SizedBox(width: 20), + ], Expanded( child: Container( - alignment: Alignment.centerLeft, - child: Row(children: [ - Text( - item.name, - overflow: TextOverflow.ellipsis, - ), - if (item.tag != null && item.tag!.isNotEmpty) - Container( - decoration: BoxDecoration( - color: customColors.tagsBackgroundHover, - borderRadius: BorderRadius.circular(8), - ), - margin: const EdgeInsets.only(left: 5), - padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 2, - ), - child: Text( - item.tag!, - style: TextStyle( - fontSize: 10, - color: customColors.tagsText, + alignment: item.avatarUrl != null + ? Alignment.centerLeft + : Alignment.center, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + item.name, + overflow: TextOverflow.ellipsis, + ), + if (item.tag != null && + item.tag!.isNotEmpty && + item.avatarUrl != null) + Container( + decoration: BoxDecoration( + color: customColors.tagsBackgroundHover, + borderRadius: BorderRadius.circular(8), + ), + margin: const EdgeInsets.only(left: 5), + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 2, + ), + child: Text( + item.tag!, + style: TextStyle( + fontSize: 10, + color: customColors.tagsText, + ), ), ), - ), - ]), + ], + ), ), ), - SizedBox( - width: 10, - child: Icon( - Icons.check, - color: - initValue == item.uid() || initValue == item.id - ? customColors.linkColor - : Colors.transparent, + if (item.avatarUrl != null) + SizedBox( + width: 10, + child: Icon( + Icons.check, + color: initValue == item.uid() || + initValue == item.id + ? customColors.linkColor + : Colors.transparent, + ), ), - ), ], ), ), diff --git a/lib/repo/openai_repo.dart b/lib/repo/openai_repo.dart index 7c06d656..2ea6762a 100644 --- a/lib/repo/openai_repo.dart +++ b/lib/repo/openai_repo.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/env.dart'; +import 'package:askaide/helper/logger.dart'; import 'package:askaide/helper/platform.dart'; import 'package:askaide/helper/queue.dart'; import 'package:askaide/repo/model/chat_message.dart'; @@ -254,6 +255,7 @@ class OpenAIRepository { String model = defaultChatModel, int? roomId, int? maxTokens, + String? tempModel, }) async { var completer = Completer(); @@ -340,8 +342,9 @@ class OpenAIRepository { completer.completeError(e); }); - channel.sink.add(jsonEncode({ + final data = jsonEncode({ 'model': model, + 'temp_model': tempModel, 'messages': messages.map((e) => e.toMap()).toList(), 'temperature': temperature, 'user': user, @@ -350,7 +353,11 @@ class OpenAIRepository { (model.startsWith('openai:') || model.startsWith('gpt-')) ? null : roomId, // n 参数暂时用不到,复用作为 roomId - })); + }); + + Logger.instance.d('send chat request: $data'); + + channel.sink.add(data); } else { var chatStream = OpenAI.instance.chat.createStream( model: model, From a3a321a7c1f04cde78ef00bb3110e2dbeb59577a Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 20 Mar 2024 22:36:34 +0800 Subject: [PATCH 18/36] =?UTF-8?q?=E8=81=8A=E5=A4=A9=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B,=E6=94=AF=E6=8C=81=E9=87=8D=E7=BD=AE,?= =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/chat/component/model_switcher.dart | 8 ++- lib/page/chat/room_create.dart | 4 +- lib/page/component/model_item.dart | 66 +++++++++++++-------- lib/page/component/random_avatar.dart | 6 +- lib/page/component/weak_text_button.dart | 4 +- 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/lib/page/chat/component/model_switcher.dart b/lib/page/chat/component/model_switcher.dart index fcf1fbae..1f8f0455 100644 --- a/lib/page/chat/component/model_switcher.dart +++ b/lib/page/chat/component/model_switcher.dart @@ -26,24 +26,26 @@ class ModelSwitcher extends StatelessWidget { openSelectModelDialog( context, (selected) { - onSelected(selected.id == '' ? null : selected); + onSelected(selected); }, initValue: value?.uid(), enableClear: true, + title: '选择要切换的对话模型', ); }, icon: value == null - ? const Icon(Icons.alternate_email) + ? const Icon(Icons.smart_toy_outlined) : value!.avatarUrl == null ? Initicon( text: value!.name.split('、').join(' '), size: 25, backgroundColor: Colors.grey.withAlpha(100), - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(100), ) : RemoteAvatar( avatarUrl: value!.avatarUrl!, size: 25, + radius: 100, ), color: customColors.chatInputPanelText, splashRadius: 20, diff --git a/lib/page/chat/room_create.dart b/lib/page/chat/room_create.dart index bf1eb6fb..21ae1c28 100644 --- a/lib/page/chat/room_create.dart +++ b/lib/page/chat/room_create.dart @@ -608,10 +608,11 @@ class _RoomCreatePageState extends State { void openSelectModelDialog( BuildContext context, - Function(mm.Model selected) onSelected, { + Function(mm.Model? selected) onSelected, { String? initValue, List? reservedModels, bool enableClear = false, + String? title, }) { openModalBottomSheet( context, @@ -643,6 +644,7 @@ void openSelectModelDialog( }); }, heightFactor: 0.7, + title: title, ); } diff --git a/lib/page/component/model_item.dart b/lib/page/component/model_item.dart index 0d18088e..0883ac5b 100644 --- a/lib/page/component/model_item.dart +++ b/lib/page/component/model_item.dart @@ -3,12 +3,14 @@ import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/image.dart'; import 'package:askaide/page/component/random_avatar.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/page/component/weak_text_button.dart'; import 'package:askaide/repo/model/model.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class ModelItem extends StatelessWidget { final List models; - final Function(Model selected) onSelected; + final Function(Model? selected) onSelected; final String? initValue; final bool enableClear; @@ -24,18 +26,14 @@ class ModelItem extends StatelessWidget { Widget build(BuildContext context) { final customColors = Theme.of(context).extension()!; - if (enableClear) { - models.insert( - 0, - Model( - '', - '重置', - '', - avatarUrl: null, - tag: null, - category: '', - ), - ); + if (enableClear && initValue != null) { + // 将当前选中的模型放在第一位 + var index = + models.indexWhere((e) => e.uid() == initValue || e.id == initValue); + if (index != -1) { + var model = models.removeAt(index); + models.insert(0, model); + } } return models.isNotEmpty @@ -66,9 +64,11 @@ class ModelItem extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Text( - item.name, - overflow: TextOverflow.ellipsis, + Expanded( + child: Text( + item.name, + overflow: TextOverflow.ellipsis, + ), ), if (item.tag != null && item.tag!.isNotEmpty && @@ -95,17 +95,33 @@ class ModelItem extends StatelessWidget { ), ), ), - if (item.avatarUrl != null) - SizedBox( - width: 10, - child: Icon( - Icons.check, - color: initValue == item.uid() || + if (item.avatarUrl != null) ...[ + if (enableClear) + SizedBox( + width: 60, + child: initValue == item.uid() || initValue == item.id - ? customColors.linkColor - : Colors.transparent, + ? WeakTextButton( + title: '取消', + fontSize: 14, + onPressed: () { + onSelected(null); + }, + ) + : const SizedBox(), + ) + else + SizedBox( + width: 10, + child: Icon( + Icons.check, + color: initValue == item.uid() || + initValue == item.id + ? customColors.linkColor + : Colors.transparent, + ), ), - ), + ], ], ), ), diff --git a/lib/page/component/random_avatar.dart b/lib/page/component/random_avatar.dart index 532d0953..7a354ba3 100644 --- a/lib/page/component/random_avatar.dart +++ b/lib/page/component/random_avatar.dart @@ -51,7 +51,9 @@ class RandomAvatar extends StatelessWidget { class RemoteAvatar extends StatelessWidget { final String avatarUrl; final int? size; - const RemoteAvatar({super.key, required this.avatarUrl, this.size}); + final double? radius; + const RemoteAvatar( + {super.key, required this.avatarUrl, this.size, this.radius}); @override Widget build(BuildContext context) { @@ -59,7 +61,7 @@ class RemoteAvatar extends StatelessWidget { width: size?.toDouble() ?? 60, height: size?.toDouble() ?? 60, child: ClipRRect( - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(radius ?? 8), child: CachedNetworkImage( imageUrl: avatarUrl, fit: BoxFit.fill, diff --git a/lib/page/component/weak_text_button.dart b/lib/page/component/weak_text_button.dart index bf241fa7..763ba045 100644 --- a/lib/page/component/weak_text_button.dart +++ b/lib/page/component/weak_text_button.dart @@ -5,11 +5,13 @@ class WeakTextButton extends StatelessWidget { final String title; final IconData? icon; final VoidCallback? onPressed; + final double? fontSize; const WeakTextButton({ super.key, required this.title, this.icon, this.onPressed, + this.fontSize, }); @override @@ -29,7 +31,7 @@ class WeakTextButton extends StatelessWidget { title, style: TextStyle( color: customColors.weakLinkColor, - fontSize: 15, + fontSize: fontSize ?? 15.0, ), ), ], From 4a2e0fb46d88c1fe76eca2278492daa0dd027f75 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 21 Mar 2024 00:48:55 +0800 Subject: [PATCH 19/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E6=95=B0=E5=AD=97=E4=BA=BA=E8=81=8A=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bloc/chat_message_bloc.dart | 5 ++-- lib/bloc/room_bloc.dart | 14 ++++++--- lib/bloc/room_state.dart | 8 ++++++ lib/helper/constant.dart | 4 +++ lib/page/admin/dashboard.dart | 3 +- lib/page/chat/home_chat.dart | 28 +++++++++++------- lib/page/chat/room_chat.dart | 19 +++++++----- lib/page/chat/room_create.dart | 19 +++++++++++- lib/page/chat/rooms.dart | 51 ++++++++++++++++++++++++++++++++- lib/repo/openai_repo.dart | 3 +- 10 files changed, 123 insertions(+), 31 deletions(-) diff --git a/lib/bloc/chat_message_bloc.dart b/lib/bloc/chat_message_bloc.dart index cc36bed6..0688157c 100644 --- a/lib/bloc/chat_message_bloc.dart +++ b/lib/bloc/chat_message_bloc.dart @@ -4,7 +4,6 @@ import 'package:askaide/bloc/bloc_manager.dart'; import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/error.dart'; -import 'package:askaide/helper/logger.dart'; import 'package:askaide/helper/model_resolver.dart'; import 'package:askaide/helper/queue.dart'; import 'package:askaide/lang/lang.dart'; @@ -276,8 +275,8 @@ class ChatMessageBloc extends BlocExt { String? tempModel = event.tempModel; String? originalModel = message.model; - Logger.instance - .d('发送消息, originalModel: $originalModel, tempModel: $tempModel'); + // Logger.instance + // .d('发送消息, originalModel: $originalModel, tempModel: $tempModel'); // 聊天历史记录中,所有发送状态为 pending 状态的消息,全部设置为失败 await chatMsgRepo.fixMessageStatus(roomId); diff --git a/lib/bloc/room_bloc.dart b/lib/bloc/room_bloc.dart index 8417ed20..c977baa9 100644 --- a/lib/bloc/room_bloc.dart +++ b/lib/bloc/room_bloc.dart @@ -136,15 +136,18 @@ class RoomBloc extends BlocExt { emit(RoomsLoading()); try { + int id = 0; if (Ability().isUserLogon()) { - await APIServer().createRoom( + final segs = event.model.split(':'); + + id = await APIServer().createRoom( name: event.name, vendor: event.model.startsWith('v2@') ? '' - : event.model.split(':').first, + : (segs.length > 1 ? segs.first : ''), model: event.model.startsWith('v2@') ? event.model - : event.model.split(':').last, + : (segs.length > 1 ? segs.last : event.model), systemPrompt: event.prompt, avatarId: event.avatarId, avatarUrl: event.avatarUrl, @@ -152,7 +155,7 @@ class RoomBloc extends BlocExt { initMessage: event.initMessage, ); } else { - await chatMsgRepo.createRoom( + final room = await chatMsgRepo.createRoom( name: event.name, category: 'chat', model: event.model, @@ -160,8 +163,11 @@ class RoomBloc extends BlocExt { userId: APIServer().localUserID(), maxContext: event.maxContext, ); + + id = room.id!; } + emit(RoomOperationResult(true, redirect: '/room/$id/chat')); emit(await createRoomsLoadedState(cache: false)); } catch (e) { emit(RoomsLoaded(const [], error: e.toString())); diff --git a/lib/bloc/room_state.dart b/lib/bloc/room_state.dart index b822eb75..d695d64a 100644 --- a/lib/bloc/room_state.dart +++ b/lib/bloc/room_state.dart @@ -51,3 +51,11 @@ class GroupRoomUpdateResultState extends RoomState { GroupRoomUpdateResultState(this.success, {this.error}); } + +class RoomOperationResult extends RoomState { + final bool success; + final Object? error; + final String? redirect; + + RoomOperationResult(this.success, {this.error, this.redirect}); +} diff --git a/lib/helper/constant.dart b/lib/helper/constant.dart index d14cb44e..5c5ad971 100644 --- a/lib/helper/constant.dart +++ b/lib/helper/constant.dart @@ -92,3 +92,7 @@ const universalLink = 'https://ai.aicode.cc/wechat-login/'; const qiniuImageTypeAvatar = 'avatar'; const qiniuImageTypeThumb = 'thumb'; const qiniuImageTypeThumbMedium = 'thumb_500'; + +// 缓存相关的 Keys +// 最后一次使用的模型 +const cacheKeyLastModel = 'last-model'; diff --git a/lib/page/admin/dashboard.dart b/lib/page/admin/dashboard.dart index 7310760b..dfe31874 100644 --- a/lib/page/admin/dashboard.dart +++ b/lib/page/admin/dashboard.dart @@ -1,6 +1,5 @@ import 'package:askaide/page/component/background_container.dart'; import 'package:askaide/page/component/theme/custom_size.dart'; -import 'package:askaide/page/component/theme/custom_theme.dart'; import 'package:askaide/repo/settings_repo.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -18,7 +17,7 @@ class AdminDashboardPage extends StatefulWidget { class _AdminDashboardPageState extends State { @override Widget build(BuildContext context) { - final customColors = Theme.of(context).extension()!; + // final customColors = Theme.of(context).extension()!; return BackgroundContainer( setting: widget.setting, diff --git a/lib/page/chat/home_chat.dart b/lib/page/chat/home_chat.dart index 46474c03..4ad3d6ae 100644 --- a/lib/page/chat/home_chat.dart +++ b/lib/page/chat/home_chat.dart @@ -204,17 +204,21 @@ class _HomeChatPageState extends State { if (state.room.model.startsWith('v2@')) { if (currentModelV2 != null && currentModelV2!.modelId != null) { // 加载免费使用次数 + if (tempModel == null) { + // ignore: use_build_context_synchronously + context.read().add(FreeCountReloadEvent( + model: currentModelV2!.modelId!, + )); + } + } + } else { + // 加载免费使用次数 + if (tempModel == null) { // ignore: use_build_context_synchronously context.read().add(FreeCountReloadEvent( - model: currentModelV2!.modelId!, + model: widget.model ?? state.room.model, )); } - } else { - // 加载免费使用次数 - // ignore: use_build_context_synchronously - context.read().add(FreeCountReloadEvent( - model: widget.model ?? state.room.model, - )); } } }, @@ -369,9 +373,11 @@ class _HomeChatPageState extends State { enableInput.value = false; }); } else if (!state.processing && !enableInput.value) { - // 更新免费使用次数 - context.read().add(FreeCountReloadEvent( - model: widget.model ?? room.room.model)); + if (tempModel == null) { + // 更新免费使用次数 + context.read().add(FreeCountReloadEvent( + model: widget.model ?? room.room.model)); + } // 聊天回复完成时,取消输入框的禁止编辑状态 setState(() { @@ -409,7 +415,7 @@ class _HomeChatPageState extends State { child: BlocBuilder( builder: (context, freeState) { var hintText = '有问题尽管问我'; - if (freeState is FreeCountLoadedState) { + if (freeState is FreeCountLoadedState && tempModel == null) { final matched = freeState.model(widget.model ?? room.room.model); if (matched != null && diff --git a/lib/page/chat/room_chat.dart b/lib/page/chat/room_chat.dart index a1c77909..669921e8 100644 --- a/lib/page/chat/room_chat.dart +++ b/lib/page/chat/room_chat.dart @@ -139,9 +139,11 @@ class _RoomChatPageState extends State { listener: (context, state) { if (state is RoomLoaded && state.cascading) { // 加载免费使用次数 - context - .read() - .add(FreeCountReloadEvent(model: state.room.model)); + if (tempModel == null) { + context + .read() + .add(FreeCountReloadEvent(model: state.room.model)); + } } if (state is RoomLoaded) { @@ -186,7 +188,8 @@ class _RoomChatPageState extends State { child: BlocBuilder( builder: (context, freeState) { var hintText = '有问题尽管问我'; - if (freeState is FreeCountLoadedState) { + if (freeState is FreeCountLoadedState && + tempModel == null) { final matched = freeState.model(room.room.model); if (matched != null && matched.leftCount > 0 && @@ -287,9 +290,11 @@ class _RoomChatPageState extends State { }); } else if (!state.processing && !_inputEnabled.value) { // 更新免费使用次数 - context - .read() - .add(FreeCountReloadEvent(model: room.room.model)); + if (tempModel == null) { + context + .read() + .add(FreeCountReloadEvent(model: room.room.model)); + } // 聊天回复完成时,取消输入框的禁止编辑状态 setState(() { diff --git a/lib/page/chat/room_create.dart b/lib/page/chat/room_create.dart index 21ae1c28..08400ea0 100644 --- a/lib/page/chat/room_create.dart +++ b/lib/page/chat/room_create.dart @@ -613,12 +613,29 @@ void openSelectModelDialog( List? reservedModels, bool enableClear = false, String? title, + String? priorityModelId, }) { + future() async { + final models = await ModelAggregate.models(); + + if (priorityModelId != null) { + // 将 models 中,id 与 priorityModelId 相同的元素排序到最前面 + final index = models.indexWhere( + (e) => e.id == priorityModelId || e.uid() == priorityModelId); + if (index != -1) { + final model = models.removeAt(index); + models.insert(0, model); + } + } + + return models; + } + openModalBottomSheet( context, (context) { return FutureBuilder( - future: ModelAggregate.models(), + future: future(), builder: (context, snapshot) { if (snapshot.hasError) { showErrorMessage(resolveError(context, snapshot.error!)); diff --git a/lib/page/chat/rooms.dart b/lib/page/chat/rooms.dart index 904f28be..8dc4b258 100644 --- a/lib/page/chat/rooms.dart +++ b/lib/page/chat/rooms.dart @@ -1,7 +1,10 @@ import 'package:askaide/helper/ability.dart'; +import 'package:askaide/helper/cache.dart'; +import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/event.dart'; import 'package:askaide/lang/lang.dart'; import 'package:askaide/bloc/room_bloc.dart'; +import 'package:askaide/page/chat/room_create.dart'; import 'package:askaide/page/component/background_container.dart'; import 'package:askaide/page/component/enhanced_button.dart'; import 'package:askaide/page/component/enhanced_error.dart'; @@ -60,6 +63,18 @@ class _RoomsPageState extends State { if (state is RoomCreateError) { showErrorMessageEnhanced(context, state.error); } + + if (state is RoomOperationResult) { + if (state.success) { + if (state.redirect != null) { + context.push(state.redirect!).then((value) { + context.read().add(RoomsLoadEvent()); + }); + } + } else { + showErrorMessageEnhanced(context, state.error ?? '操作失败'); + } + } }, buildWhen: (previous, current) => current is RoomsLoading || current is RoomsLoaded, @@ -75,6 +90,40 @@ class _RoomsPageState extends State { if (selectedSuggestions.isEmpty) EnhancedPopupMenu( items: [ + if (Ability().isUserLogon() && + !Ability().enableLocalOpenAI) + EnhancedPopupMenuItem( + title: '快速开始', + icon: Icons.quickreply_outlined, + onTap: (p0) async { + final lastModel = await Cache() + .stringGet(key: cacheKeyLastModel); + openSelectModelDialog( + // ignore: use_build_context_synchronously + context, + (selected) { + if (selected == null) { + return; + } + // 缓存最后一次使用的模型 ID,下次创建时自动排在最前面 + Cache().setString( + key: cacheKeyLastModel, + value: selected.id, + ); + + context.read().add( + RoomCreateEvent( + selected.name, + selected.id, + null, + ), + ); + }, + title: '选择要对话的模型', + priorityModelId: lastModel, + ); + }, + ), EnhancedPopupMenuItem( title: '创建数字人', icon: Icons.person_add_alt_outlined, @@ -88,7 +137,7 @@ class _RoomsPageState extends State { !Ability().enableLocalOpenAI) EnhancedPopupMenuItem( title: '发起群聊', - icon: Icons.chat_bubble_outline, + icon: Icons.forum_outlined, onTap: (p0) { context .push('/group-chat-create') diff --git a/lib/repo/openai_repo.dart b/lib/repo/openai_repo.dart index 2ea6762a..b5545ee2 100644 --- a/lib/repo/openai_repo.dart +++ b/lib/repo/openai_repo.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/env.dart'; -import 'package:askaide/helper/logger.dart'; import 'package:askaide/helper/platform.dart'; import 'package:askaide/helper/queue.dart'; import 'package:askaide/repo/model/chat_message.dart'; @@ -355,7 +354,7 @@ class OpenAIRepository { : roomId, // n 参数暂时用不到,复用作为 roomId }); - Logger.instance.d('send chat request: $data'); + // Logger.instance.d('send chat request: $data'); channel.sink.add(data); } else { From ef698403b7c680c26aee5ffd4ba3a9d21b8ac1b9 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 21 Mar 2024 00:58:26 +0800 Subject: [PATCH 20/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=98=E6=96=B9?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/setting/setting_screen.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/page/setting/setting_screen.dart b/lib/page/setting/setting_screen.dart index 065e4b8c..012b8d93 100644 --- a/lib/page/setting/setting_screen.dart +++ b/lib/page/setting/setting_screen.dart @@ -496,6 +496,7 @@ class _SettingScreenState extends State { Future>> _defaultServerList() async { return [ SelectorItem(const Text('官方正式服务器'), apiServerURL), + SelectorItem(const Text('官方测试服务器'), 'https://api.chatllm.app'), SelectorItem(const Text('本地开发机'), 'http://localhost:8080'), ]; } From d100805e8db5fceed4193296f3daf235235b2d2e Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 21 Mar 2024 17:53:23 +0800 Subject: [PATCH 21/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/bloc/user_bloc.dart | 35 +++ lib/bloc/user_event.dart | 28 ++ lib/bloc/user_state.dart | 31 ++ lib/main.dart | 39 +++ lib/page/admin/dashboard.dart | 16 + lib/page/admin/user.dart | 490 +++++++++++++++++++++++++++++ lib/page/admin/users.dart | 402 +++++++++++++++++++++++ lib/page/component/pagination.dart | 101 ++++++ lib/repo/api/admin/users.dart | 84 +++++ lib/repo/api_server.dart | 64 ++++ 10 files changed, 1290 insertions(+) create mode 100644 lib/bloc/user_bloc.dart create mode 100644 lib/bloc/user_event.dart create mode 100644 lib/bloc/user_state.dart create mode 100644 lib/page/admin/user.dart create mode 100644 lib/page/admin/users.dart create mode 100644 lib/page/component/pagination.dart create mode 100644 lib/repo/api/admin/users.dart diff --git a/lib/bloc/user_bloc.dart b/lib/bloc/user_bloc.dart new file mode 100644 index 00000000..c46cc9c4 --- /dev/null +++ b/lib/bloc/user_bloc.dart @@ -0,0 +1,35 @@ +import 'package:askaide/repo/api/admin/users.dart'; +import 'package:askaide/repo/api/page.dart'; +import 'package:askaide/repo/api/quota.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; + +part 'user_event.dart'; +part 'user_state.dart'; + +class UserBloc extends Bloc { + UserBloc() : super(UserInitial()) { + // 加载指定用户信息 + on((event, emit) async { + final user = await APIServer().adminUser(id: event.userId); + emit(UserLoaded(user)); + }); + + // 加载用户列表 + on((event, emit) async { + final users = await APIServer().adminUsers( + page: event.page, + perPage: event.perPage, + keyword: event.keyword, + ); + emit(UsersLoaded(users)); + }); + + // 加载用户配额 + on((event, emit) async { + final quota = await APIServer().adminUserQuota(userId: event.userId); + emit(UserQuotaLoaded(quota)); + }); + } +} diff --git a/lib/bloc/user_event.dart b/lib/bloc/user_event.dart new file mode 100644 index 00000000..e690fda8 --- /dev/null +++ b/lib/bloc/user_event.dart @@ -0,0 +1,28 @@ +part of 'user_bloc.dart'; + +@immutable +sealed class UserEvent {} + +class UserLoadEvent extends UserEvent { + final int userId; + + UserLoadEvent(this.userId); +} + +class UserListLoadEvent extends UserEvent { + final int page; + final int perPage; + final String? keyword; + + UserListLoadEvent({ + this.page = 1, + this.perPage = 20, + this.keyword, + }); +} + +class UserQuotaLoadEvent extends UserEvent { + final int userId; + + UserQuotaLoadEvent(this.userId); +} diff --git a/lib/bloc/user_state.dart b/lib/bloc/user_state.dart new file mode 100644 index 00000000..5fd4c3d6 --- /dev/null +++ b/lib/bloc/user_state.dart @@ -0,0 +1,31 @@ +part of 'user_bloc.dart'; + +@immutable +sealed class UserState {} + +final class UserInitial extends UserState {} + +class UserLoaded extends UserState { + final AdminUser user; + + UserLoaded(this.user); +} + +class UserOperationResult extends UserState { + final bool success; + final String? message; + + UserOperationResult(this.success, {this.message}); +} + +class UsersLoaded extends UserState { + final PagedData users; + + UsersLoaded(this.users); +} + +class UserQuotaLoaded extends UserState { + final QuotaResp quota; + + UserQuotaLoaded(this.quota); +} diff --git a/lib/main.dart b/lib/main.dart index 5b15a6f5..6292721d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:askaide/bloc/channel_bloc.dart'; import 'package:askaide/bloc/model_bloc.dart'; +import 'package:askaide/bloc/user_bloc.dart'; import 'package:askaide/helper/path.dart'; import 'package:askaide/page/admin/channels.dart'; import 'package:askaide/page/admin/channels_add.dart'; @@ -8,6 +9,8 @@ import 'package:askaide/page/admin/dashboard.dart'; import 'package:askaide/page/admin/models.dart'; import 'package:askaide/page/admin/models_add.dart'; import 'package:askaide/page/admin/models_edit.dart'; +import 'package:askaide/page/admin/user.dart'; +import 'package:askaide/page/admin/users.dart'; import 'package:askaide/page/balance/web_payment_proxy.dart'; import 'package:askaide/page/balance/web_payment_result.dart'; import 'package:askaide/page/creative_island/draw/artistic_wordart.dart'; @@ -1189,6 +1192,42 @@ class MyApp extends StatefulWidget { ); }, ), + GoRoute( + name: 'admin-users', + path: '/admin/users', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => UserBloc(), + ), + ], + child: AdminUsersPage(setting: settingRepo), + ), + ); + }, + ), + GoRoute( + name: 'admin-users-detail', + path: '/admin/users/:id', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + final userId = int.parse(state.pathParameters['id']!); + + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => UserBloc(), + ), + ], + child: AdminUserPage(setting: settingRepo, userId: userId), + ), + ); + }, + ), ], ) ], diff --git a/lib/page/admin/dashboard.dart b/lib/page/admin/dashboard.dart index dfe31874..ec916799 100644 --- a/lib/page/admin/dashboard.dart +++ b/lib/page/admin/dashboard.dart @@ -62,6 +62,22 @@ class _AdminDashboardPageState extends State { ), ], ), + SettingsSection( + title: const Text('用户管理'), + tiles: [ + SettingsTile( + title: const Text('用户列表'), + trailing: const Icon( + CupertinoIcons.chevron_forward, + size: 18, + color: Colors.grey, + ), + onPressed: (context) { + context.push('/admin/users'); + }, + ), + ], + ), SettingsSection( title: const Text('系统设置'), tiles: [ diff --git a/lib/page/admin/user.dart b/lib/page/admin/user.dart new file mode 100644 index 00000000..d99e2eeb --- /dev/null +++ b/lib/page/admin/user.dart @@ -0,0 +1,490 @@ +import 'package:askaide/bloc/user_bloc.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/admin/users.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/coin.dart'; +import 'package:askaide/page/component/column_block.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/enhanced_button.dart'; +import 'package:askaide/page/component/enhanced_textfield.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/page/creative_island/gallery/gallery_item.dart'; +import 'package:askaide/repo/api/quota.dart'; +import 'package:askaide/repo/api_server.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:intl/intl.dart'; + +class AdminUserPage extends StatefulWidget { + final SettingRepository setting; + final int userId; + const AdminUserPage({ + super.key, + required this.setting, + required this.userId, + }); + + @override + State createState() => _AdminUserPageState(); +} + +class _AdminUserPageState extends State { + @override + void initState() { + context.read().add(UserLoadEvent(widget.userId)); + context.read().add(UserQuotaLoadEvent(widget.userId)); + super.initState(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '用户详情', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + actions: [ + IconButton( + icon: const Icon(Icons.card_giftcard_outlined), + tooltip: '赠送智慧果', + onPressed: () { + int sendCount = 1000; + String? note; + int validDays = 365; + + openDialog( + context, + builder: Builder(builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + '赠送智慧果', + style: TextStyle(fontSize: 18), + ), + const SizedBox(height: 10), + EnhancedTextField( + labelText: '数量', + customColors: customColors, + textAlignVertical: TextAlignVertical.top, + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + suffixIcon: Container( + width: 110, + alignment: Alignment.center, + child: Text( + '个智慧果', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12, + ), + ), + ), + onChanged: (value) { + sendCount = int.tryParse(value) ?? 0; + }, + initValue: sendCount.toString(), + ), + const SizedBox(height: 10), + EnhancedTextField( + labelText: '有效期', + customColors: customColors, + textAlignVertical: TextAlignVertical.top, + showCounter: false, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + suffixIcon: Container( + width: 110, + alignment: Alignment.center, + child: Text( + '天', + style: TextStyle( + color: customColors.weakTextColor, + fontSize: 12, + ), + ), + ), + onChanged: (value) { + validDays = int.tryParse(value) ?? 0; + }, + initValue: validDays.toString(), + ), + const SizedBox(height: 10), + EnhancedTextField( + labelText: '备注', + customColors: customColors, + textAlignVertical: TextAlignVertical.top, + showCounter: false, + hintText: '可选', + onChanged: (value) { + note = value; + }, + initValue: note, + ), + ], + ); + }), + onSubmit: () { + if (sendCount <= 0) { + showErrorMessage('数量必须大于 0'); + return false; + } + + if (validDays <= 0) { + showErrorMessage('有效期必须大于 0'); + return false; + } + + APIServer() + .adminUserQuotaAssign( + userId: widget.userId, + quota: sendCount, + validPeriod: validDays * 24, + note: note, + ) + .then((value) { + showSuccessMessage('赠送成功'); + context + .read() + .add(UserQuotaLoadEvent(widget.userId)); + }).onError( + (error, stackTrace) => + showErrorMessageEnhanced(context, error!), + ); + + return true; + }, + ); + }, + ), + ], + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: RefreshIndicator( + color: customColors.linkColor, + onRefresh: () async { + context.read().add(UserLoadEvent(widget.userId)); + context.read().add(UserQuotaLoadEvent(widget.userId)); + }, + displacement: 20, + child: SafeArea( + top: false, + child: SingleChildScrollView( + child: Column( + children: [ + BlocConsumer( + listenWhen: (previous, current) => + current is UserOperationResult, + listener: (context, state) { + if (state is UserOperationResult) { + if (state.success) { + showSuccessMessage(state.message ?? + AppLocale.operateSuccess.getString(context)); + context.read().add(UserListLoadEvent()); + } else { + showErrorMessage(state.message ?? + AppLocale.operateFailed.getString(context)); + } + } + }, + buildWhen: (previous, current) => current is UserLoaded, + builder: (context, state) { + if (state is UserLoaded) { + return ColumnBlock( + innerPanding: 10, + padding: const EdgeInsets.all(15), + margin: const EdgeInsets.all(15), + children: [ + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + SizedBox( + width: double.infinity, + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'ID', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: + customColors.weakTextColor, + ), + ), + const SizedBox(width: 10), + Text( + '${state.user.id}', + style: TextStyle( + fontSize: 12, + color: + customColors.weakTextColor, + ), + maxLines: 5, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + const SizedBox(height: 10), + buildTags( + context, customColors, state.user), + ], + ), + ), + buildUserAvatar( + state.user, + radius: BorderRadius.circular(8), + ), + ], + ), + TextItem( + title: '类型', + value: state.user.userType ?? '-', + ), + if (state.user.phone != null && + state.user.phone!.isNotEmpty) + TextItem( + title: '手机号', + value: state.user.phone!, + ), + if (state.user.email != null && + state.user.email!.isNotEmpty) + TextItem( + title: '邮箱', + value: state.user.email!, + ), + if (state.user.realname != null && + state.user.realname!.isNotEmpty) + TextItem( + title: '昵称', + value: state.user.realname!, + ), + if (state.user.invitedBy != null && + state.user.invitedBy! > 0) + TextItem( + title: '邀请人 ID', + value: '${state.user.invitedBy}', + ), + if (state.user.createdAt != null) + TextItem( + title: '注册时间', + value: + state.user.createdAt!.toLocal().toString(), + ), + TextItem( + title: '状态', + value: state.user.status ?? '-', + ), + ], + ); + } + + return Center( + child: CircularProgressIndicator( + color: customColors.linkColor, + ), + ); + }, + ), + BlocBuilder( + buildWhen: (previous, current) => + current is UserQuotaLoaded, + builder: (context, state) { + if (state is UserQuotaLoaded) { + return ColumnBlock( + innerPanding: 10, + padding: const EdgeInsets.all(15), + margin: const EdgeInsets.only( + left: 15, + right: 15, + bottom: 15, + ), + children: [ + TextItem( + title: '剩余智慧果', + value: state.quota.total.toString(), + ), + buildPaymentDetails(customColors, state) + ], + ); + } + + return Center( + child: CircularProgressIndicator( + color: customColors.linkColor, + ), + ); + }, + ), + ], + ), + ), + ), + ), + ), + ); + } + + // 购买历史记录 + Widget buildPaymentDetails( + CustomColors customColors, + UserQuotaLoaded state, + ) { + return SizedBox( + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '充值历史', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: customColors.weakTextColor, + ), + ), + const SizedBox(height: 10), + if (state.quota.details.isEmpty) + const Text('无充值记录') + else + ListView( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + children: [ + for (var item in state.quota.details) + Stack( + children: [ + Container( + margin: const EdgeInsets.symmetric(vertical: 6), + padding: const EdgeInsets.only( + top: 20, + bottom: 10, + left: 16, + right: 16, + ), + decoration: BoxDecoration( + color: customColors.paymentItemBackgroundColor, + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + (item.note == null || item.note == '') + ? '购买' + : item.note!, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 5), + Text( + DateFormat( + 'yyyy/MM/dd HH:mm', + ).format(item.createdAt.toLocal()), + textScaleFactor: 0.8, + style: TextStyle( + color: Colors.grey[600], + ), + ), + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Coin( + count: item.quota, + color: Colors.amber, + withAddPrefix: true, + fontWeight: FontWeight.w500, + ), + Text( + '${DateFormat('yyyy/MM/dd').format(item.periodEndAt.toLocal())} 过期', + textScaleFactor: 0.7, + ), + ], + ), + ], + ), + ], + ), + ), + _buildTagForItem(item), + ], + ) + ], + ), + ], + ), + ); + } + + Widget _buildTagForItem(QuotaDetail item) { + if (item.rest <= 0) { + return _buildTag(AppLocale.usedUp.getString(context), Colors.orange); + } + + if (item.expired) { + return _buildTag(AppLocale.expired.getString(context), Colors.grey[600]!); + } + + return const SizedBox(); + } + + Widget _buildTag(String text, Color color) { + return Positioned( + right: 1, + top: 7, + child: Container( + decoration: BoxDecoration( + color: color, + borderRadius: const BorderRadius.only( + topRight: Radius.circular(9), + bottomLeft: Radius.circular(9), + ), + ), + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 2, + ), + child: Text( + text, + textScaleFactor: 0.6, + style: const TextStyle(color: Colors.white70), + ), + ), + ); + } +} diff --git a/lib/page/admin/users.dart b/lib/page/admin/users.dart new file mode 100644 index 00000000..bef3b58c --- /dev/null +++ b/lib/page/admin/users.dart @@ -0,0 +1,402 @@ +import 'package:askaide/bloc/user_bloc.dart'; +import 'package:askaide/helper/constant.dart'; +import 'package:askaide/helper/helper.dart'; +import 'package:askaide/helper/image.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/pagination.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/admin/users.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_initicon/flutter_initicon.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:go_router/go_router.dart'; + +class AdminUsersPage extends StatefulWidget { + final SettingRepository setting; + const AdminUsersPage({ + super.key, + required this.setting, + }); + + @override + State createState() => _AdminUsersPageState(); +} + +class _AdminUsersPageState extends State { + /// 当前页码 + int page = 1; + + /// 每页数量 + int perPage = 20; + + /// 搜索关键字 + final TextEditingController keywordController = TextEditingController(); + + @override + void initState() { + context.read().add(UserListLoadEvent( + perPage: perPage, + page: page, + keyword: keywordController.text, + )); + super.initState(); + } + + @override + void dispose() { + keywordController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '用户管理', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: Column( + children: [ + Container( + padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5), + child: TextField( + controller: keywordController, + textAlignVertical: TextAlignVertical.center, + style: TextStyle(color: customColors.dialogDefaultTextColor), + decoration: InputDecoration( + hintText: AppLocale.search.getString(context), + hintStyle: TextStyle( + color: customColors.dialogDefaultTextColor, + ), + prefixIcon: Icon( + Icons.search, + color: customColors.dialogDefaultTextColor, + ), + isDense: true, + border: InputBorder.none, + ), + onEditingComplete: () { + context.read().add(UserListLoadEvent( + perPage: perPage, + page: page, + keyword: keywordController.text, + )); + }, + ), + ), + Expanded( + child: RefreshIndicator( + color: customColors.linkColor, + onRefresh: () async { + context.read().add(UserListLoadEvent( + perPage: perPage, + page: page, + keyword: keywordController.text, + )); + }, + displacement: 20, + child: BlocConsumer( + listener: (context, state) { + if (state is UserOperationResult) { + if (state.success) { + showSuccessMessage(state.message ?? + AppLocale.operateSuccess.getString(context)); + context.read().add(UserListLoadEvent()); + } else { + showErrorMessage(state.message ?? + AppLocale.operateFailed.getString(context)); + } + } + + if (state is UsersLoaded) { + setState(() { + page = state.users.page; + perPage = state.users.perPage; + }); + } + }, + buildWhen: (previous, current) => current is UsersLoaded, + builder: (context, state) { + if (state is UsersLoaded) { + return SafeArea( + top: false, + child: Column( + children: [ + Expanded( + child: ListView.builder( + padding: const EdgeInsets.all(5), + itemCount: state.users.data.length, + itemBuilder: (context, index) { + return buildUserInfo( + context, + customColors, + state.users.data[index], + ); + }, + ), + ), + if (state.users.lastPage != null && + state.users.lastPage! > 1) + Container( + padding: const EdgeInsets.all(10), + child: Pagination( + numOfPages: state.users.lastPage ?? 1, + selectedPage: page, + pagesVisible: 5, + onPageChanged: (selected) { + context + .read() + .add(UserListLoadEvent( + perPage: perPage, + page: selected, + keyword: keywordController.text, + )); + }, + ), + ), + ], + ), + ); + } + + return const Center( + child: CircularProgressIndicator(), + ); + }, + ), + ), + ), + ], + ), + ), + ); + } + + Widget buildUserInfo( + BuildContext context, + CustomColors customColors, + AdminUser user, + ) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(customColors.borderRadius ?? 8), + ), + child: Slidable( + child: Material( + borderRadius: + BorderRadius.all(Radius.circular(customColors.borderRadius ?? 8)), + color: customColors.columnBlockBackgroundColor, + child: InkWell( + borderRadius: BorderRadius.all( + Radius.circular(customColors.borderRadius ?? 8)), + onTap: () { + context.push('/admin/users/${user.id}'); + }, + child: Stack( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 头像 + Stack( + children: [ + buildUserAvatar(user), + Positioned( + bottom: 0, + width: 70, + child: ClipRRect( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(8), + ), + child: Container( + color: Colors.black.withAlpha(100), + padding: const EdgeInsets.symmetric(vertical: 2), + child: Center( + child: Text( + '#${user.id}', + style: const TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: Colors.white, + ), + ), + ), + ), + ), + ), + ], + ), + // 名称 + Expanded( + child: Container( + padding: const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user.displayName, + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(height: 5), + buildTags(context, customColors, user), + ], + ), + ), + ), + ], + ), + Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.0, + alignment: Alignment.centerRight, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${user.userType}', + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: customColors.weakTextColor, + ), + ), + ], + ), + ), + ), + Positioned( + right: 0, + bottom: 0, + child: Container( + padding: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.0, + alignment: Alignment.centerRight, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user.createdAt != null + ? humanTime(user.createdAt) + : '', + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: customColors.weakTextColor, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +Widget buildUserAvatar( + AdminUser user, { + BorderRadius radius = const BorderRadius.only( + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8), + ), +}) { + if (user.avatar != null && user.avatar!.startsWith('http')) { + return SizedBox( + width: 70, + height: 70, + child: ClipRRect( + borderRadius: radius, + child: CachedNetworkImage( + imageUrl: imageURL(user.avatar!, qiniuImageTypeAvatar), + fit: BoxFit.fill, + ), + ), + ); + } + + return Initicon( + text: user.displayName.split('、').join(' '), + size: 70, + backgroundColor: Colors.grey.withAlpha(100), + borderRadius: radius, + ); +} + +Widget buildTags( + BuildContext context, CustomColors customColors, AdminUser user) { + final tags = []; + + if (user.email != null && user.email!.isNotEmpty) { + tags.add(buildTag(context, customColors, '邮箱')); + } + + if (user.phone != null && user.phone!.isNotEmpty) { + tags.add(buildTag(context, customColors, '手机')); + } + + if (user.unionId != null && user.unionId!.isNotEmpty) { + tags.add(buildTag(context, customColors, '微信')); + } + + if (user.appleUid != null && user.appleUid!.isNotEmpty) { + tags.add(buildTag(context, customColors, 'Apple')); + } + + return Wrap( + spacing: 5, + runSpacing: 5, + children: tags, + ); +} + +Widget buildTag(BuildContext context, CustomColors customColors, String s) { + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 2, + ), + decoration: BoxDecoration( + color: customColors.tagsBackground, + borderRadius: BorderRadius.circular(5), + ), + child: Text( + s, + style: TextStyle( + fontSize: 10, + color: customColors.tagsText, + ), + ), + ); +} diff --git a/lib/page/component/pagination.dart b/lib/page/component/pagination.dart new file mode 100644 index 00000000..f4382ba6 --- /dev/null +++ b/lib/page/component/pagination.dart @@ -0,0 +1,101 @@ +/// 该文件来源于 https://github.com/created-by-varun/flutter_pagination/blob/master/lib/pagination.dart + +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:flutter/material.dart'; + +class Pagination extends StatefulWidget { + const Pagination({ + super.key, + required this.numOfPages, + required this.selectedPage, + this.pagesVisible = 5, + required this.onPageChanged, + }); + + final int numOfPages; + final int selectedPage; + final int pagesVisible; + final Function onPageChanged; + + @override + State createState() => _PaginationState(); +} + +class _PaginationState extends State { + late int _startPage; + late int _endPage; + + @override + void initState() { + super.initState(); + _calculateVisiblePages(); + } + + @override + void didUpdateWidget(Pagination oldWidget) { + super.didUpdateWidget(oldWidget); + _calculateVisiblePages(); + } + + void _calculateVisiblePages() { + /// If the number of pages is less than or equal to the number of pages visible, then show all the pages + if (widget.numOfPages <= widget.pagesVisible) { + _startPage = 1; + _endPage = widget.numOfPages; + } else { + /// If the number of pages is greater than the number of pages visible, then show the pages visible + int middle = (widget.pagesVisible - 1) ~/ 2; + if (widget.selectedPage <= middle + 1) { + _startPage = 1; + _endPage = widget.pagesVisible; + } else if (widget.selectedPage >= widget.numOfPages - middle) { + _startPage = widget.numOfPages - (widget.pagesVisible - 1); + _endPage = widget.numOfPages; + } else { + _startPage = widget.selectedPage - middle; + _endPage = widget.selectedPage + middle; + } + } + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + /// loop through the pages and show the page buttons + for (int i = _startPage; i <= _endPage; i++) + AnimatedContainer( + duration: const Duration(milliseconds: 200), + child: TextButton( + style: i == widget.selectedPage + ? ButtonStyle( + backgroundColor: + MaterialStateProperty.all(Colors.transparent), + ) + : ButtonStyle( + backgroundColor: + MaterialStateProperty.all(Colors.transparent)), + onPressed: () => widget.onPageChanged(i), + child: Text( + '$i', + style: i == widget.selectedPage + ? TextStyle( + color: customColors.linkColor, + fontSize: 14, + fontWeight: FontWeight.w700, + ) + : TextStyle( + fontSize: 12, + fontWeight: FontWeight.w700, + color: customColors.weakLinkColor, + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/repo/api/admin/users.dart b/lib/repo/api/admin/users.dart new file mode 100644 index 00000000..f22f0fee --- /dev/null +++ b/lib/repo/api/admin/users.dart @@ -0,0 +1,84 @@ +class AdminUser { + final int id; + final String? email; + final String? phone; + final String? realname; + final String? avatar; + final String? unionId; + final String? appleUid; + final int? invitedBy; + final String? inviteCode; + final String? userType; + final String? status; + final String? preferSigninMethod; + final DateTime? createdAt; + + AdminUser({ + required this.id, + this.email, + this.phone, + this.realname, + this.avatar, + this.unionId, + this.appleUid, + this.invitedBy, + this.inviteCode, + required this.userType, + this.preferSigninMethod, + this.createdAt, + this.status, + }); + + String get displayName { + if (realname != null && realname!.isNotEmpty) { + return realname!; + } + + if (email != null && email!.isNotEmpty) { + return email!; + } + + if (phone != null && phone!.isNotEmpty) { + return phone!; + } + + return '-'; + } + + factory AdminUser.fromJson(Map json) { + return AdminUser( + id: json['id'], + email: json['email'], + phone: json['phone'], + realname: json['realname'], + avatar: json['avatar'], + unionId: json['union_id'], + appleUid: json['apple_uid'], + invitedBy: json['invite_by'], + inviteCode: json['invite_code'], + userType: json['user_type'], + preferSigninMethod: json['prefer_signin_method'], + createdAt: + json['CreatedAt'] != null ? DateTime.parse(json['CreatedAt']) : null, + status: json['status'], + ); + } + + Map toJson() { + return { + 'id': id, + 'email': email, + 'phone': phone, + 'realname': realname, + 'avatar': avatar, + 'union_id': unionId, + 'apple_uid': appleUid, + 'invite_by': invitedBy, + 'invite_code': inviteCode, + 'user_type': userType, + 'prefer_signin_method': preferSigninMethod, + 'CreatedAt': createdAt?.toIso8601String(), + 'status': status, + }; + } +} diff --git a/lib/repo/api_server.dart b/lib/repo/api_server.dart index 8d45bc36..629d46a2 100644 --- a/lib/repo/api_server.dart +++ b/lib/repo/api_server.dart @@ -10,6 +10,7 @@ import 'package:askaide/helper/platform.dart'; import 'package:askaide/page/component/global_alert.dart'; import 'package:askaide/repo/api/admin/channels.dart'; import 'package:askaide/repo/api/admin/models.dart'; +import 'package:askaide/repo/api/admin/users.dart'; import 'package:askaide/repo/api/article.dart'; import 'package:askaide/repo/api/creative.dart'; import 'package:askaide/repo/api/image_model.dart'; @@ -2111,4 +2112,67 @@ class APIServer { return sendDeleteRequest( '/v1/admin/models/${Uri.encodeComponent(modelId)}', (resp) {}); } + + /// 管理员接口:查询用户列表 + Future> adminUsers({ + int page = 1, + int perPage = 20, + String? keyword, + }) async { + return sendGetRequest( + '/v1/admin/users', + (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminUser.fromJson(item)); + } + + return PagedData( + data: res, + page: resp.data['page'] ?? 1, + perPage: resp.data['per_page'] ?? 20, + total: resp.data['total'], + lastPage: resp.data['last_page'], + ); + }, + queryParameters: { + 'page': page, + 'per_page': perPage, + 'keyword': keyword, + }, + ); + } + + /// 管理员接口:查询用户详情 + Future adminUser({required int id}) async { + return sendGetRequest('/v1/admin/users/$id', (resp) { + return AdminUser.fromJson(resp.data['data']); + }); + } + + /// 管理员接口:为用户分配智慧果 + Future adminUserQuotaAssign({ + required int userId, + required int quota, + int? validPeriod, + String? note, + }) { + return sendPostJSONRequest( + '/v1/admin/quotas/assign', + (resp) {}, + data: { + 'user_id': userId, + 'quota': quota, + 'valid_period': validPeriod, + 'note': note, + }, + ); + } + + /// 管理员接口:查询用户当前额度 + Future adminUserQuota({required int userId}) async { + return sendGetRequest('/v1/admin/quotas/users/$userId', (resp) { + return QuotaResp.fromJson(resp.data); + }); + } } From d264dc57ad5ebf6b0fc021e704e6db680725a2cb Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 21 Mar 2024 22:38:51 +0800 Subject: [PATCH 22/36] update --- lib/page/admin/user.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/page/admin/user.dart b/lib/page/admin/user.dart index d99e2eeb..9eebcff6 100644 --- a/lib/page/admin/user.dart +++ b/lib/page/admin/user.dart @@ -5,7 +5,6 @@ import 'package:askaide/page/component/background_container.dart'; import 'package:askaide/page/component/coin.dart'; import 'package:askaide/page/component/column_block.dart'; import 'package:askaide/page/component/dialog.dart'; -import 'package:askaide/page/component/enhanced_button.dart'; import 'package:askaide/page/component/enhanced_textfield.dart'; import 'package:askaide/page/component/theme/custom_size.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; From c3872f110a6a2ec3f8c2dd7e1850afa228b6e976 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Thu, 21 Mar 2024 23:33:15 +0800 Subject: [PATCH 23/36] =?UTF-8?q?bugfix=20=E5=8F=AA=E6=9C=89=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E6=89=8D=E8=83=BD=E7=9C=8B=E8=A7=81=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/setting/setting_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/page/setting/setting_screen.dart b/lib/page/setting/setting_screen.dart index 012b8d93..e5b21fcd 100644 --- a/lib/page/setting/setting_screen.dart +++ b/lib/page/setting/setting_screen.dart @@ -71,7 +71,7 @@ class _SettingScreenState extends State { BlocBuilder( buildWhen: (previous, current) => current is AccountLoaded, builder: (context, state) { - if (state is AccountLoaded && state.user != null) { + if (userHasLabPermission(state)) { return IconButton( onPressed: () { context.push('/admin/dashboard'); From 5068616b95eb04edfbf0508c5cc1e30f706e92c9 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Fri, 22 Mar 2024 18:16:21 +0800 Subject: [PATCH 24/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=98=E6=96=B9?= =?UTF-8?q?=E9=A2=84=E5=8F=91=E5=B8=83=E6=9C=8D=E5=8A=A1=E5=99=A8=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/setting/setting_screen.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/page/setting/setting_screen.dart b/lib/page/setting/setting_screen.dart index e5b21fcd..84606bc6 100644 --- a/lib/page/setting/setting_screen.dart +++ b/lib/page/setting/setting_screen.dart @@ -496,8 +496,9 @@ class _SettingScreenState extends State { Future>> _defaultServerList() async { return [ SelectorItem(const Text('官方正式服务器'), apiServerURL), - SelectorItem(const Text('官方测试服务器'), 'https://api.chatllm.app'), - SelectorItem(const Text('本地开发机'), 'http://localhost:8080'), + SelectorItem(const Text('官方预发布服务器'), 'https://uat.aicode.cc'), + SelectorItem(const Text('官方测试服务器'), 'https://test.chatllm.app'), + SelectorItem(const Text('本地开发环境'), 'http://localhost:8080'), ]; } From 8740c925ae1244bc82fe74028e491eebd5013edf Mon Sep 17 00:00:00 2001 From: mylxsw Date: Sat, 23 Mar 2024 01:07:00 +0800 Subject: [PATCH 25/36] =?UTF-8?q?=E5=81=9C=E6=AD=A2=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=BC=98=E5=8C=96;=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E6=96=87=E6=9C=AC=E6=A8=A1=E5=BC=8F=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E5=8F=98=E6=9B=B4,=E6=9B=B4=E5=AE=B9=E6=98=93?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/chat/component/stop_button.dart | 35 ++ lib/page/chat/home_chat.dart | 249 +++++++------- lib/page/chat/room_chat.dart | 312 +++++++++-------- lib/page/component/background_container.dart | 2 +- lib/page/component/chat/chat_input.dart | 318 ++++++++---------- lib/page/component/chat/chat_preview.dart | 34 +- .../chat/enhanced_selectable_text.dart | 28 ++ lib/page/component/dialog.dart | 10 +- lib/page/component/weak_text_button.dart | 1 + 9 files changed, 542 insertions(+), 447 deletions(-) create mode 100644 lib/page/chat/component/stop_button.dart create mode 100644 lib/page/component/chat/enhanced_selectable_text.dart diff --git a/lib/page/chat/component/stop_button.dart b/lib/page/chat/component/stop_button.dart new file mode 100644 index 00000000..9b805aee --- /dev/null +++ b/lib/page/chat/component/stop_button.dart @@ -0,0 +1,35 @@ +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:flutter/material.dart'; + +class StopButton extends StatelessWidget { + final Function()? onPressed; + final String label; + const StopButton({super.key, this.onPressed, required this.label}); + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return TextButton.icon( + style: ButtonStyle( + minimumSize: MaterialStateProperty.all(const Size(0, 0)), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + iconColor: const MaterialStatePropertyAll(Colors.red), + backgroundColor: + MaterialStatePropertyAll(customColors.chatInputPanelBackground), + ), + label: Text( + label, + style: TextStyle( + fontSize: 12, + color: customColors.textfieldLabelColor, + ), + ), + icon: const Icon( + Icons.stop_circle_outlined, + size: 13, + ), + onPressed: onPressed, + ); + } +} diff --git a/lib/page/chat/home_chat.dart b/lib/page/chat/home_chat.dart index 4ad3d6ae..4e8d44d2 100644 --- a/lib/page/chat/home_chat.dart +++ b/lib/page/chat/home_chat.dart @@ -5,10 +5,12 @@ import 'package:askaide/bloc/room_bloc.dart'; import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/global_store.dart'; +import 'package:askaide/helper/haptic_feedback.dart'; import 'package:askaide/helper/model.dart'; import 'package:askaide/helper/upload.dart'; import 'package:askaide/lang/lang.dart'; import 'package:askaide/page/chat/component/model_switcher.dart'; +import 'package:askaide/page/chat/component/stop_button.dart'; import 'package:askaide/page/chat/room_chat.dart'; import 'package:askaide/page/component/audio_player.dart'; import 'package:askaide/page/component/background_container.dart'; @@ -341,64 +343,85 @@ class _HomeChatPageState extends State { ), // 聊天内容窗口 Expanded( - child: BlocConsumer( - listener: (context, state) { - if (state is ChatAnywhereInited) { - setState(() { - chatId = state.chatId; - }); - } - - if (state is ChatMessagesLoaded && state.error == null) { - setState(() { - selectedImageFiles = []; - }); - } - // 显示错误提示 - else if (state is ChatMessagesLoaded && state.error != null) { - showErrorMessageEnhanced(context, state.error); - } else if (state is ChatMessageUpdated) { - // 聊天内容窗口滚动到底部 - if (!state.processing && scrollController.hasClients) { - scrollController.animateTo( - 0, - duration: const Duration(milliseconds: 500), - curve: Curves.easeOut, - ); - } + child: Stack( + fit: StackFit.expand, + children: [ + BlocConsumer( + listener: (context, state) { + if (state is ChatAnywhereInited) { + setState(() { + chatId = state.chatId; + }); + } - if (state.processing && enableInput.value) { - // 聊天回复中时,禁止输入框编辑 - setState(() { - enableInput.value = false; - }); - } else if (!state.processing && !enableInput.value) { - if (tempModel == null) { - // 更新免费使用次数 - context.read().add(FreeCountReloadEvent( - model: widget.model ?? room.room.model)); + if (state is ChatMessagesLoaded && state.error == null) { + setState(() { + selectedImageFiles = []; + }); } + // 显示错误提示 + else if (state is ChatMessagesLoaded && state.error != null) { + showErrorMessageEnhanced(context, state.error); + } else if (state is ChatMessageUpdated) { + // 聊天内容窗口滚动到底部 + if (!state.processing && scrollController.hasClients) { + scrollController.animateTo( + 0, + duration: const Duration(milliseconds: 500), + curve: Curves.easeOut, + ); + } + + if (state.processing && enableInput.value) { + // 聊天回复中时,禁止输入框编辑 + setState(() { + enableInput.value = false; + }); + } else if (!state.processing && !enableInput.value) { + if (tempModel == null) { + // 更新免费使用次数 + context.read().add(FreeCountReloadEvent( + model: widget.model ?? room.room.model)); + } - // 聊天回复完成时,取消输入框的禁止编辑状态 - setState(() { - enableInput.value = true; - }); - } - } - }, - buildWhen: (prv, cur) => cur is ChatMessagesLoaded, - builder: (context, state) { - if (state is ChatMessagesLoaded) { - return buildChatPreviewArea( - state, - room.examples ?? [], - room, - customColors, - chatPreviewController.selectMode, - ); - } - return const Center(child: CircularProgressIndicator()); - }, + // 聊天回复完成时,取消输入框的禁止编辑状态 + setState(() { + enableInput.value = true; + }); + } + } + }, + buildWhen: (prv, cur) => cur is ChatMessagesLoaded, + builder: (context, state) { + if (state is ChatMessagesLoaded) { + return buildChatPreviewArea( + state, + room.examples ?? [], + room, + customColors, + chatPreviewController.selectMode, + ); + } + return const Center(child: CircularProgressIndicator()); + }, + ), + if (!enableInput.value) + Positioned( + bottom: 10, + width: MediaQuery.of(context).size.width, + child: Center( + child: StopButton( + label: '停止输出', + onPressed: () { + HapticFeedbackHelper.mediumImpact(); + context + .read() + .add(ChatMessageStopEvent()); + }, + ), + ), + ), + ], ), ), @@ -425,66 +448,63 @@ class _HomeChatPageState extends State { } } - return SafeArea( - child: BlocBuilder( - buildWhen: (previous, current) => - current is ChatMessagesLoaded, - builder: (context, state) { - var enableImageUpload = false; - if (state is ChatMessagesLoaded) { - if (currentModelV2 != null) { - enableImageUpload = - currentModelV2?.supportVision ?? false; - } else { - var model = - state.chatHistory?.model ?? room.room.model; - final cur = supportModels - .where((e) => e.id == model) - .firstOrNull; - enableImageUpload = cur?.supportVision ?? false; - } + return BlocBuilder( + buildWhen: (previous, current) => + current is ChatMessagesLoaded, + builder: (context, state) { + var enableImageUpload = false; + if (state is ChatMessagesLoaded) { + if (currentModelV2 != null) { + enableImageUpload = + currentModelV2?.supportVision ?? false; + } else { + var model = state.chatHistory?.model ?? room.room.model; + final cur = supportModels + .where((e) => e.id == model) + .firstOrNull; + enableImageUpload = cur?.supportVision ?? false; } - - return ChatInput( - enableNotifier: enableInput, - onSubmit: (value) { - handleSubmit(value); - FocusManager.instance.primaryFocus?.unfocus(); - }, - enableImageUpload: tempModel == null - ? enableImageUpload - : (tempModel?.supportVision ?? false), - onImageSelected: (files) { - setState(() { - selectedImageFiles = files; - }); - }, - selectedImageFiles: - enableImageUpload ? selectedImageFiles : [], - hintText: hintText, - onVoiceRecordTappedEvent: () { - audioPlayerController.stop(); - }, - onStopGenerate: () { - context - .read() - .add(ChatMessageStopEvent()); - }, - leftSideToolsBuilder: () { - return [ - ModelSwitcher( - onSelected: (selected) { - setState(() { - tempModel = selected; - }); - }, - value: tempModel, - ), - ]; - }, - ); - }, - ), + } + + return ChatInput( + enableNotifier: enableInput, + onSubmit: (value) { + handleSubmit(value); + FocusManager.instance.primaryFocus?.unfocus(); + }, + enableImageUpload: tempModel == null + ? enableImageUpload + : (tempModel?.supportVision ?? false), + onImageSelected: (files) { + setState(() { + selectedImageFiles = files; + }); + }, + selectedImageFiles: + enableImageUpload ? selectedImageFiles : [], + hintText: hintText, + onVoiceRecordTappedEvent: () { + audioPlayerController.stop(); + }, + onStopGenerate: () { + context + .read() + .add(ChatMessageStopEvent()); + }, + leftSideToolsBuilder: () { + return [ + ModelSwitcher( + onSelected: (selected) { + setState(() { + tempModel = selected; + }); + }, + value: tempModel, + ), + ]; + }, + ); + }, ); }, ), @@ -566,6 +586,7 @@ class _HomeChatPageState extends State { chatPreviewController.setAllMessageIds(messages); return ChatPreview( + padding: enableInput.value ? null : const EdgeInsets.only(bottom: 30), messages: messages, scrollController: scrollController, controller: chatPreviewController, diff --git a/lib/page/chat/room_chat.dart b/lib/page/chat/room_chat.dart index 669921e8..12a5020d 100644 --- a/lib/page/chat/room_chat.dart +++ b/lib/page/chat/room_chat.dart @@ -7,6 +7,7 @@ import 'package:askaide/helper/model.dart'; import 'package:askaide/helper/upload.dart'; import 'package:askaide/lang/lang.dart'; import 'package:askaide/page/chat/component/model_switcher.dart'; +import 'package:askaide/page/chat/component/stop_button.dart'; import 'package:askaide/page/component/audio_player.dart'; import 'package:askaide/page/component/background_container.dart'; import 'package:askaide/page/component/chat/chat_share.dart'; @@ -172,8 +173,32 @@ class _RoomChatPageState extends State { ), // 聊天内容窗口 Expanded( - child: _buildChatPreviewArea( - room, customColors, _chatPreviewController.selectMode), + child: Stack( + fit: StackFit.expand, + children: [ + _buildChatPreviewArea( + room, + customColors, + _chatPreviewController.selectMode, + ), + if (!_inputEnabled.value) + Positioned( + bottom: 10, + width: MediaQuery.of(context).size.width, + child: Center( + child: StopButton( + label: '停止输出', + onPressed: () { + HapticFeedbackHelper.mediumImpact(); + context + .read() + .add(ChatMessageStopEvent()); + }, + ), + ), + ), + ], + ), ), // 聊天输入窗口 @@ -198,53 +223,51 @@ class _RoomChatPageState extends State { } } - return SafeArea( - child: _chatPreviewController.selectMode - ? buildSelectModeToolbars( - context, - _chatPreviewController, - customColors, - ) - : ChatInput( - enableNotifier: _inputEnabled, - onSubmit: (value) { - _handleSubmit(value); - FocusManager.instance.primaryFocus?.unfocus(); - }, - enableImageUpload: tempModel == null - ? (roomModel != null && - roomModel!.supportVision) - : (tempModel?.supportVision ?? false), - onImageSelected: (files) { - setState(() { - selectedImageFiles = files; - }); - }, - selectedImageFiles: selectedImageFiles, - onNewChat: () => handleResetContext(context), - hintText: hintText, - onVoiceRecordTappedEvent: () { - _audioPlayerController.stop(); - }, - onStopGenerate: () { - context - .read() - .add(ChatMessageStopEvent()); - }, - leftSideToolsBuilder: () { - return [ - ModelSwitcher( - onSelected: (selected) { - setState(() { - tempModel = selected; - }); - }, - value: tempModel, - ), - ]; - }, - ), - ); + return _chatPreviewController.selectMode + ? buildSelectModeToolbars( + context, + _chatPreviewController, + customColors, + ) + : ChatInput( + enableNotifier: _inputEnabled, + onSubmit: (value) { + _handleSubmit(value); + FocusManager.instance.primaryFocus?.unfocus(); + }, + enableImageUpload: tempModel == null + ? (roomModel != null && + roomModel!.supportVision) + : (tempModel?.supportVision ?? false), + onImageSelected: (files) { + setState(() { + selectedImageFiles = files; + }); + }, + selectedImageFiles: selectedImageFiles, + onNewChat: () => handleResetContext(context), + hintText: hintText, + onVoiceRecordTappedEvent: () { + _audioPlayerController.stop(); + }, + onStopGenerate: () { + context + .read() + .add(ChatMessageStopEvent()); + }, + leftSideToolsBuilder: () { + return [ + ModelSwitcher( + onSelected: (selected) { + setState(() { + tempModel = selected; + }); + }, + value: tempModel, + ), + ]; + }, + ); }, ), ), @@ -355,6 +378,8 @@ class _RoomChatPageState extends State { _chatPreviewController.setAllMessageIds(messages); return ChatPreview( + padding: + _inputEnabled.value ? null : const EdgeInsets.only(bottom: 30), messages: messages, scrollController: _scrollController, controller: _chatPreviewController, @@ -731,105 +756,108 @@ Widget buildSelectModeToolbars( ), color: customColors.backgroundColor, ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - TextButton.icon( - onPressed: () { - var messages = chatPreviewController.selectedMessages(); - if (messages.isEmpty) { - showErrorMessageEnhanced( - context, AppLocale.noMessageSelected.getString(context)); - return; - } + child: SafeArea( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + TextButton.icon( + onPressed: () { + var messages = chatPreviewController.selectedMessages(); + if (messages.isEmpty) { + showErrorMessageEnhanced( + context, AppLocale.noMessageSelected.getString(context)); + return; + } - Navigator.push( - context, - MaterialPageRoute( - fullscreenDialog: true, - builder: (context) => ChatShareScreen( - messages: messages - .map((e) => ChatShareMessage( - content: e.message.text, - username: e.message.senderName, - avatarURL: e.message.avatarUrl, - leftSide: e.message.role == Role.receiver, - images: e.message.images, - )) - .toList(), + Navigator.push( + context, + MaterialPageRoute( + fullscreenDialog: true, + builder: (context) => ChatShareScreen( + messages: messages + .map((e) => ChatShareMessage( + content: e.message.text, + username: e.message.senderName, + avatarURL: e.message.avatarUrl, + leftSide: e.message.role == Role.receiver, + images: e.message.images, + )) + .toList(), + ), ), - ), - ); - // var messages = chatPreviewController.selectedMessages(); - // if (messages.isEmpty) { - // showErrorMessageEnhanced( - // context, AppLocale.noMessageSelected.getString(context)); - // return; - // } - // var shareText = messages.map((e) { - // if (e.message.role == Role.sender) { - // return '我:\n${e.message.text}'; - // } - - // return '助理:\n${e.message.text}'; - // }).join('\n\n'); - - // shareTo( - // context, - // content: shareText, - // title: AppLocale.chatHistory.getString(context), - // ); - }, - icon: Icon(Icons.share, color: customColors.linkColor), - label: Text( - AppLocale.share.getString(context), - style: TextStyle(color: customColors.linkColor), + ); + // var messages = chatPreviewController.selectedMessages(); + // if (messages.isEmpty) { + // showErrorMessageEnhanced( + // context, AppLocale.noMessageSelected.getString(context)); + // return; + // } + // var shareText = messages.map((e) { + // if (e.message.role == Role.sender) { + // return '我:\n${e.message.text}'; + // } + + // return '助理:\n${e.message.text}'; + // }).join('\n\n'); + + // shareTo( + // context, + // content: shareText, + // title: AppLocale.chatHistory.getString(context), + // ); + }, + icon: Icon(Icons.share, color: customColors.linkColor), + label: Text( + AppLocale.share.getString(context), + style: TextStyle(color: customColors.linkColor), + ), ), - ), - TextButton.icon( - onPressed: () { - chatPreviewController.selectAllMessage(); - }, - icon: Icon(Icons.select_all_outlined, color: customColors.linkColor), - label: Text( - AppLocale.selectAll.getString(context), - style: TextStyle(color: customColors.linkColor), + TextButton.icon( + onPressed: () { + chatPreviewController.selectAllMessage(); + }, + icon: + Icon(Icons.select_all_outlined, color: customColors.linkColor), + label: Text( + AppLocale.selectAll.getString(context), + style: TextStyle(color: customColors.linkColor), + ), ), - ), - TextButton.icon( - onPressed: () { - if (chatPreviewController.selectedMessageIds.isEmpty) { - showErrorMessageEnhanced( - context, AppLocale.noMessageSelected.getString(context)); - return; - } - - openConfirmDialog( - context, - AppLocale.confirmDelete.getString(context), - () { - final ids = chatPreviewController.selectedMessageIds.toList(); - if (ids.isNotEmpty) { - context - .read() - .add(ChatMessageDeleteEvent(ids)); - - showErrorMessageEnhanced( - context, AppLocale.operateSuccess.getString(context)); + TextButton.icon( + onPressed: () { + if (chatPreviewController.selectedMessageIds.isEmpty) { + showErrorMessageEnhanced( + context, AppLocale.noMessageSelected.getString(context)); + return; + } - chatPreviewController.exitSelectMode(); - } - }, - danger: true, - ); - }, - icon: Icon(Icons.delete, color: customColors.linkColor), - label: Text( - AppLocale.delete.getString(context), - style: TextStyle(color: customColors.linkColor), + openConfirmDialog( + context, + AppLocale.confirmDelete.getString(context), + () { + final ids = chatPreviewController.selectedMessageIds.toList(); + if (ids.isNotEmpty) { + context + .read() + .add(ChatMessageDeleteEvent(ids)); + + showErrorMessageEnhanced( + context, AppLocale.operateSuccess.getString(context)); + + chatPreviewController.exitSelectMode(); + } + }, + danger: true, + ); + }, + icon: Icon(Icons.delete, color: customColors.linkColor), + label: Text( + AppLocale.delete.getString(context), + style: TextStyle(color: customColors.linkColor), + ), ), - ), - ], + ], + ), ), ); } diff --git a/lib/page/component/background_container.dart b/lib/page/component/background_container.dart index 9c9a0b74..f2a6aa5c 100644 --- a/lib/page/component/background_container.dart +++ b/lib/page/component/background_container.dart @@ -75,7 +75,7 @@ class _BackgroundContainerState extends State { FocusScope.of(context).requestFocus(FocusNode()); }, onHorizontalDragUpdate: (details) { - int sensitivity = 10; + int sensitivity = 15; if (details.delta.dx > sensitivity) { if (Navigator.of(context).canPop()) { Navigator.of(context).pop(); diff --git a/lib/page/component/chat/chat_input.dart b/lib/page/component/chat/chat_input.dart index b772ba95..de63ba19 100644 --- a/lib/page/component/chat/chat_input.dart +++ b/lib/page/component/chat/chat_input.dart @@ -16,6 +16,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localization/flutter_localization.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; class ChatInput extends StatefulWidget { final Function(String value) onSubmit; @@ -54,9 +55,10 @@ class _ChatInputState extends State with TickerProviderStateMixin { /// 用于监听键盘事件,实现回车发送消息,Shift+Enter换行 late final FocusNode _focusNode = FocusNode( - onKey: (node, event) { - if (!event.isShiftPressed && event.logicalKey.keyLabel == 'Enter') { - if (event is RawKeyDownEvent && widget.enableNotifier.value) { + onKeyEvent: (node, event) { + if (!HardwareKeyboard.instance.isShiftPressed && + event.logicalKey.keyLabel == 'Enter') { + if (event is KeyDownEvent && widget.enableNotifier.value) { _handleSubmited(_textController.text.trim()); } @@ -69,10 +71,6 @@ class _ChatInputState extends State with TickerProviderStateMixin { final maxLength = 150000; - AnimationStatus status = AnimationStatus.forward; - late AnimationController animationController; - late Animation anim; - @override void initState() { super.initState(); @@ -89,32 +87,11 @@ class _ChatInputState extends State with TickerProviderStateMixin { } }); } - - animationController = AnimationController( - vsync: this, - duration: const Duration(seconds: 1), - ); - anim = Tween(begin: 0.75, end: 1.0).animate(animationController) - ..addListener(() { - if (animationController.status != AnimationStatus.dismissed && - animationController.status != AnimationStatus.completed) { - status = animationController.status; - } - if (animationController.status == AnimationStatus.completed || - animationController.status == AnimationStatus.dismissed) { - status == AnimationStatus.forward - ? animationController.reverse() - : animationController.forward(); - } - }); - - animationController.forward(); } @override void dispose() { _textController.dispose(); - animationController.dispose(); super.dispose(); } @@ -128,152 +105,156 @@ class _ChatInputState extends State with TickerProviderStateMixin { ), child: Builder(builder: (context) { final setting = context.read(); - return Column( - children: [ - if (widget.selectedImageFiles != null && - widget.selectedImageFiles!.isNotEmpty) - SizedBox( - height: 110, - child: ListView( - scrollDirection: Axis.horizontal, - children: widget.selectedImageFiles! - .map( - (e) => Container( - margin: const EdgeInsets.only(right: 8), - padding: const EdgeInsets.all(5), - child: Stack( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(5), - child: e.file.bytes != null - ? Image.memory( - e.file.bytes!, - fit: BoxFit.cover, - width: 100, - height: 100, - ) - : Image.file( - File(e.file.path!), - fit: BoxFit.cover, - width: 100, - height: 100, - ), - ), - if (widget.enableNotifier.value) - Positioned( - right: 5, - top: 5, - child: InkWell( - onTap: () { - setState(() { - widget.selectedImageFiles!.remove(e); - widget.onImageSelected - ?.call(widget.selectedImageFiles!); - }); - }, - child: Container( - padding: const EdgeInsets.all(3), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: customColors.chatRoomBackground, - ), - child: Icon( - Icons.close, - size: 10, - color: customColors.weakTextColor, + return SafeArea( + child: Column( + children: [ + if (widget.selectedImageFiles != null && + widget.selectedImageFiles!.isNotEmpty) + SizedBox( + height: 110, + child: ListView( + scrollDirection: Axis.horizontal, + children: widget.selectedImageFiles! + .map( + (e) => Container( + margin: const EdgeInsets.only(right: 8), + padding: const EdgeInsets.all(5), + child: Stack( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(5), + child: e.file.bytes != null + ? Image.memory( + e.file.bytes!, + fit: BoxFit.cover, + width: 100, + height: 100, + ) + : Image.file( + File(e.file.path!), + fit: BoxFit.cover, + width: 100, + height: 100, + ), + ), + if (widget.enableNotifier.value) + Positioned( + right: 5, + top: 5, + child: InkWell( + onTap: () { + setState(() { + widget.selectedImageFiles!.remove(e); + widget.onImageSelected?.call( + widget.selectedImageFiles!); + }); + }, + child: Container( + padding: const EdgeInsets.all(3), + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(10), + color: + customColors.chatRoomBackground, + ), + child: Icon( + Icons.close, + size: 10, + color: customColors.weakTextColor, + ), ), ), ), - ), - ], + ], + ), ), - ), - ) - .toList(), + ) + .toList(), + ), ), - ), - // 工具栏 - if (widget.toolbar != null) widget.toolbar!, - // if (widget.toolbar != null) - const SizedBox(height: 8), - // 聊天内容输入栏 - SingleChildScrollView( - child: Slidable( - startActionPane: widget.onNewChat != null - ? ActionPane( - extentRatio: 0.3, - motion: const ScrollMotion(), + // 工具栏 + if (widget.toolbar != null) widget.toolbar!, + // if (widget.toolbar != null) + const SizedBox(height: 8), + // 聊天内容输入栏 + SingleChildScrollView( + child: Slidable( + startActionPane: widget.onNewChat != null + ? ActionPane( + extentRatio: 0.3, + motion: const ScrollMotion(), + children: [ + SlidableAction( + autoClose: true, + label: AppLocale.newChat.getString(context), + backgroundColor: Colors.blue, + borderRadius: + const BorderRadius.all(Radius.circular(20)), + onPressed: (_) { + widget.onNewChat!(); + }, + ), + const SizedBox(width: 10), + ], + ) + : null, + child: Row( + children: [ + // 聊天功能按钮 + Row( children: [ - SlidableAction( - autoClose: true, - label: AppLocale.newChat.getString(context), - backgroundColor: Colors.blue, - borderRadius: - const BorderRadius.all(Radius.circular(20)), - onPressed: (_) { - widget.onNewChat!(); - }, - ), - const SizedBox(width: 10), + if (widget.leftSideToolsBuilder != null) + ...widget.leftSideToolsBuilder!(), + if (widget.enableNotifier.value && + widget.enableImageUpload && + Ability().supportImageUploader && + widget.onImageSelected != null && + Ability().supportWebSocket) + _buildImageUploadButton( + context, setting, customColors), ], - ) - : null, - child: Row( - children: [ - // 聊天功能按钮 - Row( - children: [ - if (widget.leftSideToolsBuilder != null) - ...widget.leftSideToolsBuilder!(), - if (widget.enableNotifier.value && - widget.enableImageUpload && - Ability().supportImageUploader && - widget.onImageSelected != null && - Ability().supportWebSocket) - _buildImageUploadButton( - context, setting, customColors), - ], - ), - // 聊天输入框 - Expanded( - child: Container( - decoration: BoxDecoration( - color: customColors.chatInputAreaBackground, - borderRadius: BorderRadius.circular(20), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Row( - children: [ - Expanded( - child: TextFormField( - keyboardType: TextInputType.multiline, - textInputAction: TextInputAction.newline, - maxLines: 5, - minLines: 1, - maxLength: maxLength, - focusNode: _focusNode, - controller: _textController, - decoration: InputDecoration( - hintText: widget.hintText, - hintStyle: const TextStyle( - fontSize: CustomSize.defaultHintTextSize, + ), + // 聊天输入框 + Expanded( + child: Container( + decoration: BoxDecoration( + color: customColors.chatInputAreaBackground, + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + children: [ + Expanded( + child: TextFormField( + keyboardType: TextInputType.multiline, + textInputAction: TextInputAction.newline, + maxLines: 5, + minLines: 1, + maxLength: maxLength, + focusNode: _focusNode, + controller: _textController, + decoration: InputDecoration( + hintText: widget.hintText, + hintStyle: const TextStyle( + fontSize: CustomSize.defaultHintTextSize, + ), + border: InputBorder.none, + counterText: '', ), - border: InputBorder.none, - counterText: '', ), ), - ), - // 聊天发送按钮 - _buildSendOrVoiceButton(context, customColors), - ], + // 聊天发送按钮 + _buildSendOrVoiceButton(context, customColors), + ], + ), ), ), - ), - ], + ], + ), ), ), - ), - ], + ], + ), ); }), ); @@ -290,7 +271,7 @@ class _ChatInputState extends State with TickerProviderStateMixin { if (widget.onStopGenerate != null) { openConfirmDialog( context, - '确定要打断当前对话?', + '确定要停止当前输出?', () { widget.onStopGenerate!(); HapticFeedbackHelper.heavyImpact(); @@ -299,17 +280,10 @@ class _ChatInputState extends State with TickerProviderStateMixin { ); } }, - child: AnimatedBuilder( - animation: anim, - builder: (context, child) { - return Transform.scale( - scale: anim.value, - child: Icon( - Icons.stop_circle_outlined, - color: customColors.linkColor?.withOpacity(anim.value), - ), - ); - }), + child: LoadingAnimationWidget.beat( + color: customColors.linkColor!, + size: 20, + ), ); } diff --git a/lib/page/component/chat/chat_preview.dart b/lib/page/component/chat/chat_preview.dart index 11874b8b..82e909a2 100644 --- a/lib/page/component/chat/chat_preview.dart +++ b/lib/page/component/chat/chat_preview.dart @@ -9,6 +9,7 @@ import 'package:askaide/helper/helper.dart'; import 'package:askaide/lang/lang.dart'; import 'package:askaide/page/component/attached_button_panel.dart'; import 'package:askaide/page/component/chat/chat_share.dart'; +import 'package:askaide/page/component/chat/enhanced_selectable_text.dart'; import 'package:askaide/page/component/chat/file_upload.dart'; import 'package:askaide/page/component/chat/message_state_manager.dart'; import 'package:askaide/page/component/dialog.dart'; @@ -42,6 +43,7 @@ class ChatPreview extends StatefulWidget { final bool supportBloc; final void Function(Message message)? onSpeakEvent; final void Function(Message message, int index)? onResentEvent; + final EdgeInsetsGeometry? padding; const ChatPreview({ super.key, @@ -58,6 +60,7 @@ class ChatPreview extends StatefulWidget { this.onSpeakEvent, this.onResentEvent, this.supportBloc = true, + this.padding, }); @override @@ -86,6 +89,7 @@ class _ChatPreviewState extends State { shrinkWrap: true, reverse: true, physics: const AlwaysScrollableScrollPhysics(), + padding: widget.padding, cacheExtent: MediaQuery.of(context).size.height * 10, itemBuilder: (context, index) { final message = messages[index]; @@ -596,20 +600,16 @@ class _ChatPreviewState extends State { buttons: [ TextButton.icon( onPressed: () { - if (!state.showMarkdown) { - state.showMarkdown = true; - } else { - state.showMarkdown = false; - } - - widget.stateManager - .setState(message.roomId!, message.id!, state) - .then((value) { - setState(() {}); - context - .read() - .add(RoomLoadEvent(message.roomId!, cascading: false)); - }); + openFullscreenDialog( + context, + child: Container( + margin: const EdgeInsets.only(top: 15, bottom: 30), + child: EnhancedSelectableText( + text: message.text, + ), + ), + title: '选择文本', + ); cancel(); }, @@ -622,9 +622,9 @@ class _ChatPreviewState extends State { color: const Color.fromARGB(255, 255, 255, 255), size: 14, ), - Text( - state.showMarkdown ? "文本" : "预览", - style: const TextStyle(fontSize: 12, color: Colors.white), + const Text( + "文本", + style: TextStyle(fontSize: 12, color: Colors.white), ), ], ), diff --git a/lib/page/component/chat/enhanced_selectable_text.dart b/lib/page/component/chat/enhanced_selectable_text.dart new file mode 100644 index 00000000..0779eb5e --- /dev/null +++ b/lib/page/component/chat/enhanced_selectable_text.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +class EnhancedSelectableText extends StatefulWidget { + final String text; + const EnhancedSelectableText({super.key, required this.text}); + + @override + State createState() => _EnhancedSelectableTextState(); +} + +class _EnhancedSelectableTextState extends State { + @override + Widget build(BuildContext context) { + return SelectionArea( + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Text( + widget.text, + style: const TextStyle( + fontSize: 14, + ), + ), + ), + ), + ); + } +} diff --git a/lib/page/component/dialog.dart b/lib/page/component/dialog.dart index 3e6820df..8477a449 100644 --- a/lib/page/component/dialog.dart +++ b/lib/page/component/dialog.dart @@ -8,6 +8,7 @@ import 'package:askaide/page/component/bottom_sheet_box.dart'; import 'package:askaide/page/component/button.dart'; import 'package:askaide/page/component/enhanced_textfield.dart'; import 'package:askaide/page/component/item_selector_search.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; @@ -698,9 +699,16 @@ class _FullScreenDialog extends StatelessWidget { return Scaffold( appBar: AppBar( title: Text(title), + toolbarHeight: CustomSize.toolbarHeight, actions: actions, + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(), + ), + ), + body: SafeArea( + child: child, ), - body: child, ); } } diff --git a/lib/page/component/weak_text_button.dart b/lib/page/component/weak_text_button.dart index 763ba045..5f081f4b 100644 --- a/lib/page/component/weak_text_button.dart +++ b/lib/page/component/weak_text_button.dart @@ -25,6 +25,7 @@ class WeakTextButton extends StatelessWidget { Icon( icon, color: customColors.weakLinkColor, + size: (fontSize ?? 15.0) + 1, ), if (icon != null) const SizedBox(width: 5), Text( From 595cf2d4cd8af96a0d65a3155fdbd43a025b358e Mon Sep 17 00:00:00 2001 From: mylxsw Date: Mon, 25 Mar 2024 17:55:32 +0800 Subject: [PATCH 26/36] some bugfix --- lib/helper/model.dart | 3 +- lib/page/admin/models.dart | 192 ++++++++++++++++++----- lib/page/chat/component/stop_button.dart | 2 +- lib/page/chat/home.dart | 15 +- lib/page/setting/custom_home_models.dart | 4 + lib/repo/api/admin/models.dart | 5 + 6 files changed, 170 insertions(+), 51 deletions(-) diff --git a/lib/helper/model.dart b/lib/helper/model.dart index 5b84ac53..034fef2f 100644 --- a/lib/helper/model.dart +++ b/lib/helper/model.dart @@ -64,8 +64,9 @@ class ModelAggregate { /// 根据模型唯一id查找模型 static Future model(String uid) async { - final supportModels = await models(); + uid = uid.split(':').last; + final supportModels = await models(); return supportModels.firstWhere( (element) => element.uid() == uid || element.id == uid, orElse: () => mm.Model(defaultChatModel, defaultChatModel, 'openai', diff --git a/lib/page/admin/models.dart b/lib/page/admin/models.dart index 263ce52b..a9add4b7 100644 --- a/lib/page/admin/models.dart +++ b/lib/page/admin/models.dart @@ -12,6 +12,7 @@ import 'package:askaide/repo/api_server.dart'; import 'package:askaide/repo/settings_repo.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_initicon/flutter_initicon.dart'; import 'package:flutter_localization/flutter_localization.dart'; @@ -33,6 +34,9 @@ class _AdminModelsPageState extends State { // 渠道 List channels = []; + // 搜索关键字 + String keyword = ''; + /// 查找渠道 AdminChannel searchChannel(AdminModelProvider provider) { return channels.firstWhere( @@ -97,46 +101,86 @@ class _AdminModelsPageState extends State { body: BackgroundContainer( setting: widget.setting, enabled: false, - child: RefreshIndicator( - color: customColors.linkColor, - onRefresh: () async { - context.read().add(ModelsLoadEvent()); - }, - displacement: 20, - child: BlocConsumer( - listenWhen: (previous, current) => current is ModelOperationResult, - listener: (context, state) { - if (state is ModelOperationResult) { - if (state.success) { - showSuccessMessage(state.message); + child: Column( + children: [ + Container( + padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5), + child: TextField( + textAlignVertical: TextAlignVertical.center, + style: TextStyle(color: customColors.dialogDefaultTextColor), + decoration: InputDecoration( + hintText: AppLocale.search.getString(context), + hintStyle: TextStyle( + color: customColors.dialogDefaultTextColor, + ), + prefixIcon: Icon( + Icons.search, + color: customColors.dialogDefaultTextColor, + ), + isDense: true, + border: InputBorder.none, + ), + onChanged: (value) => setState(() => keyword = value), + ), + ), + Expanded( + child: RefreshIndicator( + color: customColors.linkColor, + onRefresh: () async { context.read().add(ModelsLoadEvent()); - } else { - showErrorMessage(state.message); - } - } - }, - buildWhen: (previous, current) => current is ModelsLoaded, - builder: (context, state) { - if (state is ModelsLoaded) { - return SafeArea( - top: false, - child: ListView.builder( - padding: const EdgeInsets.all(5), - itemCount: state.models.length, - itemBuilder: (context, index) { - final mod = state.models[index]; + }, + displacement: 20, + child: BlocConsumer( + listenWhen: (previous, current) => + current is ModelOperationResult, + listener: (context, state) { + if (state is ModelOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.read().add(ModelsLoadEvent()); + } else { + showErrorMessage(state.message); + } + } + }, + buildWhen: (previous, current) => current is ModelsLoaded, + builder: (context, state) { + if (state is ModelsLoaded) { + final models = state.models + .where((e) => + keyword == '' || + e.name + .toLowerCase() + .contains(keyword.toLowerCase()) || + e.modelId + .toLowerCase() + .contains(keyword.toLowerCase()) || + (e.description ?? '') + .toLowerCase() + .contains(keyword.toLowerCase())) + .toList(); + return SafeArea( + top: false, + child: ListView.builder( + padding: const EdgeInsets.all(5), + itemCount: models.length, + itemBuilder: (context, index) { + final mod = models[index]; - return buildModelItem(context, customColors, mod); - }, - ), - ); - } + return buildModelItem(context, customColors, mod); + }, + ), + ); + } - return const Center( - child: CircularProgressIndicator(), - ); - }, - ), + return const Center( + child: CircularProgressIndicator(), + ); + }, + ), + ), + ), + ], ), ), ); @@ -204,7 +248,44 @@ class _AdminModelsPageState extends State { mainAxisSize: MainAxisSize.min, children: [ // 头像 - buildAvatar(mod), + Stack( + children: [ + buildAvatar(mod), + if (mod.isVision) + Positioned( + left: 0, + bottom: 0, + child: ClipRRect( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(8), + ), + child: Container( + padding: const EdgeInsets.all(3), + width: 80, + color: Colors.black.withAlpha(30), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.remove_red_eye_outlined, + color: Colors.white, + size: 12, + ), + SizedBox(width: 3), + Text( + '视觉', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ) + ], + ), + ), + ), + ) + ], + ), // 名称 Expanded( child: Container( @@ -219,12 +300,13 @@ class _AdminModelsPageState extends State { ), ), Text( - mod.description ?? '', + buildModelDescription(mod), style: TextStyle( fontSize: 10, overflow: TextOverflow.ellipsis, color: customColors.weakTextColor, ), + maxLines: 2, ), ], ), @@ -267,8 +349,8 @@ class _AdminModelsPageState extends State { Widget buildAvatar(AdminModel mod) { if (mod.avatarUrl != null && mod.avatarUrl!.startsWith('http')) { return SizedBox( - width: 70, - height: 70, + width: 80, + height: 80, child: ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), @@ -284,7 +366,7 @@ class _AdminModelsPageState extends State { return Initicon( text: mod.name.split('、').join(' '), - size: 70, + size: 80, backgroundColor: Colors.grey.withAlpha(100), borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), @@ -292,4 +374,30 @@ class _AdminModelsPageState extends State { ), ); } + + String buildModelDescription(AdminModel mod) { + String desc = ''; + if (mod.inputPrice > 0 || mod.outputPrice > 0) { + desc += '💰 '; + if (mod.inputPrice == mod.outputPrice) { + desc += '${mod.inputPrice} 智慧果/1K Token'; + } else { + desc += '${mod.inputPrice} / ${mod.outputPrice} 智慧果/1K Token'; + } + } + + if (mod.maxContext > 0) { + if (desc.isNotEmpty) { + desc += ','; + } + + desc += '🎞️ ${mod.maxContext} Tokens'; + } + + if (desc != '') { + desc += '\n'; + } + + return desc + (mod.description ?? ''); + } } diff --git a/lib/page/chat/component/stop_button.dart b/lib/page/chat/component/stop_button.dart index 9b805aee..f1fb22f4 100644 --- a/lib/page/chat/component/stop_button.dart +++ b/lib/page/chat/component/stop_button.dart @@ -12,7 +12,7 @@ class StopButton extends StatelessWidget { return TextButton.icon( style: ButtonStyle( - minimumSize: MaterialStateProperty.all(const Size(0, 0)), + // minimumSize: MaterialStateProperty.all(const Size(0, 0)), tapTargetSize: MaterialTapTargetSize.shrinkWrap, iconColor: const MaterialStatePropertyAll(Colors.red), backgroundColor: diff --git a/lib/page/chat/home.dart b/lib/page/chat/home.dart index 977138f3..34479835 100644 --- a/lib/page/chat/home.dart +++ b/lib/page/chat/home.dart @@ -77,20 +77,20 @@ class _HomePageState extends State { List models = [ HomeModelV2( modelId: "openai:gpt-3.5-turbo", - modelName: 'GPT-3.5', + modelName: 'Chat-3.5', type: 'model', id: 'openai:gpt-3.5-turbo', supportVision: false, - name: 'GPT-3.5', + name: 'Chat-3.5', avatarUrl: 'https://ssl.aicode.cc/ai-server/assets/avatar/gpt35.png', ), HomeModelV2( modelId: "openai:gpt-4", - modelName: 'GPT-4', + modelName: 'Chat-4', type: 'model', id: 'openai:gpt-4', supportVision: false, - name: 'GPT-4', + name: 'Chat-4', avatarUrl: 'https://ssl.aicode.cc/ai-server/assets/avatar/gpt4-preview.png', ), @@ -106,9 +106,10 @@ class _HomePageState extends State { /// 用于监听键盘事件,实现回车发送消息,Shift+Enter换行 late final FocusNode _focusNode = FocusNode( - onKey: (node, event) { - if (!event.isShiftPressed && event.logicalKey.keyLabel == 'Enter') { - if (event is RawKeyDownEvent) { + onKeyEvent: (node, event) { + if (!HardwareKeyboard.instance.isShiftPressed && + event.logicalKey.keyLabel == 'Enter') { + if (event is KeyDownEvent) { onSubmit(context, _textController.text.trim()); } diff --git a/lib/page/setting/custom_home_models.dart b/lib/page/setting/custom_home_models.dart index 0a49b3e1..23aaca97 100644 --- a/lib/page/setting/custom_home_models.dart +++ b/lib/page/setting/custom_home_models.dart @@ -359,6 +359,10 @@ class HomeModelItem extends StatelessWidget { itemCount: models.length, itemBuilder: (context, i) { var item = models[i]; + if (item.avatarUrl == null) { + // TODO: remove this debug print + print(item.toJson()); + } return ListTile( title: Container( alignment: Alignment.center, diff --git a/lib/repo/api/admin/models.dart b/lib/repo/api/admin/models.dart index 9a32e642..a1173772 100644 --- a/lib/repo/api/admin/models.dart +++ b/lib/repo/api/admin/models.dart @@ -8,6 +8,11 @@ class AdminModel { AdminModelMeta? meta; List providers; + bool get isVision => meta?.vision ?? false; + int get inputPrice => meta?.inputPrice ?? 0; + int get outputPrice => meta?.outputPrice ?? 0; + int get maxContext => meta?.maxContext ?? 0; + AdminModel({ required this.modelId, required this.name, From 1f53ee729848f782ef0833e0bdc7e1c35b401d2f Mon Sep 17 00:00:00 2001 From: mylxsw Date: Tue, 26 Mar 2024 12:27:25 +0800 Subject: [PATCH 27/36] =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/page/chat/room_create.dart | 2 +- lib/page/component/chat/empty.dart | 2 +- lib/page/component/model_item.dart | 254 +++++++++++++++++------------ 3 files changed, 155 insertions(+), 103 deletions(-) diff --git a/lib/page/chat/room_create.dart b/lib/page/chat/room_create.dart index 08400ea0..0b93bd6a 100644 --- a/lib/page/chat/room_create.dart +++ b/lib/page/chat/room_create.dart @@ -660,7 +660,7 @@ void openSelectModelDialog( ); }); }, - heightFactor: 0.7, + heightFactor: 0.85, title: title, ); } diff --git a/lib/page/component/chat/empty.dart b/lib/page/component/chat/empty.dart index 1628fa1b..878857e5 100644 --- a/lib/page/component/chat/empty.dart +++ b/lib/page/component/chat/empty.dart @@ -130,7 +130,7 @@ class _EmptyPreviewState extends State { return screenWidth / 1.15; } - return 400; + return 348; } double _resolveTipHeight(BuildContext context) { diff --git a/lib/page/component/model_item.dart b/lib/page/component/model_item.dart index 0883ac5b..249e1eef 100644 --- a/lib/page/component/model_item.dart +++ b/lib/page/component/model_item.dart @@ -1,14 +1,15 @@ import 'package:askaide/helper/ability.dart'; import 'package:askaide/helper/constant.dart'; import 'package:askaide/helper/image.dart'; +import 'package:askaide/lang/lang.dart'; import 'package:askaide/page/component/random_avatar.dart'; import 'package:askaide/page/component/theme/custom_theme.dart'; import 'package:askaide/page/component/weak_text_button.dart'; import 'package:askaide/repo/model/model.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_localization/flutter_localization.dart'; -class ModelItem extends StatelessWidget { +class ModelItem extends StatefulWidget { final List models; final Function(Model? selected) onSelected; final String? initValue; @@ -22,121 +23,172 @@ class ModelItem extends StatelessWidget { this.enableClear = false, }); + @override + State createState() => _ModelItemState(); +} + +class _ModelItemState extends State { + String keyword = ''; + @override Widget build(BuildContext context) { final customColors = Theme.of(context).extension()!; - if (enableClear && initValue != null) { + if (widget.enableClear && widget.initValue != null) { // 将当前选中的模型放在第一位 - var index = - models.indexWhere((e) => e.uid() == initValue || e.id == initValue); + var index = widget.models.indexWhere( + (e) => e.uid() == widget.initValue || e.id == widget.initValue); if (index != -1) { - var model = models.removeAt(index); - models.insert(0, model); + var model = widget.models.removeAt(index); + widget.models.insert(0, model); } } - return models.isNotEmpty - ? Padding( - padding: const EdgeInsets.only(top: 15), - child: ListView.separated( - itemCount: models.length, - itemBuilder: (context, i) { - var item = models[i]; - return ListTile( - title: Container( - alignment: Alignment.center, - padding: - const EdgeInsets.symmetric(horizontal: 10, vertical: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, - children: [ - if (item.avatarUrl != null) ...[ - _buildAvatar(avatarUrl: item.avatarUrl, size: 40), - const SizedBox(width: 20), - ], - Expanded( - child: Container( - alignment: item.avatarUrl != null - ? Alignment.centerLeft - : Alignment.center, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: Text( - item.name, - overflow: TextOverflow.ellipsis, + return widget.models.isNotEmpty + ? Column( + children: [ + Container( + padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5), + child: TextField( + textAlignVertical: TextAlignVertical.center, + style: TextStyle(color: customColors.dialogDefaultTextColor), + decoration: InputDecoration( + hintText: AppLocale.search.getString(context), + hintStyle: TextStyle( + color: customColors.dialogDefaultTextColor, + ), + prefixIcon: Icon( + Icons.search, + color: customColors.dialogDefaultTextColor, + ), + isDense: true, + border: InputBorder.none, + ), + onChanged: (value) => + setState(() => keyword = value.toLowerCase()), + ), + ), + Expanded( + child: Builder(builder: (context) { + final models = keyword.isEmpty + ? widget.models + : widget.models.where((e) { + var matchText = e.name + + (e.description ?? '') + + (e.shortName ?? '') + + (e.tag ?? '') + + (e.category); + if (e.supportVision) { + matchText += 'vision视觉看图'; + } + + return matchText.toLowerCase().contains(keyword); + }).toList(); + return ListView.separated( + itemCount: models.length, + itemBuilder: (context, i) { + var item = models[i]; + return ListTile( + title: Container( + alignment: Alignment.center, + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + if (item.avatarUrl != null) ...[ + _buildAvatar( + avatarUrl: item.avatarUrl, size: 40), + const SizedBox(width: 20), + ], + Expanded( + child: Container( + alignment: item.avatarUrl != null + ? Alignment.centerLeft + : Alignment.center, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Text( + item.name, + overflow: TextOverflow.ellipsis, + ), + ), + if (item.tag != null && + item.tag!.isNotEmpty && + item.avatarUrl != null) + Container( + decoration: BoxDecoration( + color: customColors + .tagsBackgroundHover, + borderRadius: + BorderRadius.circular(8), + ), + margin: + const EdgeInsets.only(left: 5), + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 2, + ), + child: Text( + item.tag!, + style: TextStyle( + fontSize: 10, + color: customColors.tagsText, + ), + ), + ), + ], ), ), - if (item.tag != null && - item.tag!.isNotEmpty && - item.avatarUrl != null) - Container( - decoration: BoxDecoration( - color: customColors.tagsBackgroundHover, - borderRadius: BorderRadius.circular(8), - ), - margin: const EdgeInsets.only(left: 5), - padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 2, - ), - child: Text( - item.tag!, - style: TextStyle( - fontSize: 10, - color: customColors.tagsText, - ), + ), + if (item.avatarUrl != null) ...[ + if (widget.enableClear) + SizedBox( + width: 60, + child: widget.initValue == item.uid() || + widget.initValue == item.id + ? WeakTextButton( + title: '取消', + fontSize: 14, + onPressed: () { + widget.onSelected(null); + }, + ) + : const SizedBox(), + ) + else + SizedBox( + width: 10, + child: Icon( + Icons.check, + color: widget.initValue == item.uid() || + widget.initValue == item.id + ? customColors.linkColor + : Colors.transparent, ), ), ], - ), + ], ), ), - if (item.avatarUrl != null) ...[ - if (enableClear) - SizedBox( - width: 60, - child: initValue == item.uid() || - initValue == item.id - ? WeakTextButton( - title: '取消', - fontSize: 14, - onPressed: () { - onSelected(null); - }, - ) - : const SizedBox(), - ) - else - SizedBox( - width: 10, - child: Icon( - Icons.check, - color: initValue == item.uid() || - initValue == item.id - ? customColors.linkColor - : Colors.transparent, - ), - ), - ], - ], - ), - ), - onTap: () { - onSelected(item); - }, - ); - }, - separatorBuilder: (BuildContext context, int index) { - return Divider( - height: 1, - color: customColors.columnBlockDividerColor, - ); - }, - ), + onTap: () { + widget.onSelected(item); + }, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider( + height: 1, + color: customColors.columnBlockDividerColor, + ); + }, + ); + }), + ), + ], ) : const Center( child: Text( From cd7af53db01c9b43ad17909728124d6844870d3a Mon Sep 17 00:00:00 2001 From: mylxsw Date: Tue, 26 Mar 2024 22:34:17 +0800 Subject: [PATCH 28/36] update --- lib/page/balance/free_statistics.dart | 250 +++++++++++++------------- 1 file changed, 127 insertions(+), 123 deletions(-) diff --git a/lib/page/balance/free_statistics.dart b/lib/page/balance/free_statistics.dart index 5c41309c..6fb63366 100644 --- a/lib/page/balance/free_statistics.dart +++ b/lib/page/balance/free_statistics.dart @@ -55,139 +55,143 @@ class _FreeStatisticsPageState extends State { onRefresh: () async { context.read().add(FreeCountReloadAllEvent()); }, - child: SizedBox( - height: double.infinity, - child: SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: BlocConsumer( - listenWhen: (previous, current) => - current is FreeCountLoadedState, - listener: (BuildContext context, FreeCountState state) { - if (state is FreeCountLoadedState) { - if (state.needSignin) { - showBeautyDialog( - context, - type: QuickAlertType.warning, - text: '免费模型需登录账号后使用', - confirmBtnText: '去登录', - onConfirmBtnTap: () { - context.pop(); - context.go('/login'); - }, - showCancelBtn: true, - ); - } - } - }, - builder: (context, state) { - if (state is FreeCountLoadedState) { - if (state.counts.isEmpty) { - return const Padding( - padding: EdgeInsets.symmetric(horizontal: 10), - child: Center( - child: MessageBox( - message: '当前无可用的免费模型。', - type: MessageBoxType.warning, - ), - ), - ); + child: SafeArea( + child: SizedBox( + height: double.infinity, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: BlocConsumer( + listenWhen: (previous, current) => + current is FreeCountLoadedState, + listener: (BuildContext context, FreeCountState state) { + if (state is FreeCountLoadedState) { + if (state.needSignin) { + showBeautyDialog( + context, + type: QuickAlertType.warning, + text: '免费模型需登录账号后使用', + confirmBtnText: '去登录', + onConfirmBtnTap: () { + context.pop(); + context.go('/login'); + }, + showCancelBtn: true, + ); + } } - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Column( - children: [ - const MessageBox( - message: '以下模型享有每日免费额度。', - type: MessageBoxType.info, + }, + builder: (context, state) { + if (state is FreeCountLoadedState) { + if (state.counts.isEmpty) { + return const Padding( + padding: EdgeInsets.symmetric(horizontal: 10), + child: Center( + child: MessageBox( + message: '当前无可用的免费模型。', + type: MessageBoxType.warning, + ), ), - const SizedBox(height: 10), - ColumnBlock( - innerPanding: 5, - children: [ - const Padding( - padding: EdgeInsets.symmetric(vertical: 5), - child: Row( - children: [ - Expanded( - child: Text( - '模型', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - )), - Row( - children: [ - Text( - '今日可用', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ], - ), - ], - ), - ), - ...state.counts.map((e) { - return Padding( - padding: - const EdgeInsets.symmetric(vertical: 5), + ); + } + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Column( + children: [ + const MessageBox( + message: '以下模型享有每日免费额度。', + type: MessageBoxType.info, + ), + const SizedBox(height: 10), + ColumnBlock( + innerPanding: 5, + children: [ + const Padding( + padding: EdgeInsets.symmetric(vertical: 5), child: Row( children: [ Expanded( - child: Row( - children: [ - Text( - e.name, - style: const TextStyle( - fontSize: 14, - ), - ), - if (e.info != null && e.info != '') - const SizedBox(width: 5), - if (e.info != null && e.info != '') - InkWell( - onTap: () { - showBeautyDialog( - context, - type: QuickAlertType.info, - text: e.info ?? '', - confirmBtnText: AppLocale - .gotIt - .getString(context), - showCancelBtn: false, - ); - }, - child: Icon( - Icons.help_outline, - size: 16, - color: customColors - .weakLinkColor - ?.withAlpha(150), - ), - ), - ], + child: Text( + '模型', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, ), - ), - buildLeftCountWidget( - leftCount: e.leftCount, - maxCount: e.maxCount, + )), + Row( + children: [ + Text( + '今日可用', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], ), ], ), - ); - }), - ], - ), - ], - ), - ); - } + ), + ...state.counts.map((e) { + return Padding( + padding: + const EdgeInsets.symmetric(vertical: 5), + child: Row( + children: [ + Expanded( + child: Row( + children: [ + Text( + e.name, + style: const TextStyle( + fontSize: 14, + ), + ), + if (e.info != null && + e.info != '') + const SizedBox(width: 5), + if (e.info != null && + e.info != '') + InkWell( + onTap: () { + showBeautyDialog( + context, + type: QuickAlertType.info, + text: e.info ?? '', + confirmBtnText: AppLocale + .gotIt + .getString(context), + showCancelBtn: false, + ); + }, + child: Icon( + Icons.help_outline, + size: 16, + color: customColors + .weakLinkColor + ?.withAlpha(150), + ), + ), + ], + ), + ), + buildLeftCountWidget( + leftCount: e.leftCount, + maxCount: e.maxCount, + ), + ], + ), + ); + }), + ], + ), + ], + ), + ); + } - return const Center(child: LoadingIndicator()); - }, + return const Center(child: LoadingIndicator()); + }, + ), ), ), ), From 01503aae2532e43b71b72591b6ed51a7f51dc286 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 27 Mar 2024 12:48:14 +0800 Subject: [PATCH 29/36] Remaining free quota prompt in the chat input box adjusted to avoid excessive length causing the input box to wrap --- lib/page/chat/home.dart | 2 +- lib/page/chat/home_chat.dart | 2 +- lib/page/chat/room_chat.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/page/chat/home.dart b/lib/page/chat/home.dart index 34479835..391eb4bb 100644 --- a/lib/page/chat/home.dart +++ b/lib/page/chat/home.dart @@ -847,7 +847,7 @@ class _HomePageState extends State { matched.leftCount > 0 && matched.maxCount > 0) { return Text( - '今日还可免费畅享 ${matched.leftCount} 次', + '今日还可免费${matched.leftCount}次', style: TextStyle( color: customColors.weakTextColor?.withAlpha(120), fontSize: 11, diff --git a/lib/page/chat/home_chat.dart b/lib/page/chat/home_chat.dart index 4e8d44d2..2c07d860 100644 --- a/lib/page/chat/home_chat.dart +++ b/lib/page/chat/home_chat.dart @@ -444,7 +444,7 @@ class _HomeChatPageState extends State { if (matched != null && matched.leftCount > 0 && matched.maxCount > 0) { - hintText += '(今日还可免费畅享${matched.leftCount}次)'; + hintText += '(今日还可免费${matched.leftCount}次)'; } } diff --git a/lib/page/chat/room_chat.dart b/lib/page/chat/room_chat.dart index 12a5020d..c7bd0425 100644 --- a/lib/page/chat/room_chat.dart +++ b/lib/page/chat/room_chat.dart @@ -219,7 +219,7 @@ class _RoomChatPageState extends State { if (matched != null && matched.leftCount > 0 && matched.maxCount > 0) { - hintText += '(今日还可免费畅享${matched.leftCount}次)'; + hintText += '(今日还可免费${matched.leftCount}次)'; } } From eb6c7a9cd627294eb2e4730eb0d24c51f89bf187 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 27 Mar 2024 14:59:30 +0800 Subject: [PATCH 30/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=E6=9F=A5=E7=9C=8B=E6=94=AF=E4=BB=98=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/apple.webp | Bin 0 -> 37028 bytes lib/bloc/admin_payment_bloc.dart | 21 ++ lib/bloc/admin_payment_event.dart | 16 ++ lib/bloc/admin_payment_state.dart | 19 ++ lib/main.dart | 20 ++ lib/page/admin/dashboard.dart | 51 +++- lib/page/admin/payments.dart | 379 ++++++++++++++++++++++++++++++ lib/page/admin/users.dart | 2 - lib/repo/api/admin/payment.dart | 47 ++++ lib/repo/api_server.dart | 41 ++++ pubspec.yaml | 1 + 11 files changed, 589 insertions(+), 8 deletions(-) create mode 100644 assets/apple.webp create mode 100644 lib/bloc/admin_payment_bloc.dart create mode 100644 lib/bloc/admin_payment_event.dart create mode 100644 lib/bloc/admin_payment_state.dart create mode 100644 lib/page/admin/payments.dart create mode 100644 lib/repo/api/admin/payment.dart diff --git a/assets/apple.webp b/assets/apple.webp new file mode 100644 index 0000000000000000000000000000000000000000..a64f8ba50ce2ed43e199730437b38692267910ca GIT binary patch literal 37028 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 { + AdminPaymentBloc() : super(AdminPaymentInitial()) { + on((event, emit) async { + final histories = await APIServer().adminPaymentHistories( + page: event.page, + perPage: event.perPage, + keyword: event.keyword, + ); + emit(AdminPaymentHistoriesLoaded(histories)); + }); + } +} diff --git a/lib/bloc/admin_payment_event.dart b/lib/bloc/admin_payment_event.dart new file mode 100644 index 00000000..f0c808dd --- /dev/null +++ b/lib/bloc/admin_payment_event.dart @@ -0,0 +1,16 @@ +part of 'admin_payment_bloc.dart'; + +@immutable +sealed class AdminPaymentEvent {} + +class AdminPaymentHistoriesLoadEvent extends AdminPaymentEvent { + final int page; + final int perPage; + final String? keyword; + + AdminPaymentHistoriesLoadEvent({ + this.page = 1, + this.perPage = 20, + this.keyword, + }); +} diff --git a/lib/bloc/admin_payment_state.dart b/lib/bloc/admin_payment_state.dart new file mode 100644 index 00000000..3f46a3d0 --- /dev/null +++ b/lib/bloc/admin_payment_state.dart @@ -0,0 +1,19 @@ +part of 'admin_payment_bloc.dart'; + +@immutable +sealed class AdminPaymentState {} + +final class AdminPaymentInitial extends AdminPaymentState {} + +class AdminPaymentOperationResult extends AdminPaymentState { + final bool success; + final String message; + + AdminPaymentOperationResult(this.success, this.message); +} + +class AdminPaymentHistoriesLoaded extends AdminPaymentState { + final PagedData histories; + + AdminPaymentHistoriesLoaded(this.histories); +} diff --git a/lib/main.dart b/lib/main.dart index 6292721d..4a3d9c23 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:askaide/bloc/admin_payment_bloc.dart'; import 'package:askaide/bloc/channel_bloc.dart'; import 'package:askaide/bloc/model_bloc.dart'; import 'package:askaide/bloc/user_bloc.dart'; @@ -9,6 +10,7 @@ import 'package:askaide/page/admin/dashboard.dart'; import 'package:askaide/page/admin/models.dart'; import 'package:askaide/page/admin/models_add.dart'; import 'package:askaide/page/admin/models_edit.dart'; +import 'package:askaide/page/admin/payments.dart'; import 'package:askaide/page/admin/user.dart'; import 'package:askaide/page/admin/users.dart'; import 'package:askaide/page/balance/web_payment_proxy.dart'; @@ -1228,6 +1230,24 @@ class MyApp extends StatefulWidget { ); }, ), + + GoRoute( + name: 'admin-payment-histories', + path: '/admin/payment/histories', + parentNavigatorKey: _shellNavigatorKey, + pageBuilder: (context, state) { + return transitionResolver( + MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => AdminPaymentBloc(), + ), + ], + child: PaymentHistoriesPage(setting: settingRepo), + ), + ); + }, + ), ], ) ], diff --git a/lib/page/admin/dashboard.dart b/lib/page/admin/dashboard.dart index ec916799..f3bbe412 100644 --- a/lib/page/admin/dashboard.dart +++ b/lib/page/admin/dashboard.dart @@ -1,5 +1,7 @@ import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/dialog.dart'; import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/repo/api_server.dart'; import 'package:askaide/repo/settings_repo.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -50,7 +52,7 @@ class _AdminDashboardPageState extends State { title: const Text('创作岛'), tiles: [ SettingsTile( - title: const Text('Gallery'), + title: const Text('创作历史'), trailing: const Icon( CupertinoIcons.chevron_forward, size: 18, @@ -63,10 +65,10 @@ class _AdminDashboardPageState extends State { ], ), SettingsSection( - title: const Text('用户管理'), + title: const Text('用户 & 收入'), tiles: [ SettingsTile( - title: const Text('用户列表'), + title: const Text('用户管理'), trailing: const Icon( CupertinoIcons.chevron_forward, size: 18, @@ -76,13 +78,24 @@ class _AdminDashboardPageState extends State { context.push('/admin/users'); }, ), + SettingsTile( + title: const Text('支付订单历史'), + trailing: const Icon( + CupertinoIcons.chevron_forward, + size: 18, + color: Colors.grey, + ), + onPressed: (context) { + context.push('/admin/payment/histories'); + }, + ), ], ), SettingsSection( - title: const Text('系统设置'), + title: const Text('模型管理'), tiles: [ SettingsTile( - title: const Text('渠道管理'), + title: const Text('渠道'), trailing: const Icon( CupertinoIcons.chevron_forward, size: 18, @@ -93,7 +106,7 @@ class _AdminDashboardPageState extends State { }, ), SettingsTile( - title: const Text('大语言模型管理'), + title: const Text('大语言模型'), trailing: const Icon( CupertinoIcons.chevron_forward, size: 18, @@ -105,6 +118,32 @@ class _AdminDashboardPageState extends State { ), ], ), + SettingsSection( + title: const Text('系统设置'), + tiles: [ + SettingsTile( + title: const Text('更新配置缓存'), + trailing: const Icon( + CupertinoIcons.chevron_forward, + size: 18, + color: Colors.grey, + ), + onPressed: (context) { + openConfirmDialog( + context, + '该操作将重新加载全部系统配置,确定继续?', + () { + APIServer().adminSettingsReload().then((value) { + showSuccessMessage('更新成功'); + }).onError((error, stackTrace) { + showErrorMessageEnhanced(context, error!); + }); + }, + ); + }, + ), + ], + ), ], contentPadding: const EdgeInsets.all(0), ), diff --git a/lib/page/admin/payments.dart b/lib/page/admin/payments.dart new file mode 100644 index 00000000..4cfcc1e2 --- /dev/null +++ b/lib/page/admin/payments.dart @@ -0,0 +1,379 @@ +import 'package:askaide/bloc/admin_payment_bloc.dart'; +import 'package:askaide/bloc/user_bloc.dart'; +import 'package:askaide/helper/helper.dart'; +import 'package:askaide/lang/lang.dart'; +import 'package:askaide/page/component/background_container.dart'; +import 'package:askaide/page/component/dialog.dart'; +import 'package:askaide/page/component/pagination.dart'; +import 'package:askaide/page/component/theme/custom_size.dart'; +import 'package:askaide/page/component/theme/custom_theme.dart'; +import 'package:askaide/repo/api/admin/payment.dart'; +import 'package:askaide/repo/settings_repo.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localization/flutter_localization.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; + +class PaymentHistoriesPage extends StatefulWidget { + final SettingRepository setting; + const PaymentHistoriesPage({ + super.key, + required this.setting, + }); + + @override + State createState() => _PaymentHistoriesPageState(); +} + +class _PaymentHistoriesPageState extends State { + /// 当前页码 + int page = 1; + + /// 每页数量 + int perPage = 20; + + /// 搜索关键字 + final TextEditingController keywordController = TextEditingController(); + + @override + void initState() { + context.read().add(AdminPaymentHistoriesLoadEvent( + perPage: perPage, + page: page, + keyword: keywordController.text, + )); + super.initState(); + } + + @override + void dispose() { + keywordController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final customColors = Theme.of(context).extension()!; + + return Scaffold( + appBar: AppBar( + toolbarHeight: CustomSize.toolbarHeight, + title: const Text( + '支付订单历史', + style: TextStyle(fontSize: CustomSize.appBarTitleSize), + ), + centerTitle: true, + ), + backgroundColor: customColors.chatInputPanelBackground, + body: BackgroundContainer( + setting: widget.setting, + enabled: false, + child: Column( + children: [ + Container( + padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5), + child: TextField( + controller: keywordController, + textAlignVertical: TextAlignVertical.center, + style: TextStyle(color: customColors.dialogDefaultTextColor), + decoration: InputDecoration( + hintText: AppLocale.search.getString(context), + hintStyle: TextStyle( + color: customColors.dialogDefaultTextColor, + ), + prefixIcon: Icon( + Icons.search, + color: customColors.dialogDefaultTextColor, + ), + isDense: true, + border: InputBorder.none, + ), + onEditingComplete: () { + context + .read() + .add(AdminPaymentHistoriesLoadEvent( + perPage: perPage, + page: page, + keyword: keywordController.text, + )); + }, + ), + ), + Expanded( + child: RefreshIndicator( + color: customColors.linkColor, + onRefresh: () async { + context + .read() + .add(AdminPaymentHistoriesLoadEvent( + perPage: perPage, + page: page, + keyword: keywordController.text, + )); + }, + displacement: 20, + child: BlocConsumer( + listener: (context, state) { + if (state is AdminPaymentOperationResult) { + if (state.success) { + showSuccessMessage(state.message); + context.read().add(UserListLoadEvent()); + } else { + showErrorMessage(state.message); + } + } + + if (state is AdminPaymentHistoriesLoaded) { + setState(() { + page = state.histories.page; + perPage = state.histories.perPage; + }); + } + }, + buildWhen: (previous, current) => + current is AdminPaymentHistoriesLoaded, + builder: (context, state) { + if (state is AdminPaymentHistoriesLoaded) { + return SafeArea( + top: false, + child: Column( + children: [ + Expanded( + child: ListView.builder( + padding: const EdgeInsets.all(5), + itemCount: state.histories.data.length, + itemBuilder: (context, index) { + return buildHistoryInfo( + context, + customColors, + state.histories.data[index], + ); + }, + ), + ), + if (state.histories.lastPage != null && + state.histories.lastPage! > 1) + Container( + padding: const EdgeInsets.all(10), + child: Pagination( + numOfPages: state.histories.lastPage ?? 1, + selectedPage: page, + pagesVisible: 5, + onPageChanged: (selected) { + context + .read() + .add(AdminPaymentHistoriesLoadEvent( + perPage: perPage, + page: selected, + keyword: keywordController.text, + )); + }, + ), + ), + ], + ), + ); + } + + return const Center( + child: CircularProgressIndicator(), + ); + }, + ), + ), + ), + ], + ), + ), + ); + } + + Widget buildHistoryInfo( + BuildContext context, + CustomColors customColors, + AdminPaymentHistory his, + ) { + return Container( + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(customColors.borderRadius ?? 8), + ), + child: Slidable( + child: Material( + borderRadius: + BorderRadius.all(Radius.circular(customColors.borderRadius ?? 8)), + color: customColors.columnBlockBackgroundColor, + child: InkWell( + borderRadius: BorderRadius.all( + Radius.circular(customColors.borderRadius ?? 8)), + onTap: () { + context.push('/admin/users/${his.userId}'); + }, + child: Stack( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + // 头像 + buildAvatar(his, radius: BorderRadius.circular(15)), + // 名称 + Expanded( + child: Container( + padding: const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + '用户 ${his.userId} 充值 ${(his.retailPrice / 100).ceil()} 元', + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(width: 5), + Text( + '#${his.id}', + style: TextStyle( + fontSize: 10, + color: customColors.weakTextColor, + ), + ), + ], + ), + const SizedBox(height: 5), + buildTags(context, customColors, his), + ], + ), + ), + ), + ], + ), + Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.0, + alignment: Alignment.centerRight, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + his.environment, + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + fontWeight: FontWeight.bold, + color: his.environment.toLowerCase() == 'production' + ? customColors.linkColor + : Colors.amber, + ), + ), + ], + ), + ), + ), + Positioned( + right: 0, + bottom: 0, + child: Container( + padding: const EdgeInsets.all(10), + width: MediaQuery.of(context).size.width / 2.0, + alignment: Alignment.centerRight, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + DateFormat('y-MM-dd HH:mm') + .format(his.purchaseAt.toLocal()), + style: TextStyle( + fontSize: 10, + overflow: TextOverflow.ellipsis, + color: customColors.weakTextColor, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} + +Widget buildAvatar( + AdminPaymentHistory his, { + BorderRadius radius = const BorderRadius.only( + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8), + ), +}) { + final source = (his.source ?? '').toLowerCase(); + + var image = ''; + if (source.contains('支付宝') || source.contains('alipay')) { + image = 'assets/zhifubao.png'; + } else if (source.contains('微信') || source.contains('wechat')) { + image = 'assets/wechat-pay.png'; + } else if (source.contains('stripe')) { + image = 'assets/stripe.png'; + } else if (source.contains('apple')) { + image = 'assets/apple.webp'; + } else { + image = 'assets/app.png'; + } + + return SizedBox( + width: 70, + height: 70, + child: ClipRRect( + borderRadius: radius, + child: Image.asset(image), + ), + ); +} + +Widget buildTags( + BuildContext context, CustomColors customColors, AdminPaymentHistory his) { + final tags = []; + + if (his.source != null) { + tags.add(buildTag(context, customColors, his.source!)); + } + + return Wrap( + spacing: 5, + runSpacing: 5, + children: tags, + ); +} + +Widget buildTag(BuildContext context, CustomColors customColors, String s) { + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 2, + ), + decoration: BoxDecoration( + color: customColors.tagsBackground, + borderRadius: BorderRadius.circular(5), + ), + child: Text( + s, + style: TextStyle( + fontSize: 10, + color: customColors.tagsText, + ), + ), + ); +} diff --git a/lib/page/admin/users.dart b/lib/page/admin/users.dart index bef3b58c..3aa291e8 100644 --- a/lib/page/admin/users.dart +++ b/lib/page/admin/users.dart @@ -11,9 +11,7 @@ import 'package:askaide/page/component/theme/custom_theme.dart'; import 'package:askaide/repo/api/admin/users.dart'; import 'package:askaide/repo/settings_repo.dart'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_initicon/flutter_initicon.dart'; import 'package:flutter_localization/flutter_localization.dart'; diff --git a/lib/repo/api/admin/payment.dart b/lib/repo/api/admin/payment.dart new file mode 100644 index 00000000..7d41f99b --- /dev/null +++ b/lib/repo/api/admin/payment.dart @@ -0,0 +1,47 @@ +class AdminPaymentHistory { + final int id; + final int userId; + final String paymentId; + final String? source; + final int quantity; + final int retailPrice; + final String environment; + final DateTime purchaseAt; + + AdminPaymentHistory({ + required this.id, + required this.userId, + required this.paymentId, + required this.quantity, + required this.retailPrice, + required this.environment, + required this.purchaseAt, + this.source, + }); + + factory AdminPaymentHistory.fromJson(Map json) { + return AdminPaymentHistory( + id: json['id'], + userId: json['user_id'], + paymentId: json['payment_id'], + quantity: json['quantity'], + retailPrice: json['retail_price'], + environment: json['environment'], + purchaseAt: DateTime.parse(json['purchase_at']), + source: json['source'], + ); + } + + Map toJson() { + return { + 'id': id, + 'user_id': userId, + 'payment_id': paymentId, + 'quantity': quantity, + 'retail_price': retailPrice, + 'environment': environment, + 'purchase_at': purchaseAt.toIso8601String(), + 'source': source, + }; + } +} diff --git a/lib/repo/api_server.dart b/lib/repo/api_server.dart index 629d46a2..36657e8f 100644 --- a/lib/repo/api_server.dart +++ b/lib/repo/api_server.dart @@ -10,6 +10,7 @@ import 'package:askaide/helper/platform.dart'; import 'package:askaide/page/component/global_alert.dart'; import 'package:askaide/repo/api/admin/channels.dart'; import 'package:askaide/repo/api/admin/models.dart'; +import 'package:askaide/repo/api/admin/payment.dart'; import 'package:askaide/repo/api/admin/users.dart'; import 'package:askaide/repo/api/article.dart'; import 'package:askaide/repo/api/creative.dart'; @@ -2175,4 +2176,44 @@ class APIServer { return QuotaResp.fromJson(resp.data); }); } + + /// 管理员接口:重新加载配置缓存 + Future adminSettingsReload() async { + return sendPostRequest('/v1/admin/settings/reload', (resp) {}); + } + + /// 管理员接口:重新加载配置缓存 + Future adminSettingReload(String key) async { + return sendPostRequest('/v1/admin/settings/key/$key/reload', (resp) {}); + } + + /// 管理员接口:查询所有支付订单 + Future> adminPaymentHistories({ + int page = 1, + int perPage = 20, + String? keyword, + }) async { + return sendGetRequest( + '/v1/admin/payments/histories', + (resp) { + var res = []; + for (var item in resp.data['data']) { + res.add(AdminPaymentHistory.fromJson(item)); + } + + return PagedData( + data: res, + page: resp.data['page'] ?? 1, + perPage: resp.data['per_page'] ?? 20, + total: resp.data['total'], + lastPage: resp.data['last_page'], + ); + }, + queryParameters: { + 'page': page, + 'per_page': perPage, + 'keyword': keyword, + }, + ); + } } diff --git a/pubspec.yaml b/pubspec.yaml index 7ac201f6..ee659357 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -197,6 +197,7 @@ flutter: - assets/wechat-pay.png - assets/zhifubao.png - assets/stripe.png + - assets/apple.webp # - images/a_dot_ham.jpeg From d0e924835c82b0971ebd564a7025d8ed6bae286e Mon Sep 17 00:00:00 2001 From: mylxsw Date: Wed, 27 Mar 2024 15:02:55 +0800 Subject: [PATCH 31/36] update --- lib/page/admin/payments.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/page/admin/payments.dart b/lib/page/admin/payments.dart index 4cfcc1e2..3284211d 100644 --- a/lib/page/admin/payments.dart +++ b/lib/page/admin/payments.dart @@ -1,6 +1,5 @@ import 'package:askaide/bloc/admin_payment_bloc.dart'; import 'package:askaide/bloc/user_bloc.dart'; -import 'package:askaide/helper/helper.dart'; import 'package:askaide/lang/lang.dart'; import 'package:askaide/page/component/background_container.dart'; import 'package:askaide/page/component/dialog.dart'; From d2f817f3ab66a14f9fa84baa132c9a6477456726 Mon Sep 17 00:00:00 2001 From: mylxsw Date: Tue, 2 Apr 2024 16:45:40 +0800 Subject: [PATCH 32/36] 1. Update the background image to high-definition; 2. Disable the swipe back function on desktop and web platforms; 3. Increase the maximum height of the chat input box when it gains focus to display more input content. --- assets/background-creative-island-dark.webp | Bin 56786 -> 0 bytes assets/background-creative-island.jpg | Bin 0 -> 112894 bytes assets/background-creative-island.webp | Bin 23244 -> 0 bytes assets/background-dark-s1.jpg | Bin 0 -> 41227 bytes assets/background-dark-s3.jpg | Bin 0 -> 340253 bytes assets/background-dark.jpg | Bin 0 -> 126042 bytes assets/background-dark.png | Bin 287881 -> 0 bytes assets/background-discovery-dark.jpg | Bin 0 -> 302002 bytes assets/background-discovery-dark.webp | Bin 27028 -> 0 bytes assets/background-discovery.png | Bin 262787 -> 0 bytes assets/background-light-s1.jpg | Bin 0 -> 194340 bytes assets/background-team-dark.png | Bin 685672 -> 0 bytes assets/background-team.jpg | Bin 0 -> 208145 bytes assets/background-team.png | Bin 80687 -> 0 bytes assets/background.jpg | Bin 0 -> 227104 bytes assets/background.png | Bin 380664 -> 0 bytes lib/page/chat/home.dart | 16 ++- lib/page/component/background_container.dart | 12 +- lib/page/component/chat/chat_input.dart | 47 +++++-- lib/page/component/enhanced_textfield.dart | 132 ++++++++++--------- lib/page/component/theme/custom_theme.dart | 17 ++- pubspec.yaml | 16 +-- 22 files changed, 141 insertions(+), 99 deletions(-) delete mode 100644 assets/background-creative-island-dark.webp create mode 100644 assets/background-creative-island.jpg delete mode 100644 assets/background-creative-island.webp create mode 100644 assets/background-dark-s1.jpg create mode 100644 assets/background-dark-s3.jpg create mode 100644 assets/background-dark.jpg delete mode 100644 assets/background-dark.png create mode 100644 assets/background-discovery-dark.jpg delete mode 100644 assets/background-discovery-dark.webp delete mode 100644 assets/background-discovery.png create mode 100644 assets/background-light-s1.jpg delete mode 100644 assets/background-team-dark.png create mode 100644 assets/background-team.jpg delete mode 100644 assets/background-team.png create mode 100644 assets/background.jpg delete mode 100644 assets/background.png diff --git a/assets/background-creative-island-dark.webp b/assets/background-creative-island-dark.webp deleted file mode 100644 index d46603d5c6ec56fec1e665e0d7ed706c0cb7fdbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56786 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

12E^bP3N-duM03s(SO{%ZpHYAHQ%z% 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

12f#gE5i3nvw}u#nQ`z{4c0-^QKn)lrw& zPk@N2PfsC9+B1hpEEW?BhUX0i`_ zzjValt!YnoNj<#c4n1yKMx@k(=Rvu_&TNKt6eC;sgAr1;4@m1oGfyrIgC#4qdA~z_ zfu|X@j-Nc#O~3Eb{+0ZzGV^%>C*}~@qaus-`Z}y-bNc<|fw~~K{J9`|DAu<;O5zD! zN)12q%_YZ}p~>G;^j*bzkKzsTC2_;VUX`XgDT!?dIz8df-!<7j>bTvRc0xg|;wY^% z^LcH7394Mh#fxoC$$F*)ka`%Mi z%8U;$H~KlYR^k3&i6BeE3|cT9yAH<-@IFJ$L&s+qGvh$D6^i?TcO;}=j-}*Mn0L51 zE@6wQY&vGenFMl@hpg*7g-vu?|JLcjOXBPcCT%vt)6`7uW(_0FJF3aN_r4xlvd3aL zz81yJhYBQP=R17qZG!`qnadon?|a{KE(dm3>Z^vo(6p_%v%k}={gJNooc7d&Pn?;? zR<9AWA~fNwO`T;RqJ({$95ziCMnB^cQ)J+sTZb`t2LsH3f~QK zV)t0@khzBiLIAH+W^TM4H4MdJ8|tSON=>vAX2Oq;4D;%2%lAr;9~aMLl7aFWXY*UD z)79Tvv>!cgdgwI`Yr01Tb^~L3EXsQk9B-1QSJCkuk5OYCV{6?rEo+4te)0})8f`z6 zw5C6bjnO1rTBO)<(QZD895okKV~_@mtnA?f1PyHKXG~L!okJw#Vqqy2d}<OKoc#549%E9nbNPH%*lGhTMWnTH(#c{j2*vqH3T62_vV35`(b} zn_@rzpDw%BhqXnT1{Fs3BrR#z_nbSz>j_7r$U)k%lJW5xI&3{*LT$sPY`>(~sx(mG zU>!4?O-3UeI4+UCDu|qpCGkLTSbh?1VZNI@BTd_2CyUZZKCH99(i8RHO=7L$W-{z| z@^9p{Uzw@0DYdkR{XQgMR;sG!`O22Clhiv;e7HO?+~YWt!f}F|KX1gEe0de>1n!gI zd5A^LClGtMinNKnaT5ByQf8hhpz%*@6IGG1 zF3F`n_X>&%?!UO=mmo>X7gx$FEY&0bu`6NQw|Vv?(b6Tp0ds0xCvNMU#vr60H;tXX zc+I%nZ!nkmKsxPjzUH>dJ!$0_T~n=rugQV=25l$w`HVigYO~QN(kq5cWBt*yj?bC3 zM$m4$=}8^?eOOcBExN@dKaO*1qZ)Le@rU3?1zt$mA_EKLixa8PI@u$TuXGgdl|``{ z2p(v!k5SPjq$s5_b`ne_Cc}<$zxsGKvC1vivaI)A3UycEg1+>mcJB@oGv_|8I?auk z5RD%@Uk`Up`ocz z7F5k<7~xb3=l4Y?x2AG*76E0=tw&v4vCV1K0fx2o-BOabze5EdPYdAegXB6xvb)mc zVvSh7oj7AG#)tO3uJt?Yp`)ROwhOrx_I{cZSx%C_;#v2dKAYwDiav8fPR#WtwCJg5 ztyRrRiBOcF9`#M;i~88j9DSQyoVO_{bGjotS`^RMRhpx?RPZ!2A**l|3%Xxd?)1pK zXv*0DC#W?~f2%YjdqkFmgZSbc1P`G3)u+FCW^!{CZ-iM11-9)OYP341B-dB-qZ7=H zbM}JYTAXCT5iT?zmsUK#G~|yPhFqetAlmk6A5&;_LxVWH?7?_;f5xiK7FgWt$;GGDTk{5eCKMiFF@#i)-9^O=i{DtG-CMlve;{ znO3kqhg(l-N?q#SXTPA-w}Pxs%%R|l?H57d+GdsaLIT;QT&2v}rpgJE0Ekeb-my}* zG8iEpE)x9g<7A-R5qB|slCvY1jfAC2OrYO%c23o!un*Sa?|YPoWluR-VVQhI34z8l zF7xE}4aGG9B++!a58`$!tLEYzzG1E`f>P znhIN9M?&57Oo5N6RI;t!qVID&&nY;Uw2(DxmQ;4}jpr|)Po{>Y6$w@wI@#(AmXV;c z>G*Px4=3#wjGm;+R@c^BGP2Zv((k;^)zmbXfbcR$4kmB_$cHVQ6#sa&yoNEUiBp1n zP5*hHjS>`uN}zDP_vQMa|Q;^u=+!METKlyWT6Co>O6bJscliI#WE3dUeaz zB06!zHne-QOQ1ckl{m2WVeZ3QTl|p8&4ZU!C;}%vFn5K`AF8Qp#4IO}9uVNR&H1tBV88=A-GqZGqI7U`Tdb?qd5` zyDRycoKABQJL->heOrF)ncm~#X*u__IN?atf+}zEazTc=;-A+ruD~)4b zIo7H%_dnfUgwld(In@^70b<3T7M0h&YQnHO(cN!M<7dpBmY(7X#+c-xjtrZ{&$OTL znF5z)0TUZ-GD;Htu@BT^rX7vEk|_cbD7eA#PC>EnY}%`84g8)1ytz(%W|dFPzz5W$ z9&3YbHmHHg6dy)KY84+fZprLgy*sB2EJNfS&hO{Q2Fl2OeLtd+lx8_P>y4Q7;ur|2 z4zP(n2*piLK^?LU`K2)__Hu}o!H04pO@kOJQ;oj?i~h)?31t^ zDb=)C>8yB;hT+&LtpIA@lClL@8MT7hJ?9L$3%-%L-^*_08bfR_MSSI}Tb)yt2wfIY zEPk-HNK?X_(gEB@7!d`=N8D#9*&IqEsJ2DIMJ&VfNSER%Sthmyh_@7;m-`5ji*m?kYs@w&Nc;3TlOQ8+Ju*coJf?9e{h(_BnMRI zXZNX%g05jz>2_z2HA)4*vrisvnKRN0dR6%7tfExjWSKes{ERPTQ#HoYu^R}RIH3W= zZIieqohRe7%Y&ww@pP?U4R+!GL-s=2<4K%6pd|C3~+GU+FZ_ zbH!#j`4*3FcxPvya2a-lA#@eYsN{{Cq*F1nRn27hI6O{c%EwT!O4IR==>k3zq%-vzvWQJbcfIR4DObRcmn=c5 z92@CM%qF+an|0DzU6AFxwC}>l*kGh=Vb;#OykS%M!|bL=jtTxS@*?+X_3FJq69)^^ zb(VMsb02*& zKUIk`VlewoxP%YKX==g)H5a-kfSymicOY-9b#Djly>-E;YXPM*@17w2yPU$<895@d zgzVWJp{3Q}HwJq)A!*$_8@)f}q@^=C+2+D|My$*yPJG5NOq4@*MmnIxO~c=52p5N^ zi#X{htLb}SnKVslK5M~f;~=k#Q@T3>r1~0}W2psB!;|{$7yR{LpB)OdofTtFn3Uhd zAaUXtlCv$4b*lF@x2Y{%2j)Z|RO|PYTD+U44gTC=7U{zCTf(m~=!a+!T&d62?Af^|5Dv+`5M2&CP_E?4jn81{tb9fMp&^K71`zou2oj2Er(EDVfz;iQQ1DF4ot~E;sVbO|;3|n;VAW#k2tx#^Wh( zXluy^3xyQjI}>v~**-tIO$XL-RsW{A*+S{roS9wC-x za|-vjPi89Gw9+WN`p8XUHSV(*c3*X~XEqaB#1M``=vj>?lnfs}Q+X|GJGm-RT-_Z# z8AGu`Lqo4*%kv9SRAyKTrTg+SCB6WbQ6y}96}8$MRTt(!vKdT<_frZH@wATEVi>4= z#pKbKSv(H!5l3K-mZ3%@#c2oJ+6o<8v1tqZ1eY zQdKwgpzYeQFXFj@w|HWO*NoarEg1{(C7=u&iz)^!=$1@myH?3mD8oQS8VKJT%b9vE z;QlI+Pbn!*Q`=C&2zn7X4p${SyglMyptjl>pDaT&DoJ+pc1Ect7tCM9VDjN>CNzG% zg{AVuisiGLzA{`}_JSL%vPR#vu@MQX4ij;BPkWMDLWO@lku!Wm&weu8N>W;!o_a2O z<6l~!*e$>w*f4y+e#jA^cK@*I&g00R& zrnrUgz$u@{X@&-0Gd>?lhjP)o!y7l<%Who@u58Uykxe?7S4tW%*LjROjpadqIvlbxJF+QJ2;OQxwKi= zKvLxsS26OjuV#ExdQDU2=(=`Q2u9pOONA!{dO1=ygG3|;Hbx(HlG5u$r9!YGjK>;` zW%6E8KiiX5aU4T!7ou=|$hpt|5>7xSgm+4E3Lgyv9;@e${ncN$g^yHnCdvmXq0X4_uaT=^ z)iWwT%8ULb`e#PekX41)JIFj|z^c`Zw~4Ls6L{@{`d=bSi>B^=%WRYjKNh;hU>;YO zRdH~m>A2O;biuuFyVs`C=#HZ3OsSUC$qiexxR0~jzV!Nch~`DwNljHo z+@8(D);j~&V@_zPkN`QQ>^1qLJ}TdgLLVR)`39Pm696-0ESdZYq$~lWp4b{Whhj*M zBFEfV1Kv6igfE?0+b?}M^m0a_!N!N;%5`et5wPd2HF2lf0so+DJ2rL8Rf%a>H*El{kw`S{X6#b|-7#SYJOFzuz7*T$7VrPj?W%6XAA9ORu{Yx~}d@+}FSbr(vxj=A% zdX&+C5}F^eb9|kPleX2$d(QbC&7#5&&67Pl#i8buUIZlWb=MJ-hM9vB~YmRj>ukWJngw&#f~=eh{;~^TG}i)btE?bq`2blmGctW6AoON zw%BJ8hq_CP)~^&1SYj1LnjZ;CU)f{N?)#?8-+b@C&S9uHsKMor3cC@k+SXAnl`<1* zTryv`>40+&vOHD^VlES}9iXG!8N)qC5~mfNlzym|N#`f;n{1jEP0Y<*HgiUGIrWOFkf0 zXl-33r91R2ZT9e|pONKa!LM_$y5A}!t_iPH_N!JQm;!u-%zIYXIj+Jl+*GxIm3v;- z;H!+~aH8G&dL)@Gom5zM6>8N|BeSP7@p zir{z?zDOjv^z%syGY{8CnuqcnG{x8&THf^l9T;pGZVRjo3^riqtZ|h!RjwpyA~u?c zUq*}CNrO);-IVQnRubg6Wewx7AEx!XM$WzbuRs1ia&yqZRd`HH$kie>dv6Ap9-SFi zzaobFG0zwQ3q4$IM9D59Ez9+B9jQriht0JQgsAf~fU%eC<4dhqMV?)3R~>->_z=@M z>zqa{irb0uVer-nMZ$yzy3qnc#C{E>BzIN zbkoz7737GppEWIKd2nt!;V}VJ^>O-z?Y^0Y9Bx|ilfk9xu5?^MM_f*zC`_N~g@_H# z{I{*EU-S`=2?*}STnF^BNi14yTQpL}j!Oujw=QRYp%^uIAbgN9Cl}CU1x~WubxVL@IjF|?(r#0Q> zt?8CSUjP=%8SXu^y4zG=y?}g=nd>!w%~JC#qGuK-m+T~sERBX6^o&rL=%cppX7)wP zJqN-bisr9ib8UT_Tj-KU#ul@J2Lsg-M$ zA#9&pJZsMx2Kh4gpqI^JCbT)zOv=UWB9d^z-#xpi`F^-slDORM8oP&aowT1_e3P9X z8MA5#f-4hpam>+=i^~kMt-4G*nYOpaV>y+a5o;5*4_3FNv=T8Zp6V;{udAetB0Oai z8Ww_to`IxuP5XDKgYIc=1`H*ZArI( ziFB7R5HetBKOPPieO<&slR=dky#>!vfi@?eGrG$}vpUMH%H((rxg4J6x3B)bZqg;p zYc^FPsv2gmp+5I8(eKLAZAH#x*DWsHvr)j9R+~@*IT$xT9hTLjnV4TuiT{_#ck!?; zK=7OdR}2=j_8M_HJewJ~)00$7mbgW^k=#_^veT4Zz94)`Qz||tnsQlKY~NSK)%l$o zi28ssFdp;#w4OE?2A*QNxT=-Oqn_nv`fGtDot||y&<$(4NBn^r zYx^E&2ARSf+V0ucS~BsB-A&2I-I~DMRRe`ndZDw{K&H8Zj|Z8cy)pj4K(7#sS+T?< z0xbZ7Ym2IZ5Egywb3*eO6HSrAAp)y;b1Y0H9Ngq4CV^aNKl7gPD6p^WoHQJ-s0M|99CxmP5u zm}Ahi&d7ZF%n;MeZfca(Y=_H0or`S52rB|Dn5^E_RI6$#k|LolvOjBeuy9r9M#$R( zuGj|;e6sn@V#5VCA^);5!Xn{Og%@PT;KS@@t(Ci;Oma$4!7WQYzIOmvCJmHGg z^W~RXYk@v;-ZhuU!BTPH0^#WD5V`;dt)w>M&%TUhvCH97yEwiEb0k>??YqWt%J4cL z{!Fc7T=m}@MtIV-s-W~ZOY%#%I797UuxYrnp**aysV=(+7#_wR+=K@M`AsXPPa z_Q>whMQ`{xtj_bgK`|FLlS3Pnah?2qGX1bueRa$mtG(y?*3O-$V#EaspZ` zXrTHsqjdJSw6r58xl_PR{CM1@a!;gjHJEawK%WalCSjdZA@oe^Uj0T z#E|woAo&Fi=~M)hUyl^4?ERWX6}SX$bPe9r|4TIKgV=Ql{AMTrak1Gu)*Kt1DcUq0 z-0an^>nV3fUPDR8(jH$TZlH6V+pD@QW|Nu9kZzn8v}bTf!?z;QMNhm@$AI&6qWEs> zN7j&rQ(>6ExzlTjwbc`w8UD2FN#DhAHaBJe2H#1K#J!f->TJ|z0jX+<=fbNa z)2dP1US^5uH|Y{zuj9_8XCH6P)JdG#I)W9We)Z=`J8jY~&)QuS@9vJA6w==Hj@&S` z^f299oXRaSZ9I_IDCVmr=)bKE-V`=r*b-fXAwGOgRX;83Xmm2z3vZgRUGO@m7RU|1 zTf!SY$(J+abllebb6VK6qPO97P4HVW%<>-Q*ZC38I2VV4!YOSKLe|};KqXOF2c@Ga zjzc$i<&We$DXAMOBcYsTjIhy-A)|rxra9jetWCfN=mNkE{xu`v>Tw{_Z0+%@?AF=V z2=zm~RduPSY#+HevwBnW1D8tm98Bzt=IpF1T>Ky zg}lkwaeUSAFVPl(IW0URX)$;q^UU+o?DUG1ilHT##3rBpwa;^Ub==ZF-Q1cD#n3H_5c#{)kUMg=^`l`g zHcL!s0Wt$MTZi%D>tOszx5<_0i$I*Or03qMeaKCZJqX9 zjcYbqjumY{K0wVUvf24AyV2iKkJhOJ5aB5XfPnHDtB?F&VOzIVpo9DoM;Q&|vrh1c zy*$IB58t+|!-@oQQr%z`&X-j=;`zG;)xC$%H;Aertyt6HDX>+2afJS7LBq+AO|WcC z^IE};RLPYz-y~0>YFlG|VC(_0gy7@S?bF8OZ$F!tnqetRi5sTu?D~P@_~W*~L7@d^ z%lO*j7N>uSYUn$)p{VC#O;izKZKr=v@Yi<<+ck|Sl@?Y&&hAWH`!q{Fzv)vWgOErG zKJG8Ktl;6e>ltXXMpsKCrAfn~3*uHyDROKmnS}QS`vfs%r135G$0#oq?778hWBJoX z9+g&4>3NZ%tsd5USxrPBOKNsZV&~Bwr{DuRyy;5k5m-Vprmq!p;So&t^W+g^WudI#_zmTr^7iksCOk^5Ktzf!z_qFS z(xZBT*&fzC_lg2MVNi1GVaxy@C&yk5q1APJwINSWWF=sh?H~W$yS4DIIngdOjsYX{mSI5q>Xx5q$nT05S=Oj{}r<|TW@c`A*u>t=0E%uVcVveg}KA3Nf= zH;U!!s<)2kR)V2xuwts=W#fBi=2vBVR#OXHLEA`+|ohrvvaU)b9LRF~xZmbGct6%Np** zy#0PC&gAY~?b~d4>@k(fg7uMs_FtCk^eiQ^@SA}Z26i}eBQy^3KzuPiwT$5f|nsTFG8NRw~IEmO1k=6B|L(_bf40Mg>kqt@I3?s^go^CqlefWMb?dkHZ-`l6Ar2L{Q=<Y}gNX*T?YJKxu!5(iP&5*71t0bxiCg}6b;^}~3MuFq`1+irLsKWpGCVv#I9TPcC@ z2jid6A%i9G`it82F!E*Ra!`C2cY985_+%NyesLVYlG>vl{_^V1U2(kR;Opw*!FrTo zsx0%6%ie5mFEZ6UuhhE0YNM6PZeb#C-#NavHRbD;%gNiTf6gXt_nl!<;=6t#)6AQf z^c<+Ay1|!YhDAG zF>k(+vpqA&3R(L)hWyqAPS0`^irJ5KOA9_j&!~vqj+K9v8Adwjx`Tg=Dn1F~NLQcy z^5u9~YT6k3&c(n6c#X5VDksx+pNw5!H(0sgJKKb_w*IflIk!>vb_#s(AH7 zCXd0A$ZNGH`j$UtY*lwZpiIYt8gecR^KmJ1s-mmL$-&`vEB+YXIk-L}WX;mi!6qI@_xi1dC2-A39HaRH0fyT^ju| zv!<+UrZI1N(D?g{n>l(B z?qevO@DzTEzbCQhHkwk_iV&W54Y90y#LDH7@p(^KF`IPTfYDrU1kI`W;)Mqs&HK+|Dv$K=l;hCx%_FwwEgU2m~4q@$)~f zIcVr1EEOk=movra;vXj%-f54I$foG~+M_#3RbxYCd&Y4%YS+Nn)vnE)`N)S*rg&58D!&=hatNN>Q=m zT83^BePybg#sXOfpj|y8xU!jGgC^biwqQAVD`#~PY@*RXVN!@I!5TADzh^F50jaKK zTzb7^s=BM4XWint{Vtr8RqP{_7e;UXkJHehQ@37jQQzUA_qE0pH>|?L} zu^$DK(Zzcdyrpj-WDwL%5ACEg>^sO0Bgn==_f_Mk}+U? zbRl!-QbAb)psO0(UXm)*an3^UQb}y&LLwn#oX--1`PtRc)IfKQSg+d_)L{j?!R{S#} zXKm12CTXd}PpF9HHNUS0jKnSy%LeoIDoP<99p%;4?a`a*B^`(su!(-UaT#quT=noK-YLI=*fH`N z?3PIpL>F7~)L-j|;@Ew{vKr+veMCbINA4K}pW39PREp;)dM6W3 zE~dv&7OT2ASgMgZOR$EZl`MPpIb1NKs+X-?MYpjw#>Nnj`M})0zSxaxY9JNJ+T!V& z_@biROtx58VcoU4V{6-EmN6dWwkfK{*`QQMt5l~OlF`=m_E=rHl+G<@_F%T}o5d6iR1Vc2%yv zy3e#wo&cb*Z`s%?oGT_}*QEv+M$=PW0C=NSRq}hjS>@{RMSCPeIVU|<{zLWHWpM~n zZU$kijVhSd+c4(;K$FQhTJQLrzJBtNyWZ`Fpdj{@YEJ#35ql@z@V<)&9YC6eq2<@# z8~*L1W@#X}H|86f6d-6hNz0Y1SWW8+XH*r@s&cBbh2M!XVOEUNLp=*y(QFnj+w;7x zwMf|+F&xN~u5H@Qg8xp{0l^NyQm+R&8-w3IQ@K3>P>=+gP~?0~A`{9v zxn*;jK}mSCH)$Iu?zu8Ng3U1b_Rdwh>|(VLvsIpp(n4m)<+&S)hPcTKV* z?lAYdRQp?7bYgV~d^HL^{Q25U8FT!$XS78wNAe9lxam~>E|7AenNBOf__*(}1Y7NB zl}j4K*ScGG&vNs~xR9NueMp?}$BGy=PyfyTsI#cO)|G6O?fU+O0NhUuoza&G(=g|_ z?BT#p^x7Z?0LnbUekT&zIcy_iansX%qWg!QaAdmWke0)uWQX?6t_qYo+}jb{0VNhsE;d^%QI;Ff z-nEIcyVeCp&W-Dyk+~E6PuH$_6 z-8AGRZKA$HE(BRB;86qW%HuRH7nzzTS*g7`lwB6>MT+Vg!Z;H?NQtEC6qj|nuXiDr^B?-1EoUM27DhwYq@}4hA0CsRRg(%-@II%SI?<&v%SMjEaou4PPmILlT_B5jC0NTSA0T2v>@dV2nkr_i2S}Z#_ z)w&*~AM47<;LD{SaAzapIZbl*Fn&u7KD^y!t9|7@cFxFV@!Q%a1LKY$rt*zxD5F=# zc~ zcXD5M?&~_Qa~#KUhOKB^nkr5n2qp63DDU$CNu$rcsH)c9hGW}qXxNwaILYZ@dh2np zJPI&PcbbpS8XUa!yk7Y|LQAEB*l;+RK$jk62 z9U$><-yO&f5(0=yd2{{5q`o~Ij!{GuN(IV!{#b{SVZ%W+e?=0DKStCIYGVSDNAntB z5^lnUDcJ=ad0&#fVXU%D^%Wy0xz0+R3JLJmKo7`hjc$?ZwMD)VY8Hf!z03nIpgq)* z^Vk=(vl&M53pxC{+(~MQhV_}8M`x=_2*6%#{IMx=9wH^V<|6v|FV{7p&c!FCiW`XW zHa#u%Tfsu&o5ycdgKGkH;uWEgQXktN5Q^WBj`B$6Qi~aR=G`$R%7YE&zFy4`m?8_9TEVjqqeuUJRXk-|xIg{_~ z9i99dfdH<~$C)oS$1FuV-UynlvjBY0+dk-UVNdI0!f#pDY>~>GxV| zsHNj=+&3Y5M0QzO>?ZowJ3rcvI=&A3O@2x5XL#d59kM$|r z(K+$qdGBGNAq@s(^dn@|kc*dYlkb-8M>LL}A1o*Oz|aI;K;!sv*#&c~t6qpK>}$2L zj1#!+KHHtESrbwSQG5`jR{N$(c*k@R_gwz^z;udH-Dyu2L`eq}EoOimjhs%oW2OsZ z9rXyEIyL7B=GksT@o7B>u|ebGU-=pmsp?K_XArC(Z8yyz+O7o6=e&lUoo5idFoCZW!H5tE zbx~lhrIPQT_XS3Di^a5vhTGN!96z;e)v|x`%X5rsl>ajsJNh~0jQQ_V`UUi4Ca;zu zmYEu+kyB=etp4O7#>$@CEwo^9r8!GKasgZY@?8F3w-2T4nA;|PHPrJkgL+eyt}8Q* z&(8Ia!>A1#=w(!5UHIZ!nG~7IY_+;{x_;CH&AQmi|JCtNe-*WXO{;OVR{hLp8{_Ba zFxj%boec{VmV!Q0KCQKgH|i4boDq)e+?!OP2FphuS^PlI&^Xq!))dtCRbRoM3!{}D zDg`nZD_Y_dz)m!AF}6%zWRr(BkUG!k>}Ws-nWug>CMtgutuI9YKTrrRcBS)0zTWYx z5&6-a-MKF%-45-rmGPro?{>|tw2aanc$pS+CJhc~F>!1RtlcM>Ov+2&fl4_?~+^Y2+45w<{EQyVs^Q zkj)<>dp!SalE3fpOL2=^-(~y&(;(kE6}7HOcVIIS7V*haWX4TLIdV0q-=cr4JR;#y z^ZM2s{ifi}kKylk8L~mykGC0ZqVk@z%Mi(>SEVVg%8SZeSU;MfkJhTezbKttsK&5w zPU%O2C?6C$k@8rM^G-7uMEaB{I?rkDvtR)O9;;4c$^PceNJ?dJX?_|2tBGZj=|YMc zEW%zwV1?yeEuA0}#uB!nBsFAmffHOn^UL~5>4RG;)OpI4>^6A3eLqWs`+gtMvmC&Q zZT7>iUX2)J2-x(?J67kT~pj=J)-CU9=%J%wcajR zj|HKt#-GAh@O*a3wxZ>Iu9|vA-j>TgXUn>VvYQ(&%Fp#hpe7=nAK7>{#z7T~iuvy} zj&QI`qoBM-Ft0VpRa-mTl8R+KHWnjKDW8G=rmhA^OjHuMU&3I-%e*_HbY0lTsORIf zQ=FiFXic_IT%~vY4oDkKvz`fxU7x47iv<;mS~o%Z$j(uQjnK2{vnxs$n52}g6DV~g z_CXm&pdh(mlYDz7mhL0ED9)qYMm3LpDY?E})GLd>55A#Ocq40>*e(?NCh+y&kHehU zT5Mu5el+O3H;tvczJjGA9%@y8*s{HE%gb!0$BPL7h7K6tf`*3j0tRFo4;{2taW0t= z0`Yt>Yhb7MmDnapES0}}@#hd&Ir|8W1~zZx0F?8O2|dyjsQJdL_Mofk$pD*;Y6SYz za@p|gidN+aqeGA=@Uj83q%d^OC8>Q?Uc{*N5hp7~2a2X^k7Ungm0nU*vhk+!Ht^8Z zIvOV9pTDb3uGi6AXo=hIBX8+FIZ|8R9|+|NL%Dx^uhN<)cEDIr~KiER<>mRV~53SAi(51w7eP+u9F}==Kdw;Ix?E8Z*G3qDzKkpaz@R8s6k$r7lOXnnD=trBsRD@O z*stO$UQ#IwgdNzTtLq81y-9>+p#*=I#L*Q@C|`No|3QU+z<@bo(A>Y(6j&uQuB-sK zZb&-l#>kYgz|o1(<@X1nCtHmSE@`_J(-1}C_YzFC{aYkR2b-iCo!}5K=>IJ;W7Mr? z@cN~vg3Derge8f5PAZ$D-~avfREKKH*kwY#0Pq7aVA0ff<%QrGg@`_=d%9qJ2i|)B z3>Q}t7!jH|@pz)VNPpCBrm;CFW#~xcqmCAgNu^3bKDVs1JgG9V-z$f|NU>bvBFpo< z+-(z){Zl}xuz98&FBdYFc8X2qtA-Tm@}UZHL*J9dR2`Lio|e@KE>*8c__OiePwe=p zsc2MxHTzsXHD+6wp$7v#g8!bsWVx~otC*ZQzpd_?DVh2`ZmCq%dYofG>7|nQKU?J) z3igk9^tNb_H(q5@0=H@|yzLMBmcP3x;LWkcP@LYhIUlwN7qdiSgG!1 zT1BeFizA2Pq=OIBqVq|;4T0eBs-1$a{k)@pZtj{(dLS-druXdTg2!%iOIce?i@yq8 zh#DK8EgsI>t*a&Jp9YA?=0AnG+-ClE9n)0l2k1I?QURH$Kn4%@tJ$Yn$gV?DSeES7 zzj-Hv%|*OQn^W4H<6HBF6K6aPAXJ-}DynJsS?~}#pIGg1b6V?YKMz|Q%4j2vf4VA_ z+nl2q+gvsyLdt(h?2V&_tC}?Dd7CDH zQ70bHG0Umd)Os(JyoC(WZlT5dFsbxtqq2t12#u9nYynv(3nK>`hg-OFP@r6s`s8rU zrQQi|gA>JrL1*otrtN3`^UvTzx}uhKxBeV=!~Fl3VUAYqgA+_lPI9f~N9Ir~ngWSK z?=KE*diG6sOtYI#Mh^A?MWyJ4a7ACReCCWFXXt&O5Z&7iU;vpR*$ESwd_$|XN5R*Bz;4t)aF&xE ztQ^SLv*dnT{zT-bNJ4LTruL<&HGn<3!*@pUU_kpYh>}^RO`4!dOGcO0JnV6kkwgTl zB%f1I25wV67`FRTPIfYDR2OPf@M%&DZt=#Bj9e(hUI-r-wD@pyw|WzE47$GOO13G) zRf`GzHt`@a=>C)#2QQ&ts)SUfSJsVG_nw9OAmXlo0LaOxaI>O%!T(dRmnr~ddu~y3 z!2lezFw%n%*X3PevOdDg`UOfWA3_R?oN>zJLgT8ocD7gdS}8702E{VNY7Mhx@l z^XEbKD@H*F^R%v()~Dt&AX|GW%eAomWoL*~j^;^g$;FQ=2mYmu@!cVi{jh7L+OY;w z@bKr(w?1pTcp1Ihfw?s*(Xb=`!dn`WAyflSCi9l!0U5#BDW=NjF>|?a|d@7cEV7=Vb zFvO9G;9TqTbm|qJI;14RTV~TWxAEP zYY7om=zd2n`vVFx6_g$_VcyU8+(mCh;_G^DxxiT(g4kt#azVmwDWrgP0iFT0(q$z6 zbB*nm(oA;aiE8lp^xTA{d6fYUaDsarodGch=NG%1ElhhA2aj^#A%SnZ_(WM6 z`l02&yl~=6yG+>AQgW+y@TPoHBwu+-E`=~tnRjl5z*%U@@UfNo?T|pT)NL=Y(GZNJ zV!NuR3b#b~o>*)aEwgNv`Nlr@zQuFGw!>lb>DuRIN1JsoOZsce9K`(?C8d?5bd@8u zx5i($O*yb-U^6D`ca;!pi8i}KTZ^O{jU^Yg0{`K1j*mdHNeQ>i!Lr$Nb^B#UsBQ1n zpSK9x%jc69?Llb8vPx;#-@(4^UT!gPw};+-_enh{u*T-UzYL%8!~||pJjh=_sc?Ms zf46s^G3i&}W@vQ4<&a(XTp~wlJ@#-k-v_LPnV?!yduu8|CVOSLD4!4=k2>~RP3#1j z3bMmLv50je)>aRw5_6ZBQ`MqmsMX1V(hR%=yG8J$-&ZEg_~I z*3@k3^SXr%AaP#hGYHi-#^i|_KMu>UK|TLpAy_(A^1aIyb&&F4$ktvVKTUjns!Z+d zu4v|7x$xl_ua9w^*o(VlKc6W)BrZPuxd;zRv^-@`rKko-G7$>3eyQ#Wr+07M+!}5u zqS{6LmN$qJlnG*FJw5v2Fr!cz<)WLD>uFNDzPA_v1G}(Ecuba{Doz#}iOu_h7K?_NIwk5B*1UOLiD5iolrZoN1FSM+#;Iw=* zfa(=SQ!|$&M^$7dhLrN{`Q@Xvuk!JCO-M($X#U#7+Si#9u;Y2vRD@G6hMiG=0gi(_ zpGJ$x3%-*sT{5F_oVaC&Kf(oPz0rxd!g)`vEpM!q3m*QmH7A;F8|SENJIA9*JY^o8 zxqsI%dJm~-cChirQX9Tzlm1@L_R`zC4(y|^yF>}RaCIe^CL}N}?cI63Gu9#umwL8h zn=@MkwQIK%;?wm}oOUjzZ|7!f zu^ZM>M1I?FbiV1Qm2T=wY>_!LVm3e|3csmg5u}d&75+TmG7R=15LXV#YCD!?B%8}w zMm}3XrT6aKBm^PchEgNsC70ex-_O>~DVF=>^$q5Ha^f!Y@+&s=*L0hCL1EB5JKO)T z2#>>30~L*rlx5wgOD%R+nciKfi2tD9$cpH3<6M(@6kNhw=Y2s=njw>;h7vP%bBgAU zSK(wD_Dz{@FDeZJg-gi`nlHpPmM|a4jCVQ96C->FLdnhl{pEZ`S}U+jJXa(Tth_Wt^OX%Hnlm2 zeLHqz+(rtx`E?$uc+a_w>i~M`1^Jec*sxISjZQCjt2+D8x9zp$d^{(TF(>ckbogtf z4jvE`q$z2g6^Q(Ne_oAH`k*0n_*T~L%XzM0Feeh;^&~Vf$}iL5PO9k@6|NHro3 z>$hT_m2XS!F3d1k7o^K;mKW@`(Olu=HU4N|Gsh}@pce-Ro2o?msMvgUvwdvLv2wT$K-)%VVB_TapzpR08TPc z)Lh0A(w!2RX6jqm+0q3OqOHQ#6>7HE>$W`6{k7tHz*_!VkbWfhHrwMWc6!W_Hu z(%X^ov5gyjpq4g7GvvNyl^Md*_T$7!xK~vaVPC_j`~Y*a!Tn`prH)HSI&U;rQA@vm zStUFB$=4R}W!lJ=nKjrW*j`J-CqJOdz78I&IiazW%&)m@+A`~1+p(uVD)E)^UtbLI zbTHQ3fABD0cPwkSU-OhS;1)6yJ+!|nVWTE9Q&?B9^E_2~9Io?d)&f2vgb!x6!%Y_)iz3r( zyxe5Dj9hlclYCL%KpmqPvPtg(PFl6-|0z&cY1{~)6&44~$taX4&KcR6Kk(yo z4C0=__#1E(8-5fwX0G4jCwNY7o|pJ&7q`O6O;rE^Y07o=JOKw2lz<4g^~*?1R5h3h zIYu2snrP(3`!!tdw(I5qWVF&T2Pexg8BxD9pm{)W<)nUGJn9$JL`IZxaw^_R|ME`! zGG0Q-eD@#M^gLM4j{P}ICrOJwxh8BqX@ZK6PEKRLG{JGoEu;&&K7bl%cr@Py5kzVo z1jrwdw`BkO%P7dt^tL?N-d;#giyQ`>f|tpG0ei z7FaJk5U!SP^{v@%k6C+`wLNh&NFG=4G4HfGCJxiXEu{w<&L?;}KiF61(l2u~wbL*2NmUuJSIXWl=feU?E{i<` z#*)X;2ty19TeCjW2eb9caRaWf?PF_nizF^sRmzv`N$#$%!%#8zO()7+20)e%D`YAu`Eh z3v4Ul^;oDwgfosoQRyPt?`fWlV5{qf+_l)0c!SczPc=F)MK{H$OlXlR;NOv5plNDDgq>NXk<&&n#GPAU} z=bt@y7+{Vxg|9c(xG^70PP?2jEDWj#E*9Gv$P(i{s;yAWdTA|0`?=X)6H1m<<0tGR zNIJ;Te4f!T|P zrdAGY?jpno=@9X(OD1;+6k5tfzk+if=v7D7W;3&Gv99ey&RljracHpOqO=vq0^afy zif7F0JuwOd zD>RG(gcLv<0^p?ld50!l-xL4P%CHK-(YNDD7ezAQ83&TE(uiRgGI7Qc&O6u9U25r- zv@_WmJ!&kuYJ1AEO)T3|Jz;D>W&bE}k=s5LX7yBnnmzY=v!p{aH`i1qR*|sd5HL5i z+>*V$D-V$HakJUm05U@!wFKtN9{BSckb9vY%vmKL22fO6k9h1#G_iV41k}~SQKPy- zz{mu$|BMa8ulK+2Kb(8VrfbMZX4y!R)l$~SxV2fvY=UzR0$0*|_~OzB$jG*Qc%E%Y;PW-P}K zubt$QrYl2Q0e+mxWk_-L#hz){{#@yCZIJ1x)F7q+{5Q-J#8i!&G?JIDbu|_?z_I-I zSL{E|@~UsPlws=ZY9!&V;Bn4HkJnl!QmdX0?Qe$^Z@Mqrhy zWBbzn^dM$n61U^@8^MTISwCyrzo@Vv<4-<`F}+UpTdqs=gUhx4GY&A!k=QsJg<5N?Dwf*J&iCj*wg{9r~Tf&$8J9DJZ z_50A)xVn3rr>YT@kfenV$AX4GqFhlg?O8nCN39 zJ+H<{zI$?G=KiZlz^VrA_pT`Tiu1;M<9lm+jsk}%(s37r*qi9t1~y`ch4*)o<59F&3-dMOX7N z_Ah;4*T4rkJcVOFI{HMknoHEYzC(L=#EI=S8=xO)s@i%l_?%sJj-bNY*6`mDhzgxrn#0y5G{WAkWGdt?eR9ysH`o4O4y0GPG38Y5K zL;JPv#rC#?Ic9NG6=Gvuz#Kn!SyulP3Xk19&&n=~P0p9JD`zGp%k|c_YC&rAVkJ%V zgiIx1kWZoj38|)?2T@p7qw7^0l%h_-V&Y0y7586Uj5U>C)*xAzPVV=(u^FlDas@MtsupL=Te?JN$m{&_&3W1Px^@5Lho7$K zp#!G$z{JMb#VRq3+60v2>R6*p7nKLtX<%v40Pe7ofNdhfa^=dQ5R}96mP5vVe`rMe zxoR_E6#>VyHeSN+6BR5+;)c|RlYQ{$7o+2X)etXq-~>;9*s|mflXSe>w&Y!=l#}X` zX}+Op3zs{vp^r#|)Xv1o=AfAc6QjicbFulQ={nS*o@?{@+WpNYnA{n;ma*A)8mMaA zb5rewL=4=tCHAmqx0)A@u}9E~WPQ$I?=LY-EFqNoXTjN~bJkf-AD>ew#RDlw{_F*_G|t*f*`g5zBG>)Pe` z11jkbv)Y~oUvrtwa8h@*@zqyrsYx6b%r2LXalCg|-*%Iwvz~6K=G9q6d$tqQ%GOYX~|9QA=S^`NUK-Ta2_E_|HdPm*P@CxX2#9ZRyA2`@`` zDy**GJV>mhpqV6uJYQ~34BktLV$oTb7ht##qlyMa=mf-i<-Q7!!1{uHTqh4c2*fZ+X5wJor zmgT5F)~x24XyAgo)}VS%4UKz8}^%Xc$w$edyKZ~1-0g5T!c>-^jF zXJ#rlz7j5?iR^ESXj09yMnAY`9NDXszU*h355EY}Vt4;PRV1p-*x9N8&d^6vtH9-*F|&xGhva6GSGO5^(`JS!6X|Ndnm@T2>ZefJSe>; zy8&;sr;7Z~55kXHjq5}!`?hM+GI^Sz1;WML?~ZF2+3ltIoR#@dW%Cr=YxiLFT2>Jn zb8W-tO%g;ydHNUd0jd|{19e;S!mMp?yZn}~LgoqjQ|y4xxiOjI{Bg0?C~cYg()di$ zoc9j3n-*C({G?|JgaklB!qn0JxcRExkx$&&`T1ORv}=!^%Zd@Zf3JAFreMLDO5@od z1@Xih=EVBNc(uJ(t%O`#2`T=RWVD`jy3k0649D_r=Lz+Snbl7vYZ^tGbu zXF>F2V7@4`FM`EOgrur|lnXw}-%uY%w$85BI`8bmu}DvyD%}?wtGM6{Az+c&J}3ZO z1U9}rqUX>zqr1w>Is6hxw7{l3!7Tmjrj(RA#XTfc2=GE1DEEg8^JV55wB)UW2CE0k zvMnk~axGhAU*K4pks^9Uu`2>aqt^|V1`1c>4?x*J99vaVx3_Hzqhs{%e3Y=lyEF@> zb|7sGegXoa7Ny7A7u!dH(q(kOvH*PDK{BHXKR-9UE;lm4E-r_DsA)@(LtXEe4~N=E z0Hgo_I&wjbXB!0o-T}NpR`o$J{jew5%tF2ETBm1Z%5t7PE6>Hr^~!|CF1)vv^ zAAjq7drfiIEIprPaDn;=pTUfz z+qu3emwh;Yc1h;C*Vt%l;waD|*E5K`-2Xs6C^j`W#4lFM1hMS(l%nrOD$5&iJfM>+ zvZP3)89AQ3*hb=K@t;2`j|b@MO6O>~pIT#6M*ar8y(Ey@H#IZ>I{+cys~luZPEO9H zU>!d0Z`st1eEI(#dpp9c`X>u+|JW0pfAzPhpHw}&WVY{`p5j2=m;tZcQeY@ZpM`QH zXA7u~L05T|dTsgd^DSA-=!WGydwPrkfS5UwH@i_s_tlQfyeqVS3gPV<^SYo8e}i(K z(9=KGP#*d4Y+!ETLUQAe*X8l5Vcm9bD7kEdmz|xRC2<@dIyJl5EhU`~cm{A(ogE;l zK5}Q-+f0~AJ=K1A5;ioTtv%WHd;Zau93HmptEQ0M2h^sk`)xjLpN@au^0DJ#zUM6v zb~isIp!{oSjyy^a|r8O=RS^gYiuI4GeT20VJGi!I441{`uQFQf$!rG3wKw@bG_6weIeI z30#ZN>KPa7HBB3}NHj3}J$QraFFcp3JNM72q|+~;-EULxKWiLCP-tL^*A{~`_&%(jBhj)O+a~O@CsyIh=w5Fl zcbt78B@bukS>qKYi~d#V&;hRlRW-*d4ltn3g66KXdNL+G;8N>HlbVl1m`6I1^EHge z@!?uCh@1e9oT z-Dls?`r5w7Gf^S8tI%@D)E&R%4e;tLoiqhhOleYaCTRd%E-fZ?OH3O>pukOg@v-A z#})$55%Vr&jS6|&pt9#rt$T9@CGQ}kFG%vcvWebqW58wu(k872y1HN40zuoqVG|KD zzp0FHV)qg%l0-!$`1=+a_5Uyh_wbLwx~GV)A)=x^8F zK`o~4V<#D@%}hV~gDwJHeCh_PTHF;xQ3Q{8DCwBIdvXH*Gwn2h`y#Q49PevN1wbFg za8#DF`*c7(uL`81yC06wd|^;zUMObTooJVqZ}LQ>qbD=Q?`YP<#9}j|N=xQEZKpai zy1PJ=G6HTFSds635NW%2F6w+HH8}n|LmYu3Bb_Ix8Ae!g8$(E1zEj44bwsJ0d%T{8 z^+jtnM>%2(HstJtS|TG~|6^?p+!#Q%w*Ar6DiD#sN{Y%;I3YE$dH0y#!^l{*C;KFK zgj7cmu(s@@Fv;bjK=(G?LL?!64sI3;+jU>?Yl?th_~=(|v9o2qG@3H*z3_cexzV%V z`jRWLi}%k0bFF3{!6@p1Fb>np18y=VPvb__T1Me`Dk1?@pR#`LS+L=1h=ZfpSrIbw zS&FszqaiG_&T?nGwWyl!q;ZwR_Nffl$GMq(B?0f+{$KAyHa_-$%5Yh^BG>Wg<+E|| z-R(GNm6&G3@q7aqG++hcl$wZ_1CH~5i*N_U0$UhhFo7!^%e(u>v(Zwm&~_0OM=rH- zdymK&Uq7=l^M^Yj=)|pzTjy!|YzPT{>*m+4@XChCbAor3 zN6jfkJK6o9322_+fYPRGgT3Htd>xz8d#zXUr%&(07 zE?va#3;>M)v}`(%(roI~BhRQM8Z-#*wntb7Ad{Cja6OltZ{sDSo$@saIK2mfdc#IV z)F!o=R6fLp&rZp$bmwpN?v722^Uq})sXn?gaSE&QUjgo7j+V`0jy~~nAFR;TpACQu zH|Q~0zJ$1P7^=~>OZ)hMlb@u@YcImwM|`^Q%*{O|>`UJB5oCslz^)oUKTq1ofddLW zA$-aXa?NCQ*iC#$NlEE#$-c&YSDBg5F;R92?iW4G9c2nf$eIYQDtJ%NAS89E$3JA7 zFYL{i+0IH~RRO%`253WWm|{y#(E_=zD_RllUtAVm>smBbRZr9y$(!tXXzq3*L&&u1 zitKNw?I8j~Fzz&1c5%_{pkB}}j}^93QrS>wPCPe34aO=8nY72S-cnX^Y)C9JBNm!8 z?E|z{MR6^E*X`lBhLYAPQ>PH^BomLJw4&~!j-cx4mFZnicZpUNV3Lgkah>Sn8nr=g9o%yW%J<(w5}!fJ)4_$zvO~MVkleyVXVnUun?m8Axa9 zx11_KUlDMgI{dC`Y&EWya#TPap&Tv)&bp#FY=!D91jxHd0g@Mrbct0E_UjawoW@v*Y5WW%?2oYs z2af_!P7oT`=9#DRjOr9gzx?OF0rzvF@|Xpwqi=7!pGeIv_eW2<1Iqn$60xacJnW-j zkTP59#czjn+v6Ncft+K+Ql@h)W5b^W-da9y|Eq3pL^*P(Gj0)8{9&QP@J&Fp=7 zdyXCR>dI~Q-~MfUtFl=n$lZw^CKq43zw|wMr^+{z@NLRI=+_-dS3jl%FNgm44 z2hv2$6dyR%3D5wQSvXr&2ZKVq69?dK20qa%#H81OCMf|=f@`&2Vmb_N^ms2{JY%;{P3p8cgNX?)m@AJ^ zs}7i@3=1x9H2W6fOcK8JJU(M!L;oT>*vOkq53T_aOXrOgAeC$OTo~W={o)Crk)~I@ z8I|7i{)d}Fk!vs6=+k%f@t2=I@}O-SETf65heZ^wUBjk31J_|eaLt{7Jae66_b>nN zuhWzA58h)}ET^};hk%)ptTfN$)3hg6NW@JU`|73YQl$1|#+`KTxou^cLJYb$4IXF2 z5+$5+U1EIRu7&sF1#5k^Xkn@Nz|^@NA!v^SQ*gIxaD{fv(PR8=!$41`6@I#k89FYlQt2Q;AxQ2YiIBU zDFJd+Sfo%98Uf2{lfdzOQ;1<}8tkf*zB!azR)LB?#V24;Fef7w=U z`+)LX*R6)+o#bt8)A;;LW=_|HQ)>@}G;C!GE=GPJeK6#C)*@_JJF1lEm6lv^AgSNr z(zKWM1@`8qAeYEAc~f%41wL*+Mt$@j{)+L*iN4FIip(^BIw77jx%}*=E1kD@Mb-pr zn^H#kDg%A1gn~{86_u8Nvo&!sW>kqpJ8FF=ds%(|Il=7(g=#f6&YF0LdBXzA@$&jd zlKRinaoW+3#=H0ID(om|OZ#!lK6QTdAZ(a4Izaq(B8@Oai14?3ELVMEpWP>z!J`!f-&dt@R&!f4?iiz|gEbn=30nuW^^I~>@8`vg8Q|z%#R_EI!rHq| z?uh^yXt+dXo6F41aO2EQ92~<)_f;sClIzyVW7T&_k^g2pfJcx_Z&*J7y#sWE*^>WB znIVspP6Qm9uA@_QPdNHb5GU8^hn)8K{j7`gd!jUf6nkHs;(i2khPtN5i_Q&iiJC|n z)UKZ~$QMkzXHyW-Y=FZ4MnikD=rh|HiyuqpY(mpa8M4F*qwkaRasm1}7#VTj6pt^| zBkyx;sUk}A=0XOmN$izVvRUXQyt=)#(~(My&sT6w1iKw#a%oe!eIO?>2Ct2LHLpI zysD3Cy8Mi-@&XuV!=_;kYC-0rie~lt0Q;CzQZM?+Ldds5dJxI`FTw?NTTd^Z!KU;} z<6)Cx)ochUi#wM;c)4QA&`3jtTID0pU7?yVO2@cZC%JYC$L<)tygur@KH7a?pCBS> znBJ*m4RdMtAL}am1VQdJI*!#Cx*B&OIX+&DIKO@*tYZDGQPyyLt!sjJ9xiEB_^Y^G zfigBjR+dD9Hxw-*Jn{$Zx4Voesb>rsZ!5pY4A{1d4a1jjqGvLWTz6JAqB_rt!J=p$ zQVNt-yGVqQ@Es_;z{Hhd-;=&h9sig)A4E<4zV4tBzl0oey9>AUSxoch{U%DbspzXoAcP21XYLPU9Us?#Rc)T?}OQt zzm^K2JLF*bumYj%vaq0sHSy6eZUBs^VlIUzR<5Nj!$-od$c}=}2)y#_`n5v7gb`by5rYL+%wVr z_oj(cS0T5Xubcc*fA?qkI9ul#0TN*u;}i&bKPh2}D|(%3zVd0@N;*XJNmM7{`wSDS z4d0iZj52|OEth*?NM;L?;_MYZT4v@DUkZf{FXq6?_U3J!TB!N*rrRQ)kCO*Wqut;?T(})W+^p zc@nMISOagUQc@MZt9OX~l29eN%=K+9ZjfpT zH{*xwY3TtP3=w5n>_S?8TgDFt_Bo>92KFL!px3we(@ubE8TAP>G(rO0Br2K6HRENJ zZgRV8eRB9_CgasxF=<-WJixODf@t!?U%s`G&{Zd1dxaO0%@)jjajy6?P5r5Rq<=`J z429zuaZfLHRzoox58LV)OD5^K<`r%yrT^O%(>lziy3$fq-*td??yuW7-r2GXU;t%^ zrgFPI(9((3_#)uF&Ge?(ceH94lOhDD@=+cZK!7B!B-o;+!>G)e@?C zi0|7qcF(|yGf5lWTIfZo1LOLWLaGHED8tCexDB2ab?&SI=S(k?@yt`!XXv~Ku%`PA zDwII~g4d52g{|J^%y<0mv)%{R$8{PMp3a@#Wq}nna%2P<5D2YC#>v`f_qEUHY(Gu0sY32v&G; zPlOf&s1#GHs{fFY>0_AV1iOf-TD+k6>#rmA!k#m}=ob$p3TP5)4HU$-+?Qop4wq;3 zD(tC(3Lp7)XF3xe0h>Pt1ejCD8nfc=VLsztgP@4b-U`vCDnp~kt&(>afDa^koaydU zSNGJ#y_ym&>+eGLeFip$1{_Wun7HF!`1P ztc^@zZV3UaT$Vq%p0A%wskzkI;Fy{TP7(>nZTCDTGqT|Dknqt8s;WHYlgAp!$6;H0 zCTTX-tj@sh4(JF>|0FRm*GKn;O=4)r`1$N2{Ob44@mbA5+cftv=rG56vWe*Ha(01m zc1BfwX>GIwb;j9M(M$J;-sPPFI%~qbeU!mBpYUGVZ_))BCjnK|RxnEaB1M#0w<7A% ztzH+#DOk6{LqhKy`KGU&jg`kXx$D-~^kVs_jiurz?Kk4eA@bFD!6IZMM6OExIB<`Bk5dwwF$44hQHmi(A zi0w7S&37}ztp}O<4S_;uoiJAvK|d?d8q$SXMFgnEFc=@&No+gmfof2YQ}@ZEmJb+} z-i2_AsD69KS)Vc&j(ZrLDzKuOEZKpaID;KQZ+G`ql{KZrf*?YPUb>i^AGWda^J=|e z8l`>9;gzcHftMe%VVt=X_v|tzw@o!z-K{4?R!UEGsExDV)!0qcik(bVz2V}%+ubS3 z%tOQg9hJ5n94FZ5uzW5<2;Yx`%Oy5FX9+~l`#_)aZLjZj_2WkxBsy^4i!9yNuSp=?4RLpCSg zLmrvN&iT!pHsWik3?hC~1IdI}0}A=krRPt&`*3&7Bs%_anpAkxE%&Sjn1WwLtn+wt z&URIOk_o>%6;Dp7XWe8-1#PB1K({f=nJ*zN4fZdIO~~9h5?nf5D*Wy;B72Cds&N`4 z&Bp!Vg^MtJKYt-d@K3Dr0pkPc7zaH2X{}!o7sP*^+hmQ~hO*^G)a!y7TvZK3(S|0Q zeGMG{UiQuD+s1w|Hgb*DFF>t|O=Dq^a_AS0~HK7MmJ+m+-}?Vax5-|jLHbV*-5U?R}Jy9 z_y_7|7F;BJi6}Ojg+K;k}*0%-mhh4>Mj+KC)Vb9P09noc~znxU|nSj zF#)r@xPuoW1nU8Gl}e3k8f58|nBQf6>DQ3k1k9Rzx~LwM>}F-u`cVsG8qid+7`h{! zXNwW0&glNgV2$Igx&OFg=(iSMb|)~@Ed}o%xq8u6a;m9nwk2#3jM1wbxRnF~RwxlC zRBqch%A{h|W`kekW#91>Y9$AOuCr}5DONHJ1Uxc+J@gQXEkToNc9I))!;sZ8q0HHj zZLF#J)Zf$D*pq1o3J0@XT~#0T-H&7;96y9zVN zk2Q#ilN=;T%#cp)+#ZC_6dp$h>Tu^uIzc~D5c<#hwD&k+&HQ$Z!+%^UYze?9-F zC6l&KPxW^BM_ova{yiUcoC|1dDM#D!=ZLFU&@U*^^o^h(DRz6*=7iz27PW6O+-tP! z64Z=Q7T%Fb+K#vNj;rz$df2mlXlCTDns)Dnd}5f!?%(-UMNfp|G=WwCgE8tXmzeUX zowyQtO=yh?y`(vFkDrX+tH|ERfpR_j9oVoLH?@K=o;%U;+)lbFHRnvOS*HH*<2sVr zujmOumdU6=l*$KO2gQf~hp6v>hHGp8b`wb?B1G?k(R=SCqIc1I^fr3$Hxk__qZ34p z9tL9&L^o=PHZyvQE+j^m|8d{-t#4RkY3J;-&pyxI`+0t)VRQjpozf{~8~h3l5@Bg* z(qojY6C3!`YzOo6Lli#Qp-}3GPnrtdPIO&5T6&u~>Vhw*P&(*jbS7}ca-D!@JgN9B z^9)@5rY6BcOg+A*sl~VNCZ(1sw%R8?+U#i~_<%cK(WXvGgAV;|kEOaNGsT3$bf(Dw z5(nsr%>=|JdjY$bjmZof3P~UxAftJ*fsAi8Tz3VtjVGwQK*rX7=%2K!DSTkuW?%Cs z*(x%5G2_g2zT?vcxcKafm>9bJtRGyJX|R~b=QdIYG`a9y?I3u)7} z$G4K9=@Lxn`jQv?$l4V)tw56IS_#Y0te&(Z#c_o=xPct|4Q*yhr@q_f@#hOW;k zJ=fu#Fuk_|X zc*9Nmib(2}pa{#ZI+1!%xES2@ulhLv=!!n%#NWmFf@<`*t`jRcu zgvXd%g6@S=sPUI)#n)7Ov>mgUy-*%1&fHkezVpn)(5Fx(v5-QQ_fPif+Rg zXa1r^s&N02<~YKIbCA}9AhJ(}X&X?&ccGwH8LzaxcyuK<1`k|%2l_-kut$X^2DqVpLGIW+!VZ zi|-&|^0n+MVFQF~eQm!IzW5klQkg|%gx+y}4OCzr>=lRa?0}N`myd6(q({+$j&P*+Jwb|FGTC*UgP}CO#%INpK72?YjR!kVB zr0DmH-?u%?(_Pq~qBzldbl5P57_2`uaEGh60+=%AH>?4!xMVhVv6gGWN-07JaAT@2 ztofZlrv0s#v8nK@2%C{5Tos_ac4l(E2%SIp{H}N?_@MIW+-LJArl#r?E+#EOl-&ej z;N1KWza2Hj2=vEk3Dtd~X{V(O2E=soyejOF7*+}X!W_|U);88+wD_o}_CSw*ce^^T zTFq+_5<(ES-4x8qCCrt;xWx51Sv`aTT+^UmCHp9lUUx~!2sQPiT5<0nxZ7GF?Y^z! zZV2brn71kkn^JVNLUuK}i!d~M>U=NN0c9Eq6c2J_Ie8xyQ;={Q%g^|#>+|CBy3p4u z-4^Ul=yv1QqQY}{Vt|@TAoK8X)9P+Dos!- zH6Ap2Q*mHh^H^x#kE2b`yfS~i3Cb7}Yd@V?<1G1R;W?{+ntK~MU7nJ#0 zk&7ps=_1Gf&#*menTpwdzEf|-hGY#41~=&QP-sLIZv&xNA+}T1Irf~&G?m5a4eX{$ zgS^pYbRaRwlG|cTB4ikA(Ydu&HPL!j+Bv&O+LBd2n5lMExNA5i&feFr%CRqRTctq7 zIUi%Wy7HcwcjbzNY|@aG)g-am&gEe&MPnI4(9lqgfYeic<`B(NsxBUFE9-8+eWYrMO<<1OM-oE(drk3`yqRF9-x!!85iejuv84*?NXSRv#qrl&Kx#h&>%YkqE~3iA?&_!zGs2n5+6N|($`Xw#GPNH|Rl<|A2X6=gjZe=1R}t zJ_T1b-8`IVC~Bd!H_a44kZ@T`(2zA9lB9Bw;WENz-?g&hOK?WVq~vh++a;|j+gw-& zTHVLej78He1{BuV7g;^{+K34+bM2^`BcGrNMay~g6*BW(c?v+N*k9(@WNa|uZNF82 z$HQD!7FMien^PtGa6?n=j7yI*1|t62F#xWf?OXw+Np7A1c8XA?qcs zbT%_sfvdRuo+k2!R}HXCKu8H;Y77Q@sCD^wzzjZ{g_H-V%pWHDAq$qcPB-J)Re_pS zS|38-I$R{{29aYAOd2oKy~@Ucy#a3Q43qeJQFUtUz|D4aDJ-(eA}r2+*Y=Ib{RW=q zB!y2v)D;GO2#r0TELztHBsHyrbU7Z{W*48Sn7pWaWo(oxK|(`wRxK6fFgy>%rft~1 zIOp6L(_1~u7DY8?M_5jzU~b!6ied=(D}gmVAl_k^-G4r7gOiL8TtzRDjO8uixv2GH9 zdAB?CU%H0*6EG7-;_Y$D*<_rhYr`rZc{D0Jd)QK^RuXfn@gnKtTqRBWJ?=GS)~Ba{ zq^mN5u0~~h&wynSF(=!-7k;Vi&y5Ixoe@-NeBEs=fabmHisw2N{(>kE})TBoxSPpAL^$_x=Ha@!#2_$9FEG3jflh2T(YJGGivYjUg z0|RpsrZWy*9Tk--V(Q85k!Roa+L_Ve9eEth$JwHNezEev!5x6{%~oU~zq8%fr(YYr zaj2o9nOSY~1rf*HC(8Q}sj!1f-oId&T3TA`5e$!VK$1YK=)#8SI%hQ09`w3`Y|vW^ z9iR6E-LTp4ksLs$RxshXcJS&nL2)}SezZEDivq$WaVPJr_ht(nbA^> zrdVPsSGp-aFGjpdeO)pjpFQnzn3|L$Bu#(cD;*O^&`AtHOa&Ttm!JOeDWmZ0qF(rm z)0x&w2Zn0j+XcEhw`ASGy4I?Gw(`}9>OxGaLL8aA>7u9+iO2Q2g}JI1alQv5~I zL*(T4rSsGSNP`X8n`^)AfdNs0JV?6@9IB1a7XRN7|5p_S8vZfY8-g%H zKeX!g0`NklQ0aERf4m)dq603qy2KT~6TkhX)e#L_8_YR4o5291s=e{iZh^9=TZH^K zNLCbTKW<8-fC^OLI+<)VIn{BCPFH9(UtG!>Yq z)%*%dX11bfj=(xx*d1Vng6QD)@BGe(aYV! zkUoRAdF!Gq9HvZo%&F4ET4|-RfJH9lr39$fj6>02D0vWN{rkkt!a^{BVxY!~q&(#g zSP2B^7eE>}IaQjZdh*V883bi&&f1CyLY?mg5u#d_G|zYY+57s&x^7&%hQWVv_IQ$n ztS_;>)-}(kYDp+)cDc0Hn$=SoQW~}g$C2?Z#7^&7@8J;>6R#za%P^OKQw4oh7Jl|O z_g_&QNhPz}^qZ^S&uZ{eTY8lHAm5cXZW}NxH`i9~l@=N{fFk;0*OG@U6B}oKe|k47 z+;#?l%p=8_RaSsjCIJp+sRA_l13cw&0)KHFBKVlM0y^K!qpN~Im?`oZMX68zQXS_% z^JsmFZEV(pWhG{P3qVn?82N@RGbt~n-e@E=f6EfZqkfU3zFvSEK66!0h!bQb^!2v{ zXNIDaRGuheYeorGhooHYGLHflZlQX}cXy?R6Sfj=fzC8mmQ;zdEK!jppDCq*5z{AT zh$=bPg^uMc%RZ>yPgfOvrNsy;8oDNPpC3$Jw0uV2E>z@+y0`)O)z41pb8>_01`~-5 z<(KDdCX<2psk=-&D;o`;s>@GQr#W?Ch zkA{0-;8L+z(7MiaqaRFQ8f-G<2lWl^1H5SG<@Pl@$K20?T3UhL5gM>)=d&d%^N=2( zYv?%12~dVK*{>ETy{M;8z#+n$gfOXf(Z68xfuSUi;agS2_#m{?eU} zB|ZE1SVBxdxYrzY<*&ODyJqe%k(&*f%j)>yy@5gt`kk)Z(kB~@YSaP_;u>k=g}rvb z4#}fhW30JOes~`3^L;!Sf*^UZXj7*lV!0nYo?hL4S-tKGXyn6@Ak<%+F7s4NQGxAC z+~IiuE^@~loDC8L=z?kIX12Dr^~)Lv^2$uLJ>IElt_(5Y!3O?75`d4C{$ifE0Py*Q zyYvx0n32BkYSL|F$1PT-~e~W z_}^ERr3$O};}8fWsn-rj3`zz%Di*J#@jh|jgN-BxxxI3zmWsP;(w*a*Dq9po>p4YN z|6d&Q87rZpt0j->fooQQJ5wxufT0KnaLOEb<^bVi`%lGeHgUt3r5?hkhX_7?~$oC6lF#~PzN7KV{=L(L4fjc zFVmz`)SjSLA{gxdzsugU`>(%AHkDFKA={I<%*{Y4dN)i&Hoj0^?tqVWcA4`~Zckef z9#SZ=20O3CtQ3Hl!8aQP96Ol_@3sek&a~bB91ZxU*%hb(2jBhuZ9vp?3b;__FyH^K z7*K+)0&1)PqtkX)#PqgzJ!0cJM3bz!(nI7*^yjFJhjKM`O=Szn(`X{GJ>6wfO5OR4}cZWPddCY#_Of)VuFzc{eaC-WY5 zslXVa=9dd27R$To9LSRc3dXyOCAvTAIM|d+CXytFx3tFW}0~nT}Vzz8aew9&IRWyKQaML_Z;d}t5;T*jI zcZ)IzjYwMx{LvTQ4?l64+1&_@>BW6MHGzAg^MMh68U#$wU}V~KsfMYlr1pI~U)id_2S41v<_nwW)PYPr zUp(H617MD*1V(tYuRKu)^&Qp>8U)~e0josWs%$|25lCNsmrDEWG@EP!O2w<@>~j~G z8#EhRMXfD037oiCUzlqzEVxyt27VDj{DPwo0a#u$?aWv(pb9Vlx-_%KY3`MzwuI9M zgJ4>ywkU9PUw8bCLW6ugAWJtj`wp!(4KbzvVo=P<%4$gU7w7G5ESAR%;hK8FR8Dr7 z131qmI+&J!4ZjjgM6QPxFt9*oCGfK(wK*Dt@~4_>*e4%<>lifQQ+eU~T~{q(+HA@% z6?S&&%%F>2|V#u{)-B zWPp}c(*lf4Aiiibvl=Y6Sj{gE5(xW2XWkXnNw8%|x6Wpy^63KW78+1Ta-k_u_j8qm zi;4|=_yDjXgf?#GZX4@%mRkC~@mAiEDKX@jyMMPsE^YLc&0xr`<+AH;;Q)CDs+C{@ zASoSHH%z+C^9N%FDbHQ{UIh<*|C6MD!j>LCt2Xz2Sz`MSI2AVj=xFyxw`4i1Rw7gh z353T$Vj|#FtSUKI0oxd>d5+C%rK4VV@l-wHvx66BtV2g_vY5j8Av2zRJ{t{#11lCc zu;DSiW&5RNL(O&}?ePTjkiG99BEnLplO=}MQ;3=zLdA8TK{DvHCZh%)IPLC$Ktq>t z0mpM@yY2a<#-5aB;39#S(CE3$=bY{<$DQ^sbASf~sebx7&}?H*|AUMWyzwW%-|AQL*aNoE3$%5}Mh- zEZ{#>fKdx*@MH&Mclq2H+_rbnS5(IQOf|Qe#EawK>|DAcxDlJ*FHrziO$A~l8}7er zgnQZr&N-!X7zlJynLzf_5>vhf3cpiQ^%;ZnCKJIC|EfxcCWe0CeGE!9HYAIOmDN;r z?MKWv1a<>rDHIWL`k-;$ng51hfC_K%C5Jd%>g< zkl*Av03X{gVt8eeJX)TE(k5$(J}?HS&D@=d5D+)~-tnoBnzxnzIdg&2B*aw_w8&R{e(D}2a#btbR&7w(u z_ABJ7cw*frEXYKfWZ1m4k1?2LoAQq>!wO)?<_&;V8kpqv3k7bh7+QKYNP!&^>=?cv zgT=T3I8oDe8;3{NPzHd;@6_>u5igaBi>vp7;n2GAJwiiU$z;1VNLI*fQC#$VRs+VP zgE(uI{VIS;I;eg--l(TK>sO$*Vp?2GQPi0G*5E|p3`0pEhb7Jw@U-u zB+F0;OaOs@2T*Q7e^7}p@?svdYVimSoB!gzFGV*zfCPdsP&@s}NJ>#G8&ylqqx+>d zj|SwSjlMn&rAKNW9RmRx0FO&O>$S^pn7e6Cq5xKoHlaN9`2HfroW`MXzyhTmG|_Bg zI6_yM^Em030iL&Az>pg7qT{(cEN{Ho72FlKh*R! z;f2Q&!Mv~O+YfFT=-y8Rjot?Mb~FRyK=!8BHn_y?ws#fs!sa=P+dZGEsoE(Fc+V$Z zxH2MUU;s%J$1RsDU?8fB5mhly7I5F6!U$(UPx&pzN=vy00Xt&S3^hlearQbX&}O zXtn;e7ZWn(krNW=wyXXOoM+eAPL4R}R{w@>NSYvP*f4o6Iq_sR61cG$i5#9z5_qsWUUT+|Ma~4Q(|J!(B;YgwE}CrV-UgAgJnd zLs7%=q;|N>O!B_@)nSCq+QNcagL{P$k8x27XNC@=Krjv9?RqR@5`6g^u&VboV8E6K zjT$#nNvcE@D-fDy%lZbFvh?G+TG_x;1&HlLr83&T{Rt)3CSf2egpVrj>lWD3og7Ka z#e{(Kl11K=jBK7ssIQNt-*&iYIGafcCp8TY z0-aBEVe@?QkG?^=+8J2aagb@%#(&_VX z@lZN5Y_h4}bOr(H>a{ojydOkH1&gSCp1?flS{WEX_jy@~J1&i_jl;wDu61`jsUxZJ z-vDDO7D`lJPRNn zDQ`{<(mY^r<>uq*Z(lRlavsXi$6~INKgrtx*$HX?!3>ANAr12!-WzxliTjagsF|e4 zb*II8?Hdx#RW87iVK^5&cw}BMGBiEn%(bryM=lzEFhO8`9(@TROXEl}A*um%{155= zBXdQ0nQQrG88x2l_Bfv&83L?4p#4+8o6_BdOeThx1KDXpqi)*R7sIO?!}aUP)XfnG zfufS8{ua0q{MVK=C3a@%$Sq?LX}t$TvQ0vO9b5`!YEuPezUi`D2w1(Ft=5_vuPFVS z#;%k&YpxRW@_?yc>gB$wfJ0|bn|bE;LJ8?)-r zJ!w31z0yLqv=iau>^!(S%RL(#dy{}8P+B>~QHE&%$`y`b#B)M#q$A(6NM&NU8CX~! zI5Aq7QC;uq3E4q1?O@ueE;-AOuu^#~U4Avc-Wu>3n1MrUn!9DBCL19Cn^XbX4+@CJ zegE|}v)v_>;y&fY(9PWz3>lc;p8ox2BA?4dT5064C3A_Vty9^0zB$GkrgW+_x9QbV zbIgeUE@^_U+7Aj96$R!(3fiQlpU@LNTgcLddkz5l;-cH)y2%Ju4b2#U1trZza3F>x z+G8i3YIb*0Ei{N7YGgVMQmw+$$c}@!1Gq4L`nwwWZRqc!ay}~n#qR*r+|kg((E6Uu z7H((pH7R?sdadOUUQh`n{g5E=|0e++f(jI%+Lc9~9h4~M4J`x;SjYawi9hj{(S@H- z@pI=KWVAo)1-84vLy+QI9g%T)3bN@hj}TY>lQi%90_1766f zRySpfZCH8Z1sy3{_nFy??`7r?;(KksYco z=x3MzUHUze&C7wsJiVHz_MyyR^GSK&5r^iOn?|fzf==xWbOjnr0kF#N*69E56Bwo1 zqG619=1+l~Vj!?_A^}y)9TGC23hI=LiE@~2X(*Q(i$x>$+i(G;`xn0?LIlx+NDIT* z0`fn8wc1=))P8CJwog#O5R!@1aL||?Qc7iUHCJaf@{js9nRHlI%QPut%D-`Wn5PJ= zJrq-NKmd^04l0-l;qoJqe3h9$;<0&V=HqcCW1_yg$k{?I<5=tjynq0S3$*g&=d=-B z_EOpivLn?!PAAtN6%Cl2^-CRne&~R%=MO|gB0B{OTEgz&`_sI+J z1@^#fo-l0Yi0ku`7l#Kl{(-;Ra~i5d`UJ1_6xWIB>p*XrY!j&zT}*%tbXGBc3D;oONJTy1xU>?w_)5cLMsQ- zog71d3KX7KiCP_eehPrY9HQBvIl8{mL|EeChZe9|8vrJ_-p zM=Lzs;B53D?2mnVVco3H&lWd1`mIY1?K#_T|nvcZJ$ZgUm)I8 z=JAV1n*kWQE*HQ-OC9~a(at~ zStoxC7EYx?&oIkkxj|g6?Qm_}9TpQdz}ZVpCTU=NHqOb!lm~&;C~Z)QujFj9W2pVH z9K24ryZ0AIX>~xREin`&6}JLL3@G10mxz=aYMf~ai{y9bt{8m_n~#31 zrjfwd65m7g-8}S76#{1USM?q`X-@&V14L-%7Fm5w6& zE}!|8D?w571?zJA!c+G%tH+3L*R{GG`<`QyWC#u4ZEWcCQXg`d3aY8+OrlsK-0{&| zPNiu0D;vz8y+Y9Ox0FO*L-q^>!!nsB`vm%j4b8vF574*uUDxeDuZgj%ca@X7xqV8N zhWpZ})R|h~g#M`GXKh2qVj!AQtX)d3whw?5*0_@?PL>AIp-~4|Uw;PJ!o~-Thg+QW zpo2x066qwgV=ri}U1OdjXSr9@J=8t)$rAe71rqZYNB4vo3M4hE9i!1kWD;+J^1m#` zeE%68#BbYIApB`yql%b#GBf;wmXAVftYtsz0Cii}b)7fJ7uC=J3uJ>{s;q=Q?=O_$ zXM?*JIASpyRp*d3(uTsHqh>JBaZy^Bchn;Z`kfmxG-Xawii#^UE|F!pd5+5U0~r zLJ`<<$cFzC=}EY@*G6sfy{eI1LxM)Nc{1l;cKzlt@i#GY5Hp!2f?F|T>fM7W^lrj~ zrLzF&RFK=?DfWu>AgoNv;NU@>7$3dtOvvj<+?54WGgH&55wBG*`;fw!dN=s{=WBm) zuIgOr8>>QP9|>EW*cqgSZSe1F9$sE8nym*xz4`PosYGO3e7I4UdxpcVoG zfD%z22+B)x8OQSA4zBpCmd!5f!N$+7?X{qm9!#|fJ2BXPTY~{L(J*p(b|@~L*C|d- zy&G;Ne|nP_bQ4zogW*R@(pAvdUmUC$J$e2`LkKtOL6GSDP2H*(4_>2z_G0&a(euuc z@czxhlm!uL=KhEq{CHqcuh>rcnahf?&9#N52Su>laEk6<9B<=m7LaAJKs5n z&b5k==wU~=)YfmB#qPY;F8s`7`;fDZ;`rUc?+t$@luKxM0AfMO&6kKQ0suhH_8{&( zO{u(~0Tp*~_QuG+3vRCIHy&r)dFqz$U++>VHQf|4FB}Dks$R$}|G|#`_L$uf|83`6 zHL+yJeNZX{Sp{rkC)^K8V?!nGrSxaICm_z zorKLsHp7hyc?qKBpyUE#buM}Ki-KA-e&eJwn5?@%Rk>Ncr)`H@OY zt?b0~5_sHSU3T&{23`68ZoRFHS`PdZY#fF^^_W5aoD$`l!+Bsaw{LVjz2qTu@ihCm z8(o!0OwpNHihte)AGtO@=bkbw@n3YCHNDOMxt!AL^6k`ul;BV2Yq`mm`MEueM~k|1 z%Sb@#`C`e!Pgv9y`T9kmMHg0#5Z7t$J%xLo6QCBW(~IMRDKvfOO6 z*x{wSwA^ykd4Q5E>HCXwgC8luZA%SwxagZMtEPkV(4NXgj5J&ZfF<%dD~uH2Ki9w~4$R=^=%iPmWNy9aZlq&>FaNs-X$K~>$XZ)zsZWP{83r;$8*((7>~ zWxy5q;JZ^2P@sS+jpn>Kgq}rS*k2IrqSn83l)i5|;M1B;2NaZ-c6;ilA&;rdA*yZ- zS@&K4L`eTyW&t3&=RDTDg;?4S%(6)9rN6%N4kG-cfB16Kq12ZZ|7HIzyG2KRvORB5 zct4;NBN`1AEk=-j1piPa%*j z{x)RR-qMA;Gl={_EaH{E}V+X5+W>YJ_GW5Vtn%2wD1%Gj} zF_!h{pXe!;A0;E3N6WW!1p;4e2i9&|k~Otc7G%cPPZOV;AEohdaov%{t`joq7!2v;`mU|D^>CXsK&e!8-Q+bPM z+Ru(6oJJPg(5pc(cT>X?spJwjMZP|pOE_koXfH(1j=NyC!`B(Jnscnmy|P8L3^nI} zaSq(w`+$lQN|N=zOfr-5K}hGQ6<#o_LY~Z$MWz+irdJTRzYZWv5qB(VKU`%dq6?l1 z`;0bY3>z*vxys$r$I`Gq{el=w(&tQCYqW!nx~g({1O&}+NNLQkl(naQ_P$Xbjd(2! z_7oZQC*F0@_WwO@w^pH^gR*VCOCQOyo41N_bD*p>T}96671w=VB$(eT$EorX1@+W1si zAo8L-T4I&`)KI8SzBp{g=9Ec~@dd*f|Gatra9^r2OY-@5Z+j<}Fr0Q_m#nS;+?9N{zf`rWdsf`B12 zTg5H0^7WxZKoXq$Q!w+}b-BAuBvkw9ajk9+wopXnCdLhWK(g~W6$EU%PMuU5KcGyL zI+v@1aJQ%NJe0d70SYDNVFWWA^M&O~69(!yw*_28ie^=sc~<3I-Il)QiSyWC9gIq_ zLiQ@1>RNu8vt^9_$Y1*4T4EkMbz5h0ZvnW39nq`%3Xhw@W@*5-mgkKdXousgYfEhp z`}^jZyhS^DSWbYvG-C1>M~)(42W9lr&wYQ1G2(F1!ML7f35y897vh?N$FwclV5p?0 z#AILlcwbm5v(E8yZomQEqdGbKmWEc$vPbF;Jgk-ILa%i9T<1fR(q_cdAZJZ@1ctp} zWOVgJT&Jy)E#9}F7Ef`Xg~^l+?0-ye*nX|KJ=n|i#yud=KYclT3A5lKCRJV$bx<*|Fa0U4u*8ao-)^=QQ!cY&sj@U;qP z%sXf^@ooB?txAY;Ue%!CBnsGIxqx{R!7Bjma;+=H;bs&$03vcx<89XHa2^RR}Fp=z*JQ6gzqzTyT zmKB@6LchBI`nBn8HR7`6Nx`i)ux9j)VEAmekKPMyf}ZbCY>)`hn{(tY*gDRNwsN4 zJf^udi?JBAP6$I_KKl>b9faf$k9pAK+m)O*Y#f{JA{%){2{@7gZhoE#RjN(nGIFug=A7f%FS%xPpdhd+A_KZEwA^M*&159FfAQn*O_by za*6Y15rux}gRT?OWBnFP+t9And?OV5&ezG55nm}V;+CQ5O$(ZrV={P(D1LkJ__EGy z&d)m8w7_K?b9|B#A1go8?M9hEL({%;(@RFKFLb&<2|F_BjO@>G;QP4TH*~=5peg`x z=f1{;lrk-ot1B|g47(l*IQ?nqSy|w0yUoZG#F&S&+noRv<^Qt7Knj~oZr=jVy(F8i zX+{Os@bxk+kj%Kmp4yiYNO3p2TpTNUuj{Vr!TUqL%zNs}{ScUKUfhI_kWUQSorKip zm9uRDSr|0f3oPw%9qo2IcbW4SN9`tJAV_-oKi%_t_a4gOe4`2zVxtWz>!JF`?$q44 zTT#Bo38MTZy}V{#XkOB85RZ)BocBhBh~3*jP(xFU#> zmOk$|m&nYXILwv1w>u~VRxZv~v3@8~+O3TU#{`f+*JRt&jhg)8@pf%{_5R$u*3GQ9 z-V?W70cpG10~&a0(mLtB3$zB_O;NS{Wuq)QZIZzU-jKBTG4%@*0c}2B+-`fCd%Xq5 zL&=SYKn~JE&eXl&<0FZ!yqF)}UK%75m9G@VS6`0>xX`csd^o|jz)w4v3w9BeLmup$ zmEEYQi#u<8V@C3cOzsI+3w)z_5L|08YZAVHUwD4hO$hmU;bxC}VQwE*PN6d6tXCl1 zFs~hDJneq(cPWqkOCH9T?A;2V#lN}}it%rj@SD>qZB4~!i)N%xJKKExy|94lu=aAX zdSa73?OjB+Q4;X4X;a0n&ivM|9bI{o7{2)EQU_Tv^2a}a@Oiv(Rx*8j?+J)KgF=(N zO+cq4e*Nv*{wYfIX@4lGVFu0ncb5OSaE-mD56RATPsds36B)pN&tvaQk)>gnLG~nx zn^vC&r~h@7G^yfemzhd_bBYHK?lqJB0}H|#EhZr#=N)FMRwt`gODg*()NcP1SBHPu zmZmpY`%Tmb(zjo?P!k(jpYwK#|51Rg71auqa981SFa6Zkd~VM1j-!n7HR(WCS)%C;7={fhkM9R1wU zmco6y_}&7P6-w;{DQ>Cpp4oFrAN@H+a_qBwYg{))lL{Y4`J>-4`+#Xa^as02hN_WD zG(;&&DRb1vJ3FlvdjvUj37C{^)@FWBd>#pT=HEX?1?Z9Ii|BcV@Ee+3kR)K8<*4fl zsx$8EzXgk;F3W##j*`A@`po%wOwY@+V1i?_OFZ&L;%|cyBcA8+QM`q?Zbd#mF`!Hb zR8KsFz?wLLRjc59Q}`pNS5eO>ySGt!DG9aG=7jG;lk;Op;%x03QW+zTQfVblDYgA3KaEMW5jMPF)2{oS94&7ZSFN4V?p=J^%IW?VL3Rd*>=_ z)w`~DkrBg?7i{9@{`OIUCL*&O1C_20IsB~(yiah4VQIOs(<`5z{A-CfCb0e^)aOB_ ziaNrvhu%VnH8(~&F58keH;|X|K7k(lVRw8or*#s)gr25FYx%Oe#z*fT50*t&J|5_i zrL*sH4KGIe3|u{+PHrDuEG6~&+Ou($m(&e&6*sgg3bls+DwZN%k9PnDN4F>NMqT65 zu=3GtGn=eG9k22UQ(pYP#Zny9RH7_&?`%kr=jEdORx}PD9kf|n5M08~OHUl5XCRqWI`pnLK*^weDe|AT+;8vh+O3Q*ZHv#GoEXDJj<` zoqr-p0r=q)P8w4T<*M*s9B7cHv1jI3WQ@qou(RH%zJSxZW^%XEOpkLj@63Z|w)Qy9 ztQ2QlQ`t72x|r<`E1NBmkiZ9ITc3&safT)I2%5c;#dWLk1KD?Ur*m~mbo;N^F@a#3 z418lAb(La~9FgN$+m@$#wjQr9%oHjfY?M?A7bzk8kJH>n)@#-0l{oLkX8e=mUx7w+ zbRHCc`e@`+Y_KTiJN+`F-%D3#8Gk4om2R&~Af5PfA0ps$NRm2?hO zuphzhe((bLrs9hT!D)X`#Vh47-C`o$WjoRU(7J<-KB?B`M{udrzq(R+NrQbA?9RGU z1@RFC32{33NjvlwAEKUfQm5aGTh#D+#h1J0{BM1n&h#fzt-T@zf#+h-5!M{N(NA0o zwah2FQjO7|Ygpa7;Xg0!b=d;6_y_QXkMml>YDgv?lzKFus})^%(52DR5^M@|8+&Tn zU466Zq@)=u*Pl8P8Nlh5m=Q@N$zN~ix^KI)q@g!l5@fByK)0*-O2K0Ol=0=Vr|&Ak zSr|t=gUlI~)2K8NbJ(Zv{jbC7a(~hti6eTR2)_==(L|Lm{rJED!K{4raO7z3y+^Em zJKF@Mr?Ot*9t4#M>0+zX7raN$Yc-}~L zCMVHv+S5YI@q(M(k0X5siH1qOKPsQ11s3{Ru{oI4>b!us)P1Am9 z<;(60J)q-=GJHHvyDA_*_fyG!C(rj_bvoPTFAnLz^pmGiRIDb17=y^9pYyB?{({&~ zI;`?uYab(8FxoRSZOVIjHdKPiYJS)6Z!CWbdfBY|Fw=`FWtM;zo(zX$DBbNo22M|V zm#1%)bHxY$gZF*UAYF`KOWH;F)7XOoclQ|rwfmgYF1g<2Qp>{quk}Y(9d@QYp6e`# zlk@BL6A%hU=YZc;O!pk&4tm!7JJ?KC$|fe(t`x1aK!W?*_WMtcv1&g}gDQb~NYCT) z1w7GbUXCW^>yBjjVx)qJq`W9?41&m2nSwYePxSGaKx6QW5}Nljk+!3sii=vx&E1Aa z*f!(kA+MyPls)9ig*PR>nI1jJjG)6%bUt0EpbB#6=y*ny=bi(!CD&HV>&8Qag5gA$ zYt~hq9VPS7s@?tL`P6*1=AxGF2oF&Bn6jr9Ofup1Y`jg^7C1svR)Bpfj+LI~{=wVI z%8jO-Ga^?c`K8BTK-f4I8qI#wM5V^`XZ58pa_l-i9GW~GPvg5*lK3i(4KL*VAPw7E z`K8f9JdL#bghfxhJ?{DYGaWnedA-oAg}il$;!9rqXx>>j!N~Y%+8ab3iV(_m_$E0? zuv>bDGU}LN&d#`Fl9PAF~o zM0A{w&;MS`0Bt!fqL0+I%Sry#sYcuZWeqQ3pld}@h40RRtg(WgXBK%>&c_nL>T1SDB|Au40GXixPuOMf&O-Gh(;ppRVV6NkZwO7SfSb9qISLbnRY<3ggININc$b z@2w6NBKDMQ)L|#%ak9Z9Yo*cpuOBoGn}#CF@hos8ouu%(|A~`9)jj2Vy^$~J%kz=# z+XEKq%FjP`6(Ao*168l!90%E!gUBbAS&eV=?vn)VOPyJ+H{Sb~rx?LT$&B5XeT`jt z>aStit@uhlmi@C9-=Urw9g*)S=Gkg+Tm3^Rko~7=(5#E#hd-^Q!yX3>FH!QB=Ugkx z2G2;rmN69%o*DZ5`@H@_e%R^Jsx?8SFYE83p)WLeY#b9Wz9}qXp0Tozy~={OTVZSk zu_z@d`{N%O+ZG7?{CMWFdgFbtwA+x=3rRgXK_1D@e08zbXDD*>Ms+?PHt@1qIKIkg z*MG~|`*+LPuU+?wDg|m!ahEfRHQQ;}*=M4v6Fl`2Rv*_`$c{HW-niDIhHT^u>~!A- z9=^t6T6Lzs>J3|ter_0P+}ESF5bqJhE|vJXIzH~Nv-$YzpsdGs%x@L6Eed*-_7jlznPb?jIvHH zeoBs|VujmZRP5O%0mtwfqM{o#1Gto?1~@v75wi#5n0&(H_z^Ei8a9o->vKO9F&StSTR_$y^gRRtQWOggM>eT zYaR)7iFd+0vws_gD0gF=Xxg^Ug%ZyCg=b7e3>RGg{8@Za64`OdF_7C@)wwRHeg^Kv z-D)Hqh$bs)tbnr~+j`kp!(BU|`H;+neDhf0~ML5RT?Te=uLxaIazLnsjKgW$e z*!ok9PBcJK#?_oHCGnOkisHDgD~jT{-rP~cW1FQow}GI{d=s1e6mBtDq=7NElGy)9|wR@(!BT81;IqF8|s8qbg1f38|rCw zDE|PBYSy3|eM};_WFDmR9RC2dX&HCaz-Cd=^(UO?T0ob5a1He>XEJF( zS^dWMJ;`}{WLad@GSpO83Yujt-8Pw1`;&dLe{zJe^=eEvWgJPl=k1j@B)*!urj}Kx z&F+4crddY$o?^jd_O!{~o`JrnFj;-QXS=0pFzxB6H`5(co>>;7r?Rl$Oy3PPUwE!C zQ!(SwFLE;;s~Dyc-UKjAvVW7@{W7f6m#oyc8JCdW9B>0M=}j;A{lC>Uim|)9!xc$9pH-_Wt=lw(iq@Nsa>kTev>wwfFmf+jnV~rvPs4+~$){ zx%y{WW*KG|W-HTv0XFWnb9Bs_ZXNwMW-HTubo;x@FwH8>F0X6$U6`+h@8*f!>lE_; z0Iq&tP1%ZT(;zo|B$tP``>yO$9qT;DD$6E`KUCMBieq^;k==95LT_k&$>uq)d57JD zMLz1-f3kjG?oLb9hc9x=E~&b&9-I&a)HdoeOj=~`o^IJuo`3$ebNh$wS$)6p$$4bQ z1#Q$By1G83W}BL93oyGv)S3j#Fj<9IsBV1CH!Q0$<>;3KWY{4IijO48w?^wMzv`3q zV6WwaGRk@7-5kg5!P@~9a|HXM1G;P-`)_bgMNSn3E;mIixIBi_= z%3CKQ{hIX{V6jk9+&sp?g3UTpLrSW}kt>xP;QXS@TqStaF@ z_fq&!HgKiSF}-?arO#FYDEMu>Ip)(Ub34^Zaly9YPMIn_Ei!ou%z6_|rgfCy zk7(2hhBz_EsFlW511g3rW=3Pt^9ah7GIsNhZIY4gO|$kK7FzTf7aW15$e zY|{2jnr#!}quL*GY6~Z@h)xP)sYEB2RG4eyztV$?#Ygc?!de+UMw?Wr)F#7T?A0eUoA4YBG*rZh#hIoE|6x#h0F zfJ56I6lR#lnHyaCp{?5@kVMH3S1|s z;eRZ=-FP5H=o<=6#ex!wtWz7)9$U6y_aH}(5`LuKK?!?`1GN*~rhuMXj5dR1@(*N5wEv=Bo1)(gf!)Q8}mvah^q++eCFEDe1qk z^ID1oL~J`1>9b&-bM~kUo_T)ikX#c?GS!7gzA@#S2bO=fiCeWFl0P&Z31#UKSNgx)gK1jqn~&VmsX0DAQ-p?@5o?wgu! z#OD4{9$OATKv4bF%=eNg2A4$O-kG_uVeWt2AF5in$z~XhT=2zLkfM2%(F(dMsfztbu-K@W z;Hjdi#=nz14hY2hwX&VOgzQfV0zG>Xgo8>Xf;z`Mh0*TF6fQ?)eO!cOF^NXm!b8|m zgsCW&K91+HBMEgO4mK`6IR4nLGR%acc8x)JVRIhPyt9mGjmQSKcfITPx*ice7Zbk#PRYr6U3nBq07h~x(s0o)OY^(E+K3gNZ1qP@5#QyLbJymXHGTcX5e_pF-FDA zF^S$c^0DFU2b8^ld_`rpGh8FRGl~BIO(xa&iNx$E-m>$v^~bl8ls*}Ks7!VqM8MP# zvf4fI?w!AdWsqVq9SXw%Q_~{-y_k*Ta*fzlG7dDt{Be5dlm~)c==%B=HX-7fWgAeW zVgMelS2TP>>(c8ju~hP`l_*mjbr@9cPdW|Bfabkoi#%}Kt(5Wx)yha#GTI82o580X ze(}nAw+HK8sp=aes>YzB#Bjmv`_aV5tbB>a9EHhmkRMVpl%M{3D)yTrtJx1(y{ zX-AyONcz={xdYR1U$<0H5Qlu!z2ag1xM*1xMdMDF>Kl!=thNi`=$7n8*I zplJI-^KEyn{hb6M4-rD#c68U58d{BKEyH)>C_*#^iWU zyNZIpyWzXP6nY2DpYZC{IA zwo9G80hUAbVOgK$^{k?Rb3EdNsEl8ipJ`nP0%3k4xM zm=Xi@s|u5VLPjFoPTAx9Dev5rx`hJ$D{+11r|V71x-z~y@g3O=Uv`f+07g3ui#l@* z!{siR(Dm~_F3e2kb^z-&$wJfYH9u07i{2>h7#_VrYQ#+Db_M2LX>k%2JBPy*=b2_I zw9v&iyNq>*F)-g$3UL2B4}NU#V_Ku+<-N9>O=Y!Hbr5*!s!$~G^9mLY_Kdt}e4nM(A- z8EhQKBmtC;092uKj6O}jgm{nTUSACX5%r$aqH~3_lK@R97wS$h`qzHEXPoUz29IvXsO`0Od4#FbWX1 z#&85lzNqsYunu<$r;W1_zEn@eT_kRWKDGY<9@vTBx7*ILmEBJwyQ5P)aoRZt7#%^` z%!ctzRv4_u6VV1Ts3?fmI|{*gSA?$cBe#=bip)os9rF8=-X`Jp1TDY_#8HL|G_A$Y zQvREE61%2R^{>*qPOzT+!ba$ZPi_Fqd8telc|t}pAoQiEe6D?U<|f6vVn6^%Cwi@* z{i`e**gLUR*LCK?)Qk=VWxE+f^@dc`^6f;(4jx#O zunpxrF2+Z347}br43O}}-Opdjm?oGK9cj(54)H|fNczk{%)JSp?(de0zU|c~(VDWh03_B^fU5Rtp5gF-$5><(~fl zv+qqB1jRAtfb@GJ`w@T)4Ir3FyR@*Ir|kf0UfA$el4qFz!lzyu~p;Ro&+9T$8~x^(@Zhm7jU@N17_9b!(y#Z zJ11;w(v#t2X)g48cKRUrOM1(54d_bQsM)<`kYYA!(u#%0T5E$T`jd)|P;NBnmet2a zaaF@uTaG0QHoavq=Y}T&85kdQw@KO~Y@5*>vJMt#)<0scC9s8-;OsjNzmqHu9lW3; zVLuCr@qJ|oZbj3xH;pPlYnsqH=~XhqITWaJu;*cNLQ5Vw_-k<47v^puFxDvD+Qp zi*}%x#1}$w!a?v`=hjD%(VNmgHX?(-r?h|nP@ z;=A-It%oZ#s!C|>PIYD3%v^F_y%{CpJo_{Wgu1ZyDMI8$*>zF1PY*0bW2se;7bQ_K zs7^7`4&tAGKv7pq4PE;5=vGD^>8R}J@yA~c5&bxwzdz;XZ|=r}lb2^K;Z;>orr*ds ziy{WmM9IPjoSi09EfI-E7JIPYwCH8Iccop!L~dJ=jG|l+h3NXm@-p>ut*K29 zs`4zF*!8EGb&}_(sT*bDOXwY(4G`rtgWcJ^Gt*GW2aLQ?P6k-+_XkJz$p>8kZ6Y}o11x8z^>_3s_z4)z7vYg z918DkPH;_c+MY%AfgI%NG7}XqP`mT?1Z~(Z)G|&>o?zSg+mynCrp57$D0>e*jhiDh z5K{OB~VHysISwzA=({xuNLYH$h71;l6IbJ-WA@QccZ*&utIkZI|68i=2Zb; z$;5~&%aP33Dyo`lV10^_C)B&JKD5*xv~FIQF(I;!a&(#8A~6_}jjInEdrs5$4rC8I z9XMeu2xTi$#wEGrxXF0#6A{%B`Hv#=gimM-xe*@0&sk=-Np9FyS%x|*NDNBJ7=V~_ zW=>?PN~@LOREYK}4t(bTvfBMg^nNb<#uG7+!n8f1WVjn~*mb+2o6ZS|&pxa=Aav}l9ipAP5rnBImLso0 zu`hQH#r@5p_=odziOyl6IXrz>pGh7`wE1^K#d(l9t^H%SPjFLy#oql%{XsD;9m5WZ z8tk0%73lBoxN!3xDDNMc05L*i5P`%HvqSoF!>g;BvKP3wg`9Hx()_VPF%1wH0qG4F zc~erF3?)!#QMGQP5!jw*Jhu!MQAq9_yKPQ!=d@MS%z9(Zx7@kBV0%}Wa4|;7*-(ro z92Jn(Cj-p=`JSpFa#k}o1>BEn^K45re#5x*W89F4>r5sA>!RxE92H8#kn2?nQkMKV ziyTO&LAOlhxEvvJ1>v~kpxd9fayIT`u}vx_jpOeKPBjELJrMFN6Gy&!lSjBZ zu}>oBL)wu8b|cuEh>4F_sQcHO!pvNQvyF#w-O-d?FlPG9uv5uZegT3q(R0c$Dv+i4$_z$$Eh{2A~)hw-H|=2rmBjXC>9GfgOHqC zZ))#KKf)9sBOmO*k+~xtuIPdIvvgBpw;ou7fub-w2^!ex!ER3)rq!>6;+$cq;|_0B z(ew_KxI8EJBMF9_OAv7!&N4pqiRcHpAs*72Ii`AoYZk!kk^7c0k6>N+&f%YDY-W54tHqmLELE5t9llCv^$$w5>#r-*Z7xd-q zU(=VdR@}Xbr9;=K_!P%gjbgJzxYTinC*{l+UMB5b*@Np;BTW@*o>WW=o~7LmRcM&{ z2romsdLf^9_+*SO29U&Z{{XK72gS47qC7pC&Si(~KBXHl@W22)T=mTYU~`?pWw-ic zs}-76JI^WJ(^XYeFIeu*CBYcFh4}`a5*=e6i=t^Nb3C_VBs$h^9Ju&T>?_)(prXL3|BmMyq$=WlXCBdo8}dxxk~+Pjeu9@4*3MqI+0 zjiTg60#EH78`PY0Ot&Hr+Ot@B$9B>8rrI_7lZ;bb_NN+YifM9QZw!39o4wQbEWAW= z_3ZZP!7wyftW|UgM-aQgI1T6_gupR73eCe89|`@1WSB9Q;+%9Qd$JIY`4%5q?$0^- zL#E-NA~(vVH0}^SS|^oHUYcvSEa=Mc%PGm&;s(z_JjQE)Hj!PuK zlup8p`v)i(#Qy*;it+$Qa&hP@TmY}rksU^>0DBcd8u%1j=w_nl*v?xgMpHJgrPt zHy~P3JICC-zCKZv=oS-=GY@t|Y?sBT;a6P9c%?wHp8o)9d!~Z`FytxF@6gyR0>CN- zhcwN0LIbR(wD%8CVeKib!Z00mEA_5QU0Xei1x`l1-z+5Y*d{ux9!Vi!QmF-ga9`?@K)q3ld>S)*9}iIZ|UZkLYzsl`Vk z)@71=58krzB<776@>J3-3X{-n)0w73M)I=2o3h;uKZ!M=rWi8~o!=k+C z2cr;nge^*5Rl`P|0qm9?68zD{3TXt`x^aO|v~o;q4c~Ij6626EGyGzM-twmi{ z7?tKsJ=tyD&^1|OQmczr{X4O+xIGIuSK7U5AnQVaw%>{ zAHn%~<#|@-jBr`4oTutfHY0dPlg%79jp^Y@ZriRcjAmQatzB%f4o(4QyW{&h0;z&? z-3plR=~p-`w=TrXbbH7BtMn~SeP_Cw-MBz{$zAKDbw-Q7BQDbYBTWMADJawsgrwed zDKXdae)mrvvJvGoM6nx|Tj9p=vs)mIQr;L)e%&s447SH<*cW!QIF$VP%FApgxP3u) zLv*HV(~JkqKwZfjhja(+D9473ZAW<-kL6joo0GVA6Hnn3UC`W{bK0im#}jI?!cpEf zg&X!u!ePPYPINfvkPpNcbu@z>S2PI+cujB#kF7L`iR(`i^Od?GWr%K*&BWb|I*G6F;Rrhb?!aaG{7W>6lkGK6qM97& zZiaqg$t3_T>^fW`Br1S1auN3m{%dKU#7VJ+l$<0omGB_N0 z_m><>`Hnp+RqN0dbTV|Da?{wLTs42x`y%?RSgNV>h?R?Q0W4zHl$r&E1 zCba+)1osOB*5jH=y}+Jb}->AbCnq$g_`D5yeaUApbrBzoQg_S2DyR-I$#%rLbAP!xQ3ogx^ z=$@CaIDJ>tblm{Swy1-P53{DsO+m#!4LW=!ex2&IewHa3pG}L8XEuy+9 zs@&4-jw}b(pKqhtWE?EetbVvb4PJHi+37m4{~z5yjb-gc3i6;MOfgRcu%18vB5F)A-NaPM9G3=+8uQ&;iIWlGND!I z8gfNJ{nBIXJd-B$VYa3?jb|Q)*F&8SQ)~%>s-j_vV6mz(IE3kjy?LvSNwoxE9#Sj^ zT7`^EMNe7BlFjJW87|WsmjY769mC!IvqIBWK#+%*HWp~c?xS&R=mbs zOvCwfk7@Loq#P%=-W#^2J3SC>EE8?fnBtr#DbQ3!(*)%=F5K$q+n9Zxly`-9r;m7j zeuKWF1zi+QpF^Dva0#~{cdn!WLqlk77131sjH{^H9aTR#yFG?Ldk3XYgtvv>6yMYI z)_o7I+8Hv+G&xPMX)mbU&9y1Y(^d~jP3C=n>FHUHCwHJtt6eO43h1r~oerHc3Yr^c ziYlsd52)PU-wr+b0DC>}sR+ja7Ff$2c;72^bWeu%v(ckPIS>Q zRZgmyD)Yg_@nV?9AI&eyvfYR~h@lDic?k{1g*Ha*AwLr~8>5f43sxc{5&ref^%+;0FioPm zjit4EwH-FQ>HR1fFVrFf+MeUwJ$Nj(;vzbSrU$psV01Si+^sZIQi;Zj>OQM-d2PhV z^(Vg}5x7*R5zKeWsf9f=J-&g{OAQaDwAYx?KAyD04rfH|k~_+Ko%wa(njity>9Otf zCG^!cqjI&>WXDn4OMvtK)PflT8ZB*8xWO{;ogj*ico>8F zDdPqk%@f|a>Wc7YJLOc-01mE%>hyEf=ruKJnK0yNtFGE8tFGj-%K&6|1mp{G`M%`$ zq-K4AHK>S=q0sJd^mHFdUPYE$K+ao$bPiEs8{}*JBB}VP%JjEj6IpKze8^7ML} zJtC=PlGrkl*bp(dMHW}UR9`> z%IxKQhb1TaB^QEA8mYs(MSB82T?#u}{OwWeq2u3_kZqLxa-D8;e|ikYM#xg=J=)FKG}3-RXr`O z4)vCP-k)w-s}+}rw=0L`4xa8?BjzrDhA18?QoMI~N7eb3UK-qOj-g*~M>)sS46+Ur z;|=@00DV`P04Le2{{SA$j8D9KquV8$jl3iB!l(G8ffmKd4YTim+Oog^HvrusnEGVJ zXS3@GusgbOmRO82UFsC?q0^#o7v0pdV-)r+%1^iz-VwDO@-_Y#pm?jYncW`f{LAz$ zL>=Tg_RFN(Vqxi{ic5OSciNmP^p(ysV8~k!lx;f#8EjiHC4_3__GUroTSw~MgnenE zWpnVyLyS|M7_3%a7S!&35aZi|d&V{g%v}Ef3={EJXLRn1M1L_)X2b-B(j5N)xiG_} zSSB8uWsq>3ccJx!;-NfMdP3(6ahyvYzjy0V;<(n8==Y)q5kD7dHn=b@Oi;++{ae%V z7i31^K&l+?Q~|VAHq`t*nPoooyQAAACC6XOzBa@E0KQ+90~;c89`(-g{{VFsSO5Un zFzJRKooBT}yJ1;PCAn2~bafQ0SpNW##72Zf_hNo&{{Spejp^lq_hUi+zr2Avbsvbi zZrkh+BljobE?l~IK2iSP%)jGVgh<-Xe~MM<#vYy56w>zSc=Tkrjv_)9pd6B=!tf7g zhQP}S%zq?R6QF$nuc!3rvww)3ZQG7AkzkFl@lbF-^2~qH56pq%Zpz>o13)_>DWQU@ zA4n{EAXyRfc&UesHUaTmE6(F)WZoExM1C0RIlyQiNGw)aW6=Cf;#>*j9g!Jz$I=rV zb`_F%^eLRkH>3!+4W#e`%Visu^C+RP~ zE5B-cXE5AxO>!hE9&H{b)oxk^#_+g;Hbf7vM8NmRkJ7bQdLdEAt#@Qq2rCCwiB$)f z7@f3SLE(f+B*sEQggq6m67|b`KMEr$N-&Rld416-d`jim8rmXWt*QA@^r27|3WSA8 zDiwmkU{(tab2g>eiGIZ%BZiTM+j0_#6k-+5CfM&>vmq$%m>uu0>8AyP!C|7$8v*?} zWS3#^{cEVJpW|-rF3=vj<|#D*bX{{RPg{;iT_W=D7aBm9z5wRR>qAWUQqAdX{118(1I`0?yLb6#%eN7D#y<_d==S)R>BIxSZlmCLj8<$U zFqCLe;lIfqsNMYk0GSCyxHSZQ1u*nJbC}J*T?fpIK0v|3TXt=9*NKeTmozm^|rgf;@_ z)%1HVABc##YGI`lfeXpDb8y#2YeeGPV=u$V(_PN6yJ)n6%qcPA8@b7r-H6Iqnw4_# z*+I$?^kQWqz*Lf<9u(%W!-Eka?-Sx9<<}g*UbW&MSlor%ezCM2+}+9%9ssh19rCXz z`~HkP&NASM*#TJ}!xU^=dmJag4Q2lT$uH$p*Br;p#@VFDR{qe0;9ev+Bb#L#Q92+x zhbT-uQK&=;6ZIfXWf~u%zNI_kiGhW=7?v(vZXWVBf5k(}hyLX2FWrxZDBiz0T)8Tl zNVz#C+WgeUFo`Y1o+uL+X?Gu()H z#GiEg$j^tDopHOd0D%7hGM5*`%QeaUL*b9htLEO5^)D{pb_;%}=5f6mfkHQgCj#Jy z2bw%_OmRb%kocG*9;7aeV~Pd)lE>(tTtyA(_iaS&mj3|53`&*TgvxUy$ec+luaz9o z@YC&&?Htv{D=fwuTatt~mrSR_oF!0=i=Gl$e{FXhVt0@9)yoW1O*r}PW1+MW2$^?7GXCb_X%NheVsprDO>Q{?d($OTQehni(Z>+7O+PZB zR4Sp@dMg&~UD6L{&`wQ|w-Nh!8YhsU=f{VU?#`pPn;zXYS#9^{)rYk-j#%y#PSw|a z;3J?&Y*~iX#|;$IT}txL62&#n`1;py*Kx<_ABeax&SE`X-bXanSPBk(8?nYE)NV%! z2j-`>FkWTi-?e2O%YO*{x>zdfMt-E)a-2qqDSE`sOiR> z-s#6$yuA}oLq2HkUBg|+AD}Pp__<`Z2oBFuu5i2vl&)MEa}dA-j19)MhY{2bpGwdCHO8jqB1fxhzT75*m*p z%k-lCWmZf&lgPPEsNp!$Cmcd?iXZ@Dnqb7Ifdq2`4vMV7I(Z?(-7XJ={{S!010Ab~ z;TfVP@%%FHM_Hg*W|4Aw5Jckw+{dX$g|%NSyolfM@*UF2q!Zve(_5+Do<+`_(!mp} z)Vhjo4iP&vJV^IUlx<5B7F4adg`#M_bU z9q9C2?R-J`hHHdIJIXvi1wnzI<^0^1`6}V1lgl1KwsHWRHmWM~KDCrfFdHRRmxzOP zimd!Cz$8EQP^*upmfefaj2v;hNYz;nbsgz-UZhFx3(X#s^Jx-%U9T(ZwgiP`$K@_U-iQTtvJ= zksIW2QoVbg(pY zh8&cR=>F9s)K$a2NRhB8%2gzKJi{Jr=VFz}{{T#PA=p0j>Zr*ZcJV7M(7@n!bWA1J z$@zmApQ}XdNY-J;sayjG=R)nG(hIw6Mte@hnnlUxte=s&F2JUGikbPpVwYi29bS(f zZ6N~JF82qo#q}pXtqd_MwO7PyQMGh9D|`+T&>f!WCpbsJ+0PhxIQHp$mT&Kl)oD#xhwm3bJQ9~3H|q>Rok!BJOT z)v@x0CfYz>yi_B+^uW)Fq+%*b`9e4U0LVyMvMZ7Q0R58pzYJIQ-{S|BY*5Lne-FZp z?viA7nxmC8@m^;Gb%xkVu|K+nt|WOJM&scpFq?dL#kjX6xG0*pP=SoU<2b@D8u9l$7!^9UXC zm)fBn)#-C*g#vd6h@T998U8?tC(q+0i90|3IDCokOS`fo0GzC$W;m4RLr5kX#(O zwm(Z4z?fRwJ*TQ4nSW>gHG@#dZ0z~IWtv2iYUe`)>9kco)mnrv@N+PqRs?R4_mJVZ zrnALt9_+sX_`Xh&F$cYH#$>A}6~V1)Fft$<|}4>Gc@UZ77JJ(6-_O`Mr9P z?dMSIrzRn9`m)2Qd`QY=C*)JRWV0l3Oo<_Lz>Z~E}UcX-QORd z_>+o*(e}7ugae;i$}ozR$M4ROPN#FNl`%~9On^1f4D^zkRyH*}t8(4bD;M=7CFo<;Q-3>0j;XDs`Iox4uJ5DCPRty&d%2kAx_FE@yg zgnIU<3o#-PdYnt9)?=a5lQHKw?c4qinsqLnM7(FZXK4x1B!a8E*qzp>pK_ z4^@&M(vBTx;^|if^f^r$mEJnevuuP(_R&LxkK&i|qcemeeWslx$mPXkjl9y{a9(E- zBO|+D?BwaC_AaoG2gD!wR!8wiWWNyi`Zndw(J9U{E>!QI6Eu5Kk;JIm7(1TC!3#sQ zs7GXb$JD5sOXzJbrFtLMpK>0*5%mP;6RRHHbW}QnYqiqn;o7{h-M6@H?dfNUWYVg~ zR=SsXnNS)(W-52iGBoViuG~FAJVOqWVTzotha@oVDfQUuwujLUGlea31;_1)>XMHa zW{*inY-Bu9JlTgfFxxo*qik+b;b3VB%e3edxIb3qdjc{(7>6oTJ4%)FjOaTCl1_%z z5evwH?pPUpe)hC^+isE8Hw9*C5!Q{%hcu;$Ju^);qG;6W#?^@rGJVoEiud$NM{K^t z(G4Bvq?jRUC%X@|GOBQ~)~2H>CrnqEfBM%cbPxXkXKWCh4rs^%2*88Q7;}3zy3CZW z9}FVuS7nTeP_}#{yn6zaz0pDHQuwY>0koD;v^E5ERZ%(AqCRw<=mdy>_1NlHCE}4J z`t_sR&hA5TePM58N88h5H3Dc>SReA&F;uVb(U4V4{B>yBO|yTdz2=R^(BIH zieaILAx%cm>9IrnPZE2we&Q^qkimi&QC$2U4zhD zeVoWzvc~-IeS_lssNB6HIh;u^q((&Dv+&Ci_+-4>1^11h{M_QYP03&pxj+34N@!xK zuKFmbn?`83kgJV{ddqpgxwOJ#e(RsT%vf`qr(iAYR_qSbqSdXld7oNygleaAc~ZQ4 zG&bZTvmF&#g3OysggDp+xf)NbZ`O}*I|Jg0({fU)79D{`Fg@r7BX)`PH`(YT3YBir z#xW1u%w=|Tj6;<^Cgw6U>Kg{AyWc#sn<9Sj!>r zL{R#+CbbDmwu`xLAa#sqshAGN@Ty?3+S49(OrjPBfm%nIY zedzpOo1!nk`?8nXr!ScOs_pIV5P~~}6h~Sl>60DW z(LXTfVq1tP9pD`XV;g5T-{?8ur%4Af>l;Tb=LGjIM0Gt;x50xE@tl8jB27ueo>)%V zF_6HD5Qh)Pnwm!E=lsdXB>EdgQzr_zYO<Y@9@gtSKI~Yz$}KE7YWV$^`62Mvp`Q+KD*oI(vq@g8eAhd0qJsI;a!Kzixr& zM9LdLD9XTZsTfWqnFfrX0;Ou@B@)^l1J*g&QN4CTFcAcjn}@b!H_D$Nqv^&f9OBU zshVU6j7h;|H=_MjS?o?Tj__Yg1ysQ~(N&vftEwvUH7cBwCz<~Mk8y;??bknd-uYH& z)EtcA)quTY;bzMrQ$rmswhy(2&5XPiDpa#nDsYMiLGP zMX(1zwQi*SKqeI@6QUecMSL>;T_E$aghgc-i4Rwx)zpQ;S|sH?hmmtYjh+Yz%wsd* z9iI|6Z%E2VY38mdM$m-i{Ydv^+BW+12N~~A!4Kw_%Dm1lMDB>BM`UykCx$H{h}j|V z$wP^?;h1*Zc7)|Ru7(P_GVSNT{{UNjyrLe_J4eC$zVFM>*Cihvk}eNdi~XxI96j^g z*iOVuc8Vzuv=C%E^q1R2>&lB|KyM)k3;+QRHfC|yYo{z~O#t4b!kkEXADGmvyR|8zsfN3A zDyP&J>TJuqawBN?zZ6iM2r-awM$mc|98^O>{9L!i8Xu`uS5e}+^oa~p=(TsLy@++G z4fXb@aM1USPT(se>{(zb5C9!R1+eil6dSuyAWG%KQoxh-EyqPU?LH!eq(GEp3_;ty zy$YN_CK8QE6a--U_j6Fb-ObKviiD&Hk%(|ryOAR~4Jdwxd~=~kpQ2HF?>rbLd1JkG4_SC+N$2w zBI7aZRBaoRNsuldv@An*uJr(sZm@&mqi{%Oz=sd)SFVB$=?syG@d1qH-wN|>1AB>? zXhtFO{L*A?aaUo(lUdI6gjjY-vrFYu{{RpF0QqqlN+5aMR?@QSO3}MRo@Q) literal 0 HcmV?d00001 diff --git a/assets/background-creative-island.webp b/assets/background-creative-island.webp deleted file mode 100644 index d53d9bb0625dbe2bcc34f062257880362056ebe1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23244 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 P|4P5~WWPbL^jrV{6BJ$R diff --git a/assets/background-dark-s1.jpg b/assets/background-dark-s1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58d78ddae59b6cf7f93981377b279857cef1f1d3 GIT binary patch literal 41227 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 y9kX~Nb=*2g%(wG@K>nYvcc*LciD7$!k^k1& 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%0ADzrS?bS6PeO6o8;$d+H0^-tf+1jHKr! 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