diff --git a/apps/flutter/account/.flutter-plugins b/apps/flutter/account/.flutter-plugins new file mode 100644 index 000000000..59e378d87 --- /dev/null +++ b/apps/flutter/account/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider-2.0.15\\ +path_provider_android=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_android-2.0.27\\ +path_provider_foundation=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_foundation-2.2.3\\ +path_provider_linux=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_linux-2.1.11\\ +path_provider_windows=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_windows-2.1.7\\ diff --git a/apps/flutter/account/.flutter-plugins-dependencies b/apps/flutter/account/.flutter-plugins-dependencies new file mode 100644 index 000000000..25b653eb3 --- /dev/null +++ b/apps/flutter/account/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_android-2.0.27\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.1.11\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.1.7\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-07-14 11:41:46.248683","version":"3.10.5"} \ No newline at end of file diff --git a/apps/flutter/account/.gitignore b/apps/flutter/account/.gitignore new file mode 100644 index 000000000..96486fd93 --- /dev/null +++ b/apps/flutter/account/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/apps/flutter/account/.metadata b/apps/flutter/account/.metadata new file mode 100644 index 000000000..9596faeed --- /dev/null +++ b/apps/flutter/account/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: package diff --git a/apps/flutter/account/CHANGELOG.md b/apps/flutter/account/CHANGELOG.md new file mode 100644 index 000000000..41cc7d819 --- /dev/null +++ b/apps/flutter/account/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/apps/flutter/account/LICENSE b/apps/flutter/account/LICENSE new file mode 100644 index 000000000..ba75c69f7 --- /dev/null +++ b/apps/flutter/account/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/apps/flutter/account/README.md b/apps/flutter/account/README.md new file mode 100644 index 000000000..02fe8ecab --- /dev/null +++ b/apps/flutter/account/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/apps/flutter/account/analysis_options.yaml b/apps/flutter/account/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/apps/flutter/account/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/apps/flutter/account/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/apps/flutter/account/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 000000000..7eb0d9f93 --- /dev/null +++ b/apps/flutter/account/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,25 @@ +package io.flutter.plugins; + +import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugins.pathprovider.PathProviderPlugin; + +/** + * Generated file. Do not edit. + */ +public final class GeneratedPluginRegistrant { + public static void registerWith(PluginRegistry registry) { + if (alreadyRegisteredWith(registry)) { + return; + } + PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); + } + + private static boolean alreadyRegisteredWith(PluginRegistry registry) { + final String key = GeneratedPluginRegistrant.class.getCanonicalName(); + if (registry.hasPlugin(key)) { + return true; + } + registry.registrarFor(key); + return false; + } +} diff --git a/apps/flutter/account/android/local.properties b/apps/flutter/account/android/local.properties new file mode 100644 index 000000000..1a3be4ff1 --- /dev/null +++ b/apps/flutter/account/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=C:\\Users\\eddlevol\\AppData\\Local\\Android\\sdk +flutter.sdk=D:\\Sdk\\Flutter \ No newline at end of file diff --git a/apps/flutter/account/ios/Flutter/Generated.xcconfig b/apps/flutter/account/ios/Flutter/Generated.xcconfig new file mode 100644 index 000000000..a909d18f8 --- /dev/null +++ b/apps/flutter/account/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\account +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/account/ios/Flutter/flutter_export_environment.sh b/apps/flutter/account/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 000000000..9f0a6f7a6 --- /dev/null +++ b/apps/flutter/account/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\account" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/account/ios/Runner/GeneratedPluginRegistrant.h b/apps/flutter/account/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 000000000..7a8909271 --- /dev/null +++ b/apps/flutter/account/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/apps/flutter/account/ios/Runner/GeneratedPluginRegistrant.m b/apps/flutter/account/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 000000000..c0d0cbad8 --- /dev/null +++ b/apps/flutter/account/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,21 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import path_provider_foundation; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; +} + +@end diff --git a/apps/flutter/account/lib/account.module.dart b/apps/flutter/account/lib/account.module.dart new file mode 100644 index 000000000..77d2e1a42 --- /dev/null +++ b/apps/flutter/account/lib/account.module.dart @@ -0,0 +1,15 @@ +import 'package:account/pages/route.account.dart'; +import 'package:core/modularity/module.dart'; +import 'package:get/get.dart'; + +class AccountModule extends Module { + @override + void configureServices() { + inject(this); + } + + @override + List get routes => [ + ...AccountRoute.routes, + ]; +} diff --git a/apps/flutter/account/lib/index.dart b/apps/flutter/account/lib/index.dart new file mode 100644 index 000000000..999852c0c --- /dev/null +++ b/apps/flutter/account/lib/index.dart @@ -0,0 +1,3 @@ +export './interceptors/index.dart'; +export './services/index.dart'; +export 'account.module.dart'; \ No newline at end of file diff --git a/apps/flutter/account/lib/interceptors/index.dart b/apps/flutter/account/lib/interceptors/index.dart new file mode 100644 index 000000000..4e4f85873 --- /dev/null +++ b/apps/flutter/account/lib/interceptors/index.dart @@ -0,0 +1 @@ +export 'oauth.api.interceptor.dart'; \ No newline at end of file diff --git a/apps/flutter/account/lib/interceptors/oauth.api.interceptor.dart b/apps/flutter/account/lib/interceptors/oauth.api.interceptor.dart new file mode 100644 index 000000000..ed7cecf07 --- /dev/null +++ b/apps/flutter/account/lib/interceptors/oauth.api.interceptor.dart @@ -0,0 +1,72 @@ + +import 'package:core/models/oauth.dart'; +import 'package:core/services/auth.service.dart'; +import 'package:core/services/rest.service.dart'; +import 'package:core/services/session.service.dart'; +import 'package:core/tokens/http.token.dart'; +import 'package:core/utils/string.extensions.dart'; +import 'package:dio/dio.dart'; + +class OAuthApiInterceptor extends Interceptor { + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { + if (!options.extra.containsKey(HttpTokens.ignoreToken)) { + var token = SessionService.to.token; + if (token != null && token.accessToken.isNullOrWhiteSpace() == false) { + var accessToken = token.accessToken; + var scheme = token.tokenType ?? 'Bearer'; + options.headers['Authorization'] = '$scheme $accessToken'; + } + } + return handler.next(options); + } + + @override + void onError(DioException err, ErrorInterceptorHandler handler) { + // 需要处理401错误 + if (err.response?.statusCode == 401) { + var token = SessionService.to.token; + if (token == null || token.refreshToken.isNullOrWhiteSpace() == true) + { + return handler.next(err); + } + var authService = AuthService.to; + authService.refreshToken(RefreshTokenParams(token.refreshToken!)) + .then((value) { + SessionService.to.refreshToken(value); + //err.requestOptions + RestService.to.request( + err.requestOptions.path, + data: err.requestOptions.data, + queryParameters: err.requestOptions.queryParameters, + cancelToken: err.requestOptions.cancelToken, + onSendProgress: err.requestOptions.onSendProgress, + onReceiveProgress: err.requestOptions.onReceiveProgress, + options: Options( + method: err.requestOptions.method, + sendTimeout: err.requestOptions.sendTimeout, + receiveTimeout: err.requestOptions.receiveTimeout, + extra: err.requestOptions.extra, + headers: err.requestOptions.headers, + responseType: err.requestOptions.responseType, + contentType: err.requestOptions.contentType, + validateStatus: err.requestOptions.validateStatus, + receiveDataWhenStatusError: err.requestOptions.receiveDataWhenStatusError, + followRedirects: err.requestOptions.followRedirects, + maxRedirects: err.requestOptions.maxRedirects, + persistentConnection: err.requestOptions.persistentConnection, + requestEncoder: err.requestOptions.requestEncoder, + responseDecoder: err.requestOptions.responseDecoder, + listFormat: err.requestOptions.listFormat, + ) + ).then((value) { + return handler.resolve(value); + }).catchError((_) { + handler.next(err); + }); + }); + } else { + return handler.next(err); + } + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/models/auth.dart b/apps/flutter/account/lib/models/auth.dart new file mode 100644 index 000000000..6ee9126f9 --- /dev/null +++ b/apps/flutter/account/lib/models/auth.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'auth.g.dart'; + +@JsonSerializable() +class PortalLoginProvider { + PortalLoginProvider({ + required this.id, + required this.name, + this.logo, + }); + @JsonKey(name: 'Id') + String id; + @JsonKey(name: 'Name') + String name; + @JsonKey(name: 'Logo') + String? logo; + + factory PortalLoginProvider.fromJson(Map json) => _$PortalLoginProviderFromJson(json); + Map toJson() => _$PortalLoginProviderToJson(this); +} diff --git a/apps/flutter/account/lib/models/auth.g.dart b/apps/flutter/account/lib/models/auth.g.dart new file mode 100644 index 000000000..1e7e256f2 --- /dev/null +++ b/apps/flutter/account/lib/models/auth.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PortalLoginProvider _$PortalLoginProviderFromJson(Map json) => + PortalLoginProvider( + id: json['Id'] as String, + name: json['Name'] as String, + logo: json['Logo'] as String?, + ); + +Map _$PortalLoginProviderToJson( + PortalLoginProvider instance) => + { + 'Id': instance.id, + 'Name': instance.name, + 'Logo': instance.logo, + }; diff --git a/apps/flutter/account/lib/models/common.dart b/apps/flutter/account/lib/models/common.dart new file mode 100644 index 000000000..ff3196de8 --- /dev/null +++ b/apps/flutter/account/lib/models/common.dart @@ -0,0 +1,6 @@ +import 'auth.dart'; + +class PortalLoginException implements Exception { + PortalLoginException(this.providers); + List providers; +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/index.dart b/apps/flutter/account/lib/pages/index.dart new file mode 100644 index 000000000..ecc0e4988 --- /dev/null +++ b/apps/flutter/account/lib/pages/index.dart @@ -0,0 +1,2 @@ +export './login/index.dart'; +export './user-info/index.dart'; \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/binding.dart b/apps/flutter/account/lib/pages/login/binding.dart new file mode 100644 index 000000000..88906db4e --- /dev/null +++ b/apps/flutter/account/lib/pages/login/binding.dart @@ -0,0 +1,9 @@ +import 'package:account/pages/login/controller.dart'; +import 'package:get/get.dart'; + +class LoginBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => LoginController()); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/controller.dart b/apps/flutter/account/lib/pages/login/controller.dart new file mode 100644 index 000000000..9f7f7d638 --- /dev/null +++ b/apps/flutter/account/lib/pages/login/controller.dart @@ -0,0 +1,66 @@ +import 'package:account/models/auth.dart'; +import 'package:account/models/common.dart'; +import 'package:account/pages/login/widget/portal_form.dart'; +import 'package:core/index.dart'; +import 'package:get/get.dart'; +import 'state.dart'; + +class LoginController extends GetxController { + AuthService get authService => Get.find(); + SessionService get sessionService => Get.find(); + + final Rx _state = Rx(LoginState( + loading: false, + showPassword: false, + portalProviders: [], + )); + LoginState get state => _state.value; + + void changePwdVisiable() { + _state.update((val) { + val?.showPassword = !val.showPassword; + }); + } + + Future login() async { + await portalLogin(null); + } + + void showPortalLoginDialog() { + Get.defaultDialog( + title: 'Lable:LoginToPortal'.tr, + content: Obx(() => PortalForm( + portalProviders: state.portalProviders, + onSelected: portalLogin, + ), + ), + barrierDismissible: false, + ); + } + + Future portalLogin(PortalLoginProvider? provider) async { + _state.update((val) { + val?.loading = true; + }); + try { + var token = await authService.portal(PortalLoginParams( + enterpriseId: provider?.id, + username: state.username.text, + password: state.password.text)); + sessionService.refreshToken(token); + state.username.clear(); + state.password.clear(); + Get.back(closeOverlays: true); + } on PortalLoginException catch (error) { + _state.update((val) { + val!.portalProviders = error.providers; + }); + showPortalLoginDialog(); + } + finally { + _state.update((val) { + val?.loading = false; + }); + } + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/index.dart b/apps/flutter/account/lib/pages/login/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/account/lib/pages/login/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/state.dart b/apps/flutter/account/lib/pages/login/state.dart new file mode 100644 index 000000000..a5c2eca07 --- /dev/null +++ b/apps/flutter/account/lib/pages/login/state.dart @@ -0,0 +1,16 @@ +import 'package:account/models/auth.dart'; +import 'package:flutter/material.dart'; + +class LoginState { + LoginState({ + required this.loading, + required this.showPassword, + required this.portalProviders, + }); + bool showPassword; + bool loading; + List portalProviders; + + late TextEditingController username = TextEditingController(); + late TextEditingController password = TextEditingController(); +} diff --git a/apps/flutter/account/lib/pages/login/view.dart b/apps/flutter/account/lib/pages/login/view.dart new file mode 100644 index 000000000..dd082d6a7 --- /dev/null +++ b/apps/flutter/account/lib/pages/login/view.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'controller.dart'; +import './widget/index.dart'; + +class LoginPage extends GetView { + const LoginPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: ListView( + children: [ + const Logo(), + Obx(() => LoginForm( + state: controller.state, + onSubmit: controller.login, + onPwdVisiable: controller.changePwdVisiable, + )), + const SizedBox(height: 10), + Obx(() => LoginExternal( + state: controller.state, + )), + ], + )), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/widget/index.dart b/apps/flutter/account/lib/pages/login/widget/index.dart new file mode 100644 index 000000000..75c42facc --- /dev/null +++ b/apps/flutter/account/lib/pages/login/widget/index.dart @@ -0,0 +1,3 @@ +export './logo.dart'; +export './login_form.dart'; +export './login_external.dart'; \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/widget/login_external.dart b/apps/flutter/account/lib/pages/login/widget/login_external.dart new file mode 100644 index 000000000..7b8e10581 --- /dev/null +++ b/apps/flutter/account/lib/pages/login/widget/login_external.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; + +import '../state.dart'; + +class LoginExternal extends StatelessWidget { + const LoginExternal({ + super.key, + required this.state, + }); + + final LoginState state; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + IconButton( + onPressed: () { + + }, + iconSize: 28.0, + color: Colors.green, + icon: const Icon(Icons.wechat), + ), + IconButton( + onPressed: () { + + }, + iconSize: 28.0, + color: Colors.teal, + icon: const Icon(Icons.phone_iphone) + ), + ], + ); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/widget/login_form.dart b/apps/flutter/account/lib/pages/login/widget/login_form.dart new file mode 100644 index 000000000..cb420c2e4 --- /dev/null +++ b/apps/flutter/account/lib/pages/login/widget/login_form.dart @@ -0,0 +1,173 @@ +import 'package:core/utils/string.extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../state.dart'; + +class LoginForm extends StatelessWidget { + LoginForm({ + super.key, + required this.state, + required this.onSubmit, + this.onPwdVisiable, + }); + + final LoginState state; + final Future Function() onSubmit; + final VoidCallback? onPwdVisiable; + + final GlobalKey formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 30), + Padding( + padding: const EdgeInsets.only(left: 25), + child: Column( + children: [ + Text( + 'Label:LoginTitle'.tr, + textAlign: TextAlign.left, + style: const TextStyle( + fontSize: 32.0, + fontWeight: FontWeight.w400, + letterSpacing: 0.0, + ) + ), + Text( + 'Label:LoginSubTitle'.tr, + textAlign: TextAlign.left, + style: const TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w400, + letterSpacing: 0.32, + ) + ), + ], + )), + const SizedBox(height: 30), + Padding( + padding: const EdgeInsets.all(15), + child: Column( + children: [ + Form( + key: formKey, + child: Column( + children: [ + SizedBox( + height: 40, + child: TextFormField( + textAlignVertical: TextAlignVertical.bottom, + controller: state.username, + decoration: InputDecoration( + hintText: 'Label:UserNameRequired'.tr, + prefixIcon: const Icon(Icons.person), + filled: true, + ), + validator: (value) { + if (value.isNullOrWhiteSpace()) { + return 'Label:UserNameRequired'.tr; + } + return null; + }, + ), + ), + const SizedBox(height: 20), + SizedBox( + height: 40, + child: TextFormField( + textAlignVertical: TextAlignVertical.bottom, + controller: state.password, + decoration: InputDecoration( + hintText: 'Label:PasswordRequired'.tr, + prefixIcon: const Icon(Icons.lock), + suffixIcon: IconButton( + onPressed: onPwdVisiable, + icon: Icon(state.showPassword ? Icons.visibility_off : Icons.visibility, + color: state.showPassword ? Theme.of(context).indicatorColor : Theme.of(context).disabledColor,), + ), + filled: true, + ), + obscureText: !state.showPassword, + validator: (value) { + if (value.isNullOrWhiteSpace()) { + return 'Label:PasswordRequired'.tr; + } + return null; + }, + ), + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton( + onPressed: () { + + }, + child: Text('Label:NoAccount'.tr) + ), + TextButton( + onPressed: () { + + }, + child: Text('Label:ForgotPassword'.tr) + ), + ], + ), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.only(left: 8, right: 8, top: 6), + child: SizedBox( + height: 40, + child: Row( + children: [ + Expanded( + child: _loginButton(state.loading), + ) + ], + ), + ) + ), + ], + ), + ) + ], + ), + ), + ] + ); + } + + Widget _loginButton(bool isLoading) { + return IgnorePointer( + ignoring: isLoading, + child: FilledButton( + onPressed: () { + if (formKey.currentState?.validate() == true) { + onSubmit().then((value) { + formKey.currentState?.reset(); + }); + } + }, + style: ButtonStyle( + shape: MaterialStatePropertyAll( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + //shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + child: Text( + 'Label:Login'.tr, + style: const TextStyle( + letterSpacing: 4, + ), + ) + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/widget/logo.dart b/apps/flutter/account/lib/pages/login/widget/logo.dart new file mode 100644 index 000000000..4659ac05c --- /dev/null +++ b/apps/flutter/account/lib/pages/login/widget/logo.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +class Logo extends StatelessWidget { + const Logo({super.key}); + @override + Widget build(BuildContext context) { + return Container( + height: 100, + padding: const EdgeInsets.all(8), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/login/widget/portal_form.dart b/apps/flutter/account/lib/pages/login/widget/portal_form.dart new file mode 100644 index 000000000..c2de0bfe9 --- /dev/null +++ b/apps/flutter/account/lib/pages/login/widget/portal_form.dart @@ -0,0 +1,42 @@ +import 'package:account/models/auth.dart'; +import 'package:flutter/material.dart'; + +class PortalForm extends StatelessWidget { + const PortalForm({ + super.key, + required this.portalProviders, + this.onSelected, + }); + + final List portalProviders; + final void Function(PortalLoginProvider provider)? onSelected; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 200, + child: ListView( + children: _buildLoginProviders(), + ), + ); + } + + List _buildLoginProviders() { + List providers = []; + + for (var provider in portalProviders) { + providers.add(Card( + child: ListTile( + title: Text(provider.name), + leading: const FlutterLogo(), + onTap: () { + onSelected?.call(provider); + }, + ), + ), + ); + } + + return providers; + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/route.account.dart b/apps/flutter/account/lib/pages/route.account.dart new file mode 100644 index 000000000..23ada49e8 --- /dev/null +++ b/apps/flutter/account/lib/pages/route.account.dart @@ -0,0 +1,21 @@ +import 'package:get/get.dart'; +import 'package:core/middlewares/index.dart'; + +import 'index.dart'; +import 'route.name.dart'; + +class AccountRoute { + static List routes = [ + GetPage( + name: AccountRoutes.login, + page: () => const LoginPage(), + binding: LoginBinding(), + ), + GetPage( + name: AccountRoutes.profile, + page: () => const UserInfoPage(), + binding: UserInfoBinding(), + middlewares: [AuthorizationMiddleware(AccountRoutes.login)] + ), + ]; +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/route.name.dart b/apps/flutter/account/lib/pages/route.name.dart new file mode 100644 index 000000000..7662167b4 --- /dev/null +++ b/apps/flutter/account/lib/pages/route.name.dart @@ -0,0 +1,4 @@ +class AccountRoutes { + static String login = '/account/login'; + static String profile = '/account/profile'; +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/user-info/binding.dart b/apps/flutter/account/lib/pages/user-info/binding.dart new file mode 100644 index 000000000..9f6252905 --- /dev/null +++ b/apps/flutter/account/lib/pages/user-info/binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import 'controller.dart'; + +class UserInfoBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => UserInfoController()); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/user-info/controller.dart b/apps/flutter/account/lib/pages/user-info/controller.dart new file mode 100644 index 000000000..b0459ffc7 --- /dev/null +++ b/apps/flutter/account/lib/pages/user-info/controller.dart @@ -0,0 +1,20 @@ +import 'package:core/models/auth.dart'; +import 'package:core/services/index.dart'; +import 'package:get/get.dart'; +import 'state.dart'; + +class UserInfoController extends GetxController { + SessionService get sessionService => Get.find(); + + final Rx _state = Rx(UserInfoState()); + UserInfoState get state => _state.value; + Token? get token => sessionService.token; + + @override + void onInit() { + super.onInit(); + _state.update((val) { + val!.profile = sessionService.profile; + }); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/user-info/index.dart b/apps/flutter/account/lib/pages/user-info/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/account/lib/pages/user-info/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/user-info/state.dart b/apps/flutter/account/lib/pages/user-info/state.dart new file mode 100644 index 000000000..a664a24c9 --- /dev/null +++ b/apps/flutter/account/lib/pages/user-info/state.dart @@ -0,0 +1,8 @@ +import 'package:core/models/auth.dart'; + +class UserInfoState { + UserInfoState({ + this.profile, + }); + UserProfile? profile; +} \ No newline at end of file diff --git a/apps/flutter/account/lib/pages/user-info/view.dart b/apps/flutter/account/lib/pages/user-info/view.dart new file mode 100644 index 000000000..04056a9d9 --- /dev/null +++ b/apps/flutter/account/lib/pages/user-info/view.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:components/index.dart'; +import 'package:get/get.dart'; +import 'controller.dart'; + +class UserInfoPage extends GetView { + const UserInfoPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Page:UserProfile'.tr), + ), + body: Container( + padding: const EdgeInsets.only(top: 12), + child: Column( + children: [ + /// 主题设置 + _actionButton( + title: 'Avatar'.tr, + suffix: Obx(() => Avatar( + url: controller.state.profile?.avatarUrl, + hintText: controller.state.profile?.userName, + takeToken: controller.token?.accessToken, + )), + ), + /// 账号设置 + _actionButton( + title: 'DisplayName:UserName'.tr, + suffix: Obx(() => Text(controller.state.profile?.userName ?? '')), + ), + _actionButton( + title: 'DisplayName:Email'.tr, + suffix: Obx(() => Text(controller.state.profile?.email ?? '')), + ), + _actionButton( + title: 'DisplayName:PhoneNumber'.tr, + suffix: Obx(() => Text(controller.state.profile?.phoneNumber ?? '')), + ), + ], + ), + ), + ); + } + + Widget _actionButton( + { + required String title, + Widget? suffix, + VoidCallback? onTap, + } + ) { + return Container( + height: 50, + alignment: Alignment.center, + child: ActionButton( + title: title, + onTap: onTap, + suffix: suffix, + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/services/auth.service.oauth.dart b/apps/flutter/account/lib/services/auth.service.oauth.dart new file mode 100644 index 000000000..2f59ef4dd --- /dev/null +++ b/apps/flutter/account/lib/services/auth.service.oauth.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; + +import 'package:account/models/auth.dart'; +import 'package:account/models/common.dart'; +import 'package:core/models/auth.dart'; +import 'package:core/models/oauth.dart'; +import 'package:core/services/index.dart'; +import 'package:core/tokens/http.token.dart'; +import 'package:dio/dio.dart'; + +class OAuthService extends AuthService { + OAuthService({ + required this.clientId, + this.clientSecret, + }); + RestService get _restService => find(); + + final String clientId; + final String? clientSecret; + + @override + Future password(LoginParams params) { + var request = PasswordTokenRequest( + clientId: clientId, + clientSecret: clientSecret, + userName: params.username, + password: params.password); + return _restService.post('/connect/token', + data: request.toFormUrlencodedData(), + options: Options( + extra: { + HttpTokens.ignoreToken: true, + }, + contentType: 'application/x-www-form-urlencoded', + )).then((res) => Token.fromJson(res.data)); + } + + @override + Future portal(PortalLoginParams params) { + var request = PortalTokenRequest( + clientId: clientId, + clientSecret: clientSecret, + userName: params.username, + password: params.password, + enterpriseId: params.enterpriseId); + return _restService.post('/connect/token', + data: request.toFormUrlencodedData(), + options: Options( + extra: { + HttpTokens.ignoreToken: true, + HttpTokens.ignoreError: true, + }, + contentType: 'application/x-www-form-urlencoded', + )).then((res) => Token.fromJson(res.data)) + .catchError((error) { + var portalProviders = (jsonDecode(error.response.data["Enterprises"]) as List) + .map((e) => PortalLoginProvider.fromJson(e)).toList(); + throw PortalLoginException(portalProviders); + }, test:(error) { + var err = error as dynamic; + if (err?.response?.statusCode == 400 && err?.response?.data != null && + err?.response?.data["Enterprises"] != null) { + return true; + } + return false; + }); + } + + @override + Future phoneNumber(SmsLoginParams params) { + var request = PhoneNumberTokenRequest( + clientId: clientId, + clientSecret: clientSecret, + phoneNumber: params.phonenumber, + code: params.code); + return _restService.post('/connect/token', + data: request.toFormUrlencodedData(), + options: Options( + extra: { + HttpTokens.ignoreToken: true, + }, + contentType: 'application/x-www-form-urlencoded', + )).then((res) => Token.fromJson(res.data)); + } + + @override + Future refreshToken(RefreshTokenParams params) { + var request = RefreshTokenRequest( + clientId: clientId, + clientSecret: clientSecret, + refreshToken: params.refreshToken, + ); + return _restService.post('/connect/token', + data: request.toFormUrlencodedData(), + options: Options( + contentType: 'application/x-www-form-urlencoded', + )).then((res) => Token.fromJson(res.data)); + } + + @override + Future getProfile() { + return _restService.get('/connect/userinfo') + .then((res) => UserProfile.fromJson(res.data)); + } +} \ No newline at end of file diff --git a/apps/flutter/account/lib/services/index.dart b/apps/flutter/account/lib/services/index.dart new file mode 100644 index 000000000..5459885df --- /dev/null +++ b/apps/flutter/account/lib/services/index.dart @@ -0,0 +1 @@ +export 'auth.service.oauth.dart'; \ No newline at end of file diff --git a/apps/flutter/account/linux/flutter/generated_plugin_registrant.cc b/apps/flutter/account/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/apps/flutter/account/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/apps/flutter/account/linux/flutter/generated_plugin_registrant.h b/apps/flutter/account/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/apps/flutter/account/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/account/linux/flutter/generated_plugins.cmake b/apps/flutter/account/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2e1de87a7 --- /dev/null +++ b/apps/flutter/account/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/account/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/apps/flutter/account/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 000000000..8d838a86b --- /dev/null +++ b/apps/flutter/account/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\account +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/account/macos/Flutter/ephemeral/flutter_export_environment.sh b/apps/flutter/account/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100644 index 000000000..7e5adc2ba --- /dev/null +++ b/apps/flutter/account/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\account" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/account/pubspec.yaml b/apps/flutter/account/pubspec.yaml new file mode 100644 index 000000000..41cefda11 --- /dev/null +++ b/apps/flutter/account/pubspec.yaml @@ -0,0 +1,65 @@ +name: account +description: A new Flutter package project. +version: 0.0.1 +homepage: +publish_to: none + +environment: + sdk: '>=3.0.5 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + core: + path: '../core' + components: + path: '../components' + dio: + get: + json_annotation: ^4.8.1 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + + build_runner: ^2.4.5 + json_serializable: ^6.7.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/apps/flutter/account/windows/flutter/generated_plugin_registrant.cc b/apps/flutter/account/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/apps/flutter/account/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/apps/flutter/account/windows/flutter/generated_plugin_registrant.h b/apps/flutter/account/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/apps/flutter/account/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/account/windows/flutter/generated_plugins.cmake b/apps/flutter/account/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..b93c4c30c --- /dev/null +++ b/apps/flutter/account/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/components/.flutter-plugins b/apps/flutter/components/.flutter-plugins new file mode 100644 index 000000000..59e378d87 --- /dev/null +++ b/apps/flutter/components/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider-2.0.15\\ +path_provider_android=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_android-2.0.27\\ +path_provider_foundation=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_foundation-2.2.3\\ +path_provider_linux=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_linux-2.1.11\\ +path_provider_windows=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_windows-2.1.7\\ diff --git a/apps/flutter/components/.flutter-plugins-dependencies b/apps/flutter/components/.flutter-plugins-dependencies new file mode 100644 index 000000000..419cef769 --- /dev/null +++ b/apps/flutter/components/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_android-2.0.27\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.1.11\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.1.7\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-07-16 10:47:15.025132","version":"3.10.5"} \ No newline at end of file diff --git a/apps/flutter/components/.gitignore b/apps/flutter/components/.gitignore new file mode 100644 index 000000000..96486fd93 --- /dev/null +++ b/apps/flutter/components/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/apps/flutter/components/.metadata b/apps/flutter/components/.metadata new file mode 100644 index 000000000..9596faeed --- /dev/null +++ b/apps/flutter/components/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: package diff --git a/apps/flutter/components/CHANGELOG.md b/apps/flutter/components/CHANGELOG.md new file mode 100644 index 000000000..41cc7d819 --- /dev/null +++ b/apps/flutter/components/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/apps/flutter/components/LICENSE b/apps/flutter/components/LICENSE new file mode 100644 index 000000000..ba75c69f7 --- /dev/null +++ b/apps/flutter/components/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/apps/flutter/components/README.md b/apps/flutter/components/README.md new file mode 100644 index 000000000..02fe8ecab --- /dev/null +++ b/apps/flutter/components/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/apps/flutter/components/analysis_options.yaml b/apps/flutter/components/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/apps/flutter/components/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/apps/flutter/components/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/apps/flutter/components/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 000000000..7eb0d9f93 --- /dev/null +++ b/apps/flutter/components/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,25 @@ +package io.flutter.plugins; + +import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugins.pathprovider.PathProviderPlugin; + +/** + * Generated file. Do not edit. + */ +public final class GeneratedPluginRegistrant { + public static void registerWith(PluginRegistry registry) { + if (alreadyRegisteredWith(registry)) { + return; + } + PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); + } + + private static boolean alreadyRegisteredWith(PluginRegistry registry) { + final String key = GeneratedPluginRegistrant.class.getCanonicalName(); + if (registry.hasPlugin(key)) { + return true; + } + registry.registrarFor(key); + return false; + } +} diff --git a/apps/flutter/components/android/local.properties b/apps/flutter/components/android/local.properties new file mode 100644 index 000000000..1a3be4ff1 --- /dev/null +++ b/apps/flutter/components/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=C:\\Users\\eddlevol\\AppData\\Local\\Android\\sdk +flutter.sdk=D:\\Sdk\\Flutter \ No newline at end of file diff --git a/apps/flutter/components/ios/Flutter/Generated.xcconfig b/apps/flutter/components/ios/Flutter/Generated.xcconfig new file mode 100644 index 000000000..d710d87bf --- /dev/null +++ b/apps/flutter/components/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\components +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/components/ios/Flutter/flutter_export_environment.sh b/apps/flutter/components/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 000000000..288025f9b --- /dev/null +++ b/apps/flutter/components/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\components" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/components/ios/Runner/GeneratedPluginRegistrant.h b/apps/flutter/components/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 000000000..7a8909271 --- /dev/null +++ b/apps/flutter/components/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/apps/flutter/components/ios/Runner/GeneratedPluginRegistrant.m b/apps/flutter/components/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 000000000..c0d0cbad8 --- /dev/null +++ b/apps/flutter/components/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,21 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import path_provider_foundation; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; +} + +@end diff --git a/apps/flutter/components/lib/config/avatar.config.dart b/apps/flutter/components/lib/config/avatar.config.dart new file mode 100644 index 000000000..9f90a963e --- /dev/null +++ b/apps/flutter/components/lib/config/avatar.config.dart @@ -0,0 +1,3 @@ +class AvatarConfig { + static String baseUrl = 'http://127.0.0.1:8080/blob/avatars'; +} \ No newline at end of file diff --git a/apps/flutter/components/lib/config/index.dart b/apps/flutter/components/lib/config/index.dart new file mode 100644 index 000000000..606c6f290 --- /dev/null +++ b/apps/flutter/components/lib/config/index.dart @@ -0,0 +1 @@ +export 'avatar.config.dart'; \ No newline at end of file diff --git a/apps/flutter/components/lib/index.dart b/apps/flutter/components/lib/index.dart new file mode 100644 index 000000000..e6349e001 --- /dev/null +++ b/apps/flutter/components/lib/index.dart @@ -0,0 +1,3 @@ +export './config/index.dart'; +export './pages/index.dart'; +export './widgets/index.dart'; \ No newline at end of file diff --git a/apps/flutter/components/lib/pages/index.dart b/apps/flutter/components/lib/pages/index.dart new file mode 100644 index 000000000..0137a90d1 --- /dev/null +++ b/apps/flutter/components/lib/pages/index.dart @@ -0,0 +1 @@ +export 'page.base.dart'; \ No newline at end of file diff --git a/apps/flutter/components/lib/pages/page.base.dart b/apps/flutter/components/lib/pages/page.base.dart new file mode 100644 index 000000000..73f702f8a --- /dev/null +++ b/apps/flutter/components/lib/pages/page.base.dart @@ -0,0 +1,9 @@ +import 'package:core/dependency/index.dart'; +import 'package:get/get.dart'; +import 'package:flutter/material.dart'; + +abstract class BasePage extends GetView { + const BasePage({Key? key}) : super(key: key); + + Bloc get bloc => Injector.instance.get(tag: tag); +} \ No newline at end of file diff --git a/apps/flutter/components/lib/widgets/action-button/index.dart b/apps/flutter/components/lib/widgets/action-button/index.dart new file mode 100644 index 000000000..9327d4c83 --- /dev/null +++ b/apps/flutter/components/lib/widgets/action-button/index.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import '../empty/index.dart'; + +class ActionButton extends StatelessWidget { + const ActionButton({ + super.key, + required this.title, + this.prefixIcon, + this.prefixIconColor, + this.splashColor, + this.onTap, + this.suffix, + this.suffixIcon, + this.suffixIconColor, + this.hideBorder = false, + }); + + final String title; + final VoidCallback? onTap; + final Color? splashColor; + final IconData? prefixIcon; + final Color? prefixIconColor; + final Widget? suffix; + final IconData? suffixIcon; + final Color? suffixIconColor; + final bool? hideBorder; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + splashColor: splashColor, + child: Container( + decoration: BoxDecoration( + border: hideBorder != true ? const Border( + bottom: BorderSide( + width: 0.2, + style: BorderStyle.solid, + ), + // top: BorderSide( + // width: 0.2, + // style: BorderStyle.solid, + // ), + ) : null, + ), + child: Stack( + children: [ + prefixIcon != null ? + Positioned( + left: 10, + top: 12, + width: 20, + height: 25, + child: Center( + child: Icon(prefixIcon, + size: 25, + color: prefixIconColor + ), + ), + ) : const Empty( + height: 50, + ), + Positioned( + left: prefixIcon != null ? 50 : 16, + height: 50, + child: Center( + child: Text( + title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + suffix == null ? const Empty() : + Positioned( + height: 50, + right: 36, + child: Center( + child: suffix!, + ), + ), + Positioned( + height: 50, + right: 10, + child: Center( + child: Icon( + suffixIcon ?? Icons.arrow_forward_ios, + size: 16, + color: suffixIconColor, + ), + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/components/lib/widgets/avatar/index.dart b/apps/flutter/components/lib/widgets/avatar/index.dart new file mode 100644 index 000000000..3d01c6c95 --- /dev/null +++ b/apps/flutter/components/lib/widgets/avatar/index.dart @@ -0,0 +1,48 @@ +import 'package:core/utils/string.extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:components/config/avatar.config.dart'; + +class Avatar extends StatelessWidget { + const Avatar({ + super.key, + this.url, + this.schema, + this.hintText, + this.takeToken, + }); + + final String? url; + final String? hintText; + final String? schema; + final String? takeToken; + + String get avatarUrl { + var formatUrl = url ?? ''; + if (!formatUrl.isNullOrWhiteSpace()) { + var urlSchema = schema ?? AvatarConfig.baseUrl; + if (!formatUrl.startsWith(urlSchema)) { + formatUrl = "$urlSchema$formatUrl"; + } + } + if (!takeToken.isNullOrWhiteSpace()) { + formatUrl += "?access_token=$takeToken"; + } + return formatUrl; + } + + @override + Widget build(BuildContext context) { + return CircleAvatar( + child: !url.isNullOrWhiteSpace() + ? CircleAvatar( + backgroundImage: NetworkImage(avatarUrl), + ) + : Text(!hintText.isNullOrWhiteSpace() && hintText!.length > 3 ? hintText!.substring(0, 3) : hintText ?? 'A', + style: const TextStyle( + //fontSize: 20, + color: Colors.white, + ), + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/components/lib/widgets/bottom-button/index.dart b/apps/flutter/components/lib/widgets/bottom-button/index.dart new file mode 100644 index 000000000..599da333d --- /dev/null +++ b/apps/flutter/components/lib/widgets/bottom-button/index.dart @@ -0,0 +1,72 @@ +import 'package:core/utils/theme.utils.dart'; +import 'package:flutter/material.dart'; + +class BottomButton extends StatelessWidget { + const BottomButton({ + super.key, + this.padding, + required this.title, + this.titleStyle, + required this.onPressed, + this.enable = true, + }); + + final String title; + final TextStyle? titleStyle; + final VoidCallback onPressed; + final EdgeInsetsGeometry? padding; + final bool enable; + + final EdgeInsetsGeometry _defaultPadding = const EdgeInsets.only(left: 0, right: 0); + + @override + Widget build(BuildContext context) { + return Padding( + padding: padding ?? _defaultPadding, + child: Row( + children: [ + _buildMainButtonPane(context), + ], + ), + ); + } + + Widget _buildMainButtonPane(BuildContext context) { + return Expanded( + child: GestureDetector( + onTap: () { + if (enable == true) { + onPressed(); + } + }, + child: Container( + height: 48, + padding: const EdgeInsets.only(left: 8, right: 8, top: 6, bottom: 6), + decoration: BoxDecoration( + color: enable + ? ThemeUtils.currentColor.primaryContainer + : ThemeUtils.currentTheme.disabledColor, + borderRadius: const BorderRadius.all(Radius.circular(12.0)), + ), + child: Center( + child: Text( + title, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w600, + letterSpacing: 2, + color: enable + ? Colors.white + : ThemeUtils.currentColor.inversePrimary.withOpacity(0.7), + ).merge(titleStyle), + ), + ), + ), + // child: Text( + // title, + // style: titleStyle, + // ), + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/components/lib/widgets/empty/index.dart b/apps/flutter/components/lib/widgets/empty/index.dart new file mode 100644 index 000000000..31568a536 --- /dev/null +++ b/apps/flutter/components/lib/widgets/empty/index.dart @@ -0,0 +1,45 @@ +import 'package:flutter/widgets.dart'; + +class Empty extends StatelessWidget { + const Empty({ + super.key, + this.width, + this.height, + this.margin, + this.padding, + this.child, + this.alignment, + this.decoration, + this.foregroundDecoration, + this.transformAlignment, + }); + + final Widget? child; + final double? width; + final double? height; + final EdgeInsetsGeometry? margin; + final EdgeInsetsGeometry? padding; + final AlignmentGeometry? alignment; + final AlignmentGeometry? transformAlignment; + final Decoration? decoration; + final Decoration? foregroundDecoration; + + @override + Widget build(BuildContext context) { + return Container( + width: width, + height: height, + margin: margin, + padding: padding, + alignment: alignment, + decoration: decoration, + foregroundDecoration: foregroundDecoration, + transformAlignment: transformAlignment, + child: child, + ); + } + + static Empty get none { + return const Empty(); + } +} \ No newline at end of file diff --git a/apps/flutter/components/lib/widgets/index.dart b/apps/flutter/components/lib/widgets/index.dart new file mode 100644 index 000000000..2683ea74b --- /dev/null +++ b/apps/flutter/components/lib/widgets/index.dart @@ -0,0 +1,4 @@ +export 'avatar/index.dart'; +export 'action-button/index.dart'; +export 'bottom-button/index.dart'; +export 'empty/index.dart'; \ No newline at end of file diff --git a/apps/flutter/components/linux/flutter/generated_plugin_registrant.cc b/apps/flutter/components/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/apps/flutter/components/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/apps/flutter/components/linux/flutter/generated_plugin_registrant.h b/apps/flutter/components/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/apps/flutter/components/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/components/linux/flutter/generated_plugins.cmake b/apps/flutter/components/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2e1de87a7 --- /dev/null +++ b/apps/flutter/components/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/components/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/apps/flutter/components/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 000000000..1d550c760 --- /dev/null +++ b/apps/flutter/components/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\components +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/components/macos/Flutter/ephemeral/flutter_export_environment.sh b/apps/flutter/components/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100644 index 000000000..31898cd03 --- /dev/null +++ b/apps/flutter/components/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\components" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/components/pubspec.yaml b/apps/flutter/components/pubspec.yaml new file mode 100644 index 000000000..fd7e4a6ed --- /dev/null +++ b/apps/flutter/components/pubspec.yaml @@ -0,0 +1,58 @@ +name: components +description: A new Flutter package project. +version: 0.0.1 +homepage: +publish_to: none + +environment: + sdk: '>=3.0.5 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + core: + path: '../core' + get: + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/apps/flutter/components/windows/flutter/generated_plugin_registrant.cc b/apps/flutter/components/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/apps/flutter/components/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/apps/flutter/components/windows/flutter/generated_plugin_registrant.h b/apps/flutter/components/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/apps/flutter/components/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/components/windows/flutter/generated_plugins.cmake b/apps/flutter/components/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..b93c4c30c --- /dev/null +++ b/apps/flutter/components/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/core/.flutter-plugins b/apps/flutter/core/.flutter-plugins new file mode 100644 index 000000000..59e378d87 --- /dev/null +++ b/apps/flutter/core/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider-2.0.15\\ +path_provider_android=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_android-2.0.27\\ +path_provider_foundation=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_foundation-2.2.3\\ +path_provider_linux=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_linux-2.1.11\\ +path_provider_windows=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_windows-2.1.7\\ diff --git a/apps/flutter/core/.flutter-plugins-dependencies b/apps/flutter/core/.flutter-plugins-dependencies new file mode 100644 index 000000000..f3f5d8430 --- /dev/null +++ b/apps/flutter/core/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_android-2.0.27\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.3\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.1.11\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.1.7\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-07-16 08:23:33.451996","version":"3.10.5"} \ No newline at end of file diff --git a/apps/flutter/core/.gitignore b/apps/flutter/core/.gitignore new file mode 100644 index 000000000..96486fd93 --- /dev/null +++ b/apps/flutter/core/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/apps/flutter/core/.metadata b/apps/flutter/core/.metadata new file mode 100644 index 000000000..9596faeed --- /dev/null +++ b/apps/flutter/core/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: package diff --git a/apps/flutter/core/CHANGELOG.md b/apps/flutter/core/CHANGELOG.md new file mode 100644 index 000000000..41cc7d819 --- /dev/null +++ b/apps/flutter/core/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/apps/flutter/core/LICENSE b/apps/flutter/core/LICENSE new file mode 100644 index 000000000..ba75c69f7 --- /dev/null +++ b/apps/flutter/core/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/apps/flutter/core/README.md b/apps/flutter/core/README.md new file mode 100644 index 000000000..02fe8ecab --- /dev/null +++ b/apps/flutter/core/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/apps/flutter/core/analysis_options.yaml b/apps/flutter/core/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/apps/flutter/core/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/apps/flutter/core/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/apps/flutter/core/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 000000000..7eb0d9f93 --- /dev/null +++ b/apps/flutter/core/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,25 @@ +package io.flutter.plugins; + +import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugins.pathprovider.PathProviderPlugin; + +/** + * Generated file. Do not edit. + */ +public final class GeneratedPluginRegistrant { + public static void registerWith(PluginRegistry registry) { + if (alreadyRegisteredWith(registry)) { + return; + } + PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); + } + + private static boolean alreadyRegisteredWith(PluginRegistry registry) { + final String key = GeneratedPluginRegistrant.class.getCanonicalName(); + if (registry.hasPlugin(key)) { + return true; + } + registry.registrarFor(key); + return false; + } +} diff --git a/apps/flutter/core/android/local.properties b/apps/flutter/core/android/local.properties new file mode 100644 index 000000000..1a3be4ff1 --- /dev/null +++ b/apps/flutter/core/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=C:\\Users\\eddlevol\\AppData\\Local\\Android\\sdk +flutter.sdk=D:\\Sdk\\Flutter \ No newline at end of file diff --git a/apps/flutter/core/ios/Flutter/Generated.xcconfig b/apps/flutter/core/ios/Flutter/Generated.xcconfig new file mode 100644 index 000000000..a17a34f96 --- /dev/null +++ b/apps/flutter/core/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\core +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/core/ios/Flutter/flutter_export_environment.sh b/apps/flutter/core/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 000000000..1576646f6 --- /dev/null +++ b/apps/flutter/core/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\core" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/core/ios/Runner/GeneratedPluginRegistrant.h b/apps/flutter/core/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 000000000..7a8909271 --- /dev/null +++ b/apps/flutter/core/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/apps/flutter/core/ios/Runner/GeneratedPluginRegistrant.m b/apps/flutter/core/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 000000000..c0d0cbad8 --- /dev/null +++ b/apps/flutter/core/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,21 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import path_provider_foundation; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; +} + +@end diff --git a/apps/flutter/core/lib/abstracts/copy.with.dart b/apps/flutter/core/lib/abstracts/copy.with.dart new file mode 100644 index 000000000..8f7b3a05f --- /dev/null +++ b/apps/flutter/core/lib/abstracts/copy.with.dart @@ -0,0 +1,13 @@ +abstract class CloneObject { + T clone(); + + T cloneWith(Function(T) update) { + var obj = clone(); + update(obj); + return obj; + } + + void deepWith(Function(T) update) { + update(this as T); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/abstracts/index.dart b/apps/flutter/core/lib/abstracts/index.dart new file mode 100644 index 000000000..3ac25e682 --- /dev/null +++ b/apps/flutter/core/lib/abstracts/index.dart @@ -0,0 +1,2 @@ +export 'copy.with.dart'; +export 'logging.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/abstracts/logging.dart b/apps/flutter/core/lib/abstracts/logging.dart new file mode 100644 index 000000000..e09a7c0f8 --- /dev/null +++ b/apps/flutter/core/lib/abstracts/logging.dart @@ -0,0 +1,14 @@ +abstract class ILogger { + + void debug(dynamic message, [dynamic error, StackTrace? stackTrace]); + + void info(dynamic message, [dynamic error, StackTrace? stackTrace]); + + void warn(dynamic message, [dynamic error, StackTrace? stackTrace]); + + void error(dynamic message, [dynamic error, StackTrace? stackTrace]); + + void trace(dynamic message, [dynamic error, StackTrace? stackTrace]); + + void all(dynamic message, [dynamic error, StackTrace? stackTrace]); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/config/env.config.dart b/apps/flutter/core/lib/config/env.config.dart new file mode 100644 index 000000000..c054b0141 --- /dev/null +++ b/apps/flutter/core/lib/config/env.config.dart @@ -0,0 +1,60 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_app_environment/flutter_app_environment.dart' as envlib; + +part 'env.config.g.dart'; + +@JsonSerializable(createToJson: false) +class EnvConfig { + EnvConfig({ + required this.clientId, + this.clientSecret, + required this.authority, + required this.baseUrl, + this.uploadFilesUrl, + this.staticFilesUrl, + this.tenantKey = '__tenant', + this.defaultLanguage = 'en', + }); + String clientId; + String? clientSecret; + String authority; + String baseUrl; + String? uploadFilesUrl; + String? staticFilesUrl; + String? tenantKey; + String? defaultLanguage; + + factory EnvConfig.fromJson(Map json) => _$EnvConfigFromJson(json); +} + +enum Env { + development('DEV', 'Development'), + profile('PROF', 'Profile'), + production('PROD', 'Production'); + + final String name; + final String value; + const Env(this.name, this.value); + +} + +class Environment { + static Future initAsync() async { + var envType = envlib.EnvironmentType.development; + if (kReleaseMode) { + envType = envlib.EnvironmentType.production; + } else if (kProfileMode) { + envType = envlib.EnvironmentType.test; + } + + await envlib.Environment.initFromJson( + environmentType: envType, + fromJson: EnvConfig.fromJson, + ); + + Environment.current = envlib.Environment.instance().config; + } + + static late EnvConfig current; +} diff --git a/apps/flutter/core/lib/config/env.config.g.dart b/apps/flutter/core/lib/config/env.config.g.dart new file mode 100644 index 000000000..19b0a34fc --- /dev/null +++ b/apps/flutter/core/lib/config/env.config.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'env.config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +EnvConfig _$EnvConfigFromJson(Map json) => EnvConfig( + clientId: json['clientId'] as String, + clientSecret: json['clientSecret'] as String?, + authority: json['authority'] as String, + baseUrl: json['baseUrl'] as String, + uploadFilesUrl: json['uploadFilesUrl'] as String?, + staticFilesUrl: json['staticFilesUrl'] as String?, + tenantKey: json['tenantKey'] as String?, + defaultLanguage: json['defaultLanguage'] as String?, + ); diff --git a/apps/flutter/core/lib/config/index.dart b/apps/flutter/core/lib/config/index.dart new file mode 100644 index 000000000..dcea24ea1 --- /dev/null +++ b/apps/flutter/core/lib/config/index.dart @@ -0,0 +1 @@ +export 'env.config.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/core.module.dart b/apps/flutter/core/lib/core.module.dart new file mode 100644 index 000000000..76d87d066 --- /dev/null +++ b/apps/flutter/core/lib/core.module.dart @@ -0,0 +1,36 @@ +import 'package:core/dependency/injector.dart'; +import 'package:core/modularity/module.dart'; +import 'package:core/services/index.dart'; +import 'package:get/get.dart'; +import 'proxy/index.dart'; + +class CoreModule extends Module { + + @override + Future configureServicesAsync() async { + await Get.putAsync(() async { + if (await GetxStorageService.init()) { + return GetxStorageService(); + } + return StorageService(); + }, permanent: true); + await super.configureServicesAsync(); + } + + @override + void configureServices() { + inject(Injector.instance); + inject(this); + inject(ConfigStateService(), permanent: true); + inject(ThemeService(), permanent: true); + + lazyInject(() => SessionService(), fenix: true); + lazyInject(() => SubscriptionService(), fenix: true); + lazyInject(() => LanguageService(), fenix: true); + lazyInject(() => LocalizationService(), fenix: true); + lazyInject(() => AbpTenantService(), fenix: true); + lazyInject(() => AbpApiDefinitionService(), fenix: true); + lazyInject(() => AbpApplicationLocalizationService(), fenix: true); + lazyInject(() => AbpApplicationConfigurationService(), fenix: true); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/dependency/index.dart b/apps/flutter/core/lib/dependency/index.dart new file mode 100644 index 000000000..9d253260d --- /dev/null +++ b/apps/flutter/core/lib/dependency/index.dart @@ -0,0 +1 @@ +export 'injector.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/dependency/injector.dart b/apps/flutter/core/lib/dependency/injector.dart new file mode 100644 index 000000000..734f9a745 --- /dev/null +++ b/apps/flutter/core/lib/dependency/injector.dart @@ -0,0 +1,45 @@ +import 'package:get/get.dart'; + +class Injector { + factory Injector() => _getInstance ??= const Injector._(); + + const Injector._(); + + static Injector? _getInstance; + + static Injector get instance => Injector(); + + T get({ String? tag }) => Get.find(tag: tag); + + T inject( + T dependency, + { + String? tag, + bool permanent = false, + InstanceBuilderCallback? builder, + }) => Get.put(dependency, tag: tag, permanent: permanent, builder: builder); + + void create( + InstanceBuilderCallback builder, + { + String? tag, + bool permanent = true, + } + ) => Get.create(builder, tag: tag, permanent: permanent); + + void lazyInject( + InstanceBuilderCallback builder, + { + String? tag, + bool fenix = false, + }) => Get.lazyPut(builder, tag: tag, fenix: fenix); + + Future injectAsync( + AsyncInstanceBuilderCallback builder, + { + String? tag, + bool permanent = false, + }) => Get.putAsync(builder, tag: tag, permanent: permanent); + + bool isInjected({String? tag}) => Get.isRegistered(tag: tag); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/index.dart b/apps/flutter/core/lib/index.dart new file mode 100644 index 000000000..ec10ee99a --- /dev/null +++ b/apps/flutter/core/lib/index.dart @@ -0,0 +1,11 @@ +export './abstracts/index.dart'; +export './config/index.dart'; +export './dependency/index.dart'; +export './interceptors/index.dart'; +export './middlewares/index.dart'; +export './models/index.dart'; +export './proxy/index.dart'; +export './services/index.dart'; +export './tokens/index.dart'; +export './utils/index.dart'; +export 'core.module.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/interceptors/api.abp.wrapper.error.interceptor.dart b/apps/flutter/core/lib/interceptors/api.abp.wrapper.error.interceptor.dart new file mode 100644 index 000000000..cf4abd28c --- /dev/null +++ b/apps/flutter/core/lib/interceptors/api.abp.wrapper.error.interceptor.dart @@ -0,0 +1,26 @@ +import 'package:core/models/abp.error.dart'; +import 'package:dio/dio.dart'; + +class AbpWrapperRemoteServiceErrorInterceptor extends Interceptor { + @override + void onError(DioException err, ErrorInterceptorHandler handler) { + if (err.response == null) return handler.next(err); + var abpErrorMap = err.response?.headers['_abperrorformat']; + if (abpErrorMap != null && abpErrorMap.contains('true')) { + var errorJson = err.response!.data['error']; + if (errorJson == null && err.response!.data?.type == 'application/json') { + // 读取流 + } + else { + var remoteServiceErrorInfo = RemoteServiceErrorInfo.fromJson(errorJson); + var errorMessage = remoteServiceErrorInfo.message; + if (remoteServiceErrorInfo.validationErrors?.isEmpty == false) { + errorMessage += remoteServiceErrorInfo.validationErrors!.map((v) => v.message).join('\n'); + } + var cloneError = err.copyWith(message: errorMessage); + return handler.next(cloneError); + } + } + handler.next(err); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/interceptors/api.logger.interceptor.dart b/apps/flutter/core/lib/interceptors/api.logger.interceptor.dart new file mode 100644 index 000000000..979745a7b --- /dev/null +++ b/apps/flutter/core/lib/interceptors/api.logger.interceptor.dart @@ -0,0 +1,22 @@ +import 'package:core/utils/logging.dart'; +import 'package:dio/dio.dart'; + +class LoggerInterceptor extends Interceptor { + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { + logger.debug('网络请求开始: ${options.uri.toString()}'); + return handler.next(options); + } + + @override + void onResponse(Response response, ResponseInterceptorHandler handler) { + logger.debug('网络请求结束, status: ${response.statusCode}, message: ${response.statusMessage}'); + return handler.next(response); + } + + @override + void onError(DioException err, ErrorInterceptorHandler handler) { + logger.debug('网络请求错误', err, err.stackTrace); + return handler.next(err); + } +} diff --git a/apps/flutter/core/lib/interceptors/api.wrapper.result.interceptor.dart b/apps/flutter/core/lib/interceptors/api.wrapper.result.interceptor.dart new file mode 100644 index 000000000..0ad9c2e1b --- /dev/null +++ b/apps/flutter/core/lib/interceptors/api.wrapper.result.interceptor.dart @@ -0,0 +1,33 @@ +import 'package:core/models/wrapper.dart'; +import 'package:dio/dio.dart'; + +class WrapperResultInterceptor extends Interceptor { + @override + void onResponse(Response response, ResponseInterceptorHandler handler) { + if ('true' == response.headers.value('_abpwrapresult')) { + if (response.data == null) { + handler.reject(DioException( + requestOptions: response.requestOptions, + response: response, + type: DioExceptionType.badResponse, + message: '请求出错, 请稍后再试!')); + return; + } + var result = Wrapper.fromJson(response.data!); + if ('0' == result.code) { + response.data = result; + handler.resolve(response); + return; + } + + handler.reject(DioException( + requestOptions: response.requestOptions, + response: response, + type: DioExceptionType.badResponse, + message: result.details ?? result.message)); + + return; + } + handler.next(response); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/interceptors/index.dart b/apps/flutter/core/lib/interceptors/index.dart new file mode 100644 index 000000000..90e0277fe --- /dev/null +++ b/apps/flutter/core/lib/interceptors/index.dart @@ -0,0 +1,3 @@ +export 'api.abp.wrapper.error.interceptor.dart'; +export 'api.wrapper.result.interceptor.dart'; +export 'api.logger.interceptor.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/middlewares/authorization.dart b/apps/flutter/core/lib/middlewares/authorization.dart new file mode 100644 index 000000000..45b437747 --- /dev/null +++ b/apps/flutter/core/lib/middlewares/authorization.dart @@ -0,0 +1,15 @@ +import 'package:core/services/session.service.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class AuthorizationMiddleware extends GetMiddleware { + AuthorizationMiddleware(this.loginRoute); + final String loginRoute; + @override + RouteSettings? redirect(String? route) { + if (!SessionService.to.isAuthenticated) { + return RouteSettings(name: loginRoute); + } + return super.redirect(route); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/middlewares/index.dart b/apps/flutter/core/lib/middlewares/index.dart new file mode 100644 index 000000000..b9b4a8afb --- /dev/null +++ b/apps/flutter/core/lib/middlewares/index.dart @@ -0,0 +1 @@ +export 'authorization.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/models/abp.dto.dart b/apps/flutter/core/lib/models/abp.dto.dart new file mode 100644 index 000000000..3dcf1e647 --- /dev/null +++ b/apps/flutter/core/lib/models/abp.dto.dart @@ -0,0 +1,393 @@ +class LocalizableStringInfo { + LocalizableStringInfo({ + required this.resourceName, + required this.name, + }); + String resourceName; + String name; + + factory LocalizableStringInfo.fromJson(Map json) => + LocalizableStringInfo( + resourceName: json['resourceName'] as String, + name: json['name'] as String, + ); + Map toJson() => { + 'resourceName': resourceName, + 'name': name, + }; +} + + +class ExtraPropertyDictionary implements Map { + ExtraPropertyDictionary({ + Map? map + }) { + _innerMap = map ?? {}; + } + late Map _innerMap = {}; + @override + operator [](Object? key) { + return _innerMap[key]; + } + + @override + void operator []=(String key, value) { + _innerMap[key] = value; + } + + @override + void addAll(Map other) { + _innerMap.addAll(other); + } + + @override + void addEntries(Iterable> newEntries) { + _innerMap.addEntries(newEntries); + } + + @override + Map cast() { + return _innerMap.cast(); + } + + @override + void clear() { + _innerMap.clear(); + } + + @override + bool containsKey(Object? key) { + return _innerMap.containsKey(key); + } + + @override + bool containsValue(Object? value) { + return _innerMap.containsValue(value); + } + + @override + Iterable> get entries => _innerMap.entries; + + @override + void forEach(void Function(String key, dynamic value) action) { + _innerMap.forEach(action); + } + + @override + bool get isEmpty => _innerMap.isEmpty; + + @override + bool get isNotEmpty => _innerMap.isNotEmpty; + + @override + Iterable get keys => _innerMap.keys; + + @override + int get length => _innerMap.length; + + @override + Map map(MapEntry Function(String key, dynamic value) convert) { + return _innerMap.map(convert); + } + + @override + putIfAbsent(String key, Function() ifAbsent) { + return _innerMap.putIfAbsent(key, ifAbsent); + } + + @override + remove(Object? key) { + return _innerMap.remove(key); + } + + @override + void removeWhere(bool Function(String key, dynamic value) test) { + _innerMap.removeWhere(test); + } + + @override + update(String key, Function(dynamic value) update, {Function()? ifAbsent}) { + return _innerMap.update(key, update, ifAbsent: ifAbsent); + } + + @override + void updateAll(Function(String key, dynamic value) update) { + _innerMap.updateAll(update); + } + + @override + Iterable get values => _innerMap.values; +} + +class ExtensibleObject { + ExtensibleObject({ + this.extraProperties, + }); + ExtraPropertyDictionary? extraProperties; +} + +class EntityDto { + EntityDto({ + required this.id, + }); + TPrimaryKey id; +} + +class CreationAuditedEntityDto extends EntityDto { + CreationAuditedEntityDto({ + required super.id, + required this.creationTime, + this.creatorId, + }); + DateTime creationTime; + String? creatorId; +} + +class CreationAuditedEntityWithUserDto extends CreationAuditedEntityDto { + CreationAuditedEntityWithUserDto({ + required super.id, + required this.creator, + required super.creationTime, + super.creatorId, + }); + TUserDto creator; +} + +class AuditedEntityDto extends CreationAuditedEntityDto { + AuditedEntityDto({ + required super.id, + required super.creationTime, + super.creatorId, + this.lastModificationTime, + this.lastModifierId, + }); + DateTime? lastModificationTime; + String? lastModifierId; +} + +class AuditedEntityWithUserDto extends AuditedEntityDto { + AuditedEntityWithUserDto({ + required super.id, + required this.creator, + required this.lastModifier, + required super.creationTime, + super.creatorId, + super.lastModificationTime, + super.lastModifierId, + }); + TUserDto creator; + TUserDto lastModifier; +} + +class FullAuditedEntityDto extends AuditedEntityDto { + FullAuditedEntityDto({ + required super.id, + required this.isDeleted, + this.deleterId, + this.deletionTime, + required super.creationTime, + super.creatorId, + super.lastModificationTime, + super.lastModifierId, + }); + bool isDeleted; + String? deleterId; + DateTime? deletionTime; +} + +class FullAuditedEntityWithUserDto extends FullAuditedEntityDto { + FullAuditedEntityWithUserDto({ + required super.id, + required this.creator, + required this.lastModifier, + required this.deleter, + required super.isDeleted, + super.deleterId, + super.deletionTime, + required super.creationTime, + super.creatorId, + super.lastModificationTime, + super.lastModifierId, + }); + TUserDto creator; + TUserDto lastModifier; + TUserDto deleter; +} + +class ExtensibleEntityDto extends ExtensibleObject { + ExtensibleEntityDto({ + required this.id, + }); + TKey id; +} + +class ExtensibleCreationAuditedEntityDto extends ExtensibleEntityDto { + ExtensibleCreationAuditedEntityDto({ + required super.id, + required this.creationTime, + this.creatorId, + }); + DateTime creationTime; + String? creatorId; +} + +class ExtensibleCreationAuditedEntityWithUserDto extends ExtensibleCreationAuditedEntityDto { + ExtensibleCreationAuditedEntityWithUserDto({ + required super.id, + required this.creator, + required super.creationTime, + super.creatorId, + }); + TUserDto creator; +} + +class ExtensibleAuditedEntityDto extends ExtensibleCreationAuditedEntityDto { + ExtensibleAuditedEntityDto({ + required super.id, + required super.creationTime, + super.creatorId, + this.lastModificationTime, + this.lastModifierId, + }); + DateTime? lastModificationTime; + String? lastModifierId; +} + +class ExtensibleAuditedEntityWithUserDto extends ExtensibleAuditedEntityDto { + ExtensibleAuditedEntityWithUserDto({ + required super.id, + required this.creator, + required this.lastModifier, + required super.creationTime, + super.creatorId, + super.lastModificationTime, + super.lastModifierId, + }); + TUserDto creator; + TUserDto lastModifier; +} + +class ExtensibleFullAuditedEntityDto extends ExtensibleAuditedEntityDto { + ExtensibleFullAuditedEntityDto({ + required super.id, + required this.isDeleted, + this.deleterId, + this.deletionTime, + required super.creationTime, + super.creatorId, + super.lastModificationTime, + super.lastModifierId, + }); + bool isDeleted; + String? deleterId; + DateTime? deletionTime; +} + +class ExtensibleFullAuditedEntityWithUserDto extends ExtensibleFullAuditedEntityDto { + ExtensibleFullAuditedEntityWithUserDto({ + required super.id, + required this.creator, + required this.lastModifier, + required this.deleter, + required super.isDeleted, + super.deleterId, + super.deletionTime, + required super.creationTime, + super.creatorId, + super.lastModificationTime, + super.lastModifierId, + }); + TUserDto creator; + TUserDto lastModifier; + TUserDto deleter; +} + +class ListResultDto { + ListResultDto({ + required this.items, + }); + List items; +} + +class LimitedResultRequestDto { + LimitedResultRequestDto({ + this.maxResultCount, + }); + int? maxResultCount = 10; +} + +class ExtensibleLimitedResultRequestDto extends LimitedResultRequestDto { + ExtensibleLimitedResultRequestDto({ + super.maxResultCount, + this.extraProperties, + }); + ExtraPropertyDictionary? extraProperties; +} + +class ExtensibleListResultDto extends ListResultDto { + ExtensibleListResultDto({ + required super.items, + this.extraProperties, + }); + ExtraPropertyDictionary? extraProperties; +} + +class PagedResultDto extends ListResultDto { + PagedResultDto({ + required this.totalCount, + required super.items, + }); + int totalCount; +} + +class ExtensiblePagedResultDto extends PagedResultDto { + ExtensiblePagedResultDto({ + required super.totalCount, + required super.items, + this.extraProperties, + }); + ExtraPropertyDictionary? extraProperties; +} + +class SortedResultRequest { + SortedResultRequest({ + this.sorting, + }); + String? sorting; +} + +class PagedResultRequestDto extends LimitedResultRequestDto { + PagedResultRequestDto({ + this.skipCount, + super.maxResultCount, + }); + int? skipCount = 0; +} + +class PagedAndSortedResultRequestDto extends PagedResultRequestDto { + PagedAndSortedResultRequestDto({ + super.skipCount, + super.maxResultCount, + this.sorting, + }); + String? sorting; +} + +class ExtensiblePagedAndSortedResultRequestDto extends PagedAndSortedResultRequestDto { + ExtensiblePagedAndSortedResultRequestDto({ + super.skipCount, + super.maxResultCount, + super.sorting, + this.extraProperties, + }); + ExtraPropertyDictionary? extraProperties; +} + +class ExtensiblePagedResultRequestDto extends PagedResultRequestDto { + ExtensiblePagedResultRequestDto({ + super.skipCount, + super.maxResultCount, + this.extraProperties, + }); + ExtraPropertyDictionary? extraProperties; +} diff --git a/apps/flutter/core/lib/models/abp.error.dart b/apps/flutter/core/lib/models/abp.error.dart new file mode 100644 index 000000000..3ba2516eb --- /dev/null +++ b/apps/flutter/core/lib/models/abp.error.dart @@ -0,0 +1,35 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'abp.error.g.dart'; + +@JsonSerializable() +class RemoteServiceErrorInfo { + RemoteServiceErrorInfo({ + required this.code, + required this.message, + this.details, + this.data, + this.validationErrors, + }); + String code; + String message; + String? details; + Map? data; + List? validationErrors; + + factory RemoteServiceErrorInfo.fromJson(Map json) => _$RemoteServiceErrorInfoFromJson(json); + Map toJson() => _$RemoteServiceErrorInfoToJson(this); +} + +@JsonSerializable() +class RemoteServiceValidationErrorInfo { + RemoteServiceValidationErrorInfo({ + required this.message, + this.members, + }); + String message; + List? members = []; + + factory RemoteServiceValidationErrorInfo.fromJson(Map json) => _$RemoteServiceValidationErrorInfoFromJson(json); + Map toJson() => _$RemoteServiceValidationErrorInfoToJson(this); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/models/abp.error.g.dart b/apps/flutter/core/lib/models/abp.error.g.dart new file mode 100644 index 000000000..d587f0e84 --- /dev/null +++ b/apps/flutter/core/lib/models/abp.error.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'abp.error.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +RemoteServiceErrorInfo _$RemoteServiceErrorInfoFromJson( + Map json) => + RemoteServiceErrorInfo( + code: json['code'] as String, + message: json['message'] as String, + details: json['details'] as String?, + data: (json['data'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ), + validationErrors: (json['validationErrors'] as List?) + ?.map((e) => RemoteServiceValidationErrorInfo.fromJson( + e as Map)) + .toList(), + ); + +Map _$RemoteServiceErrorInfoToJson( + RemoteServiceErrorInfo instance) => + { + 'code': instance.code, + 'message': instance.message, + 'details': instance.details, + 'data': instance.data, + 'validationErrors': instance.validationErrors, + }; + +RemoteServiceValidationErrorInfo _$RemoteServiceValidationErrorInfoFromJson( + Map json) => + RemoteServiceValidationErrorInfo( + message: json['message'] as String, + members: + (json['members'] as List?)?.map((e) => e as String).toList(), + ); + +Map _$RemoteServiceValidationErrorInfoToJson( + RemoteServiceValidationErrorInfo instance) => + { + 'message': instance.message, + 'members': instance.members, + }; diff --git a/apps/flutter/core/lib/models/auth.dart b/apps/flutter/core/lib/models/auth.dart new file mode 100644 index 000000000..43971b78d --- /dev/null +++ b/apps/flutter/core/lib/models/auth.dart @@ -0,0 +1,285 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'auth.g.dart'; + +/// 企业平台认证请求承载体 +@JsonSerializable() +class PortalTokenRequest extends TokenRequest { + PortalTokenRequest({ + required clientId, + clientSecret, + required this.userName, + required this.password, + this.enterpriseId, + }) : super( + grantType: 'portal', + clientId: clientId, + clientSecret: clientSecret, + ); + /// 用户名 + @JsonKey(name: 'username') + String userName; + /// 密码 + @JsonKey(name: 'password') + String password; + /// 双因素认证提供者 + @JsonKey(name: 'enterpriseId') + String? enterpriseId; + + @override + String toFormUrlencodedData() { + return '${super.toFormUrlencodedData()}&enterpriseId=${enterpriseId ?? ''}&username=$userName&password=$password'; + } + + factory PortalTokenRequest.fromJson(Map json) => _$PortalTokenRequestFromJson(json); + + Map toJson() => _$PortalTokenRequestToJson(this); +} + +/// 双因素身份认证手机认证请求承载体 +@JsonSerializable() +class TwoFactorPhoneNumberTokenRequest extends PhoneNumberTokenRequest { + TwoFactorPhoneNumberTokenRequest({ + required super.clientId, + super.clientSecret, + required super.phoneNumber, + required super.code, + required this.twoFactorProvider, + required this.twoFactorCode, + }); + /// 双因素认证提供者 + @JsonKey(name: 'twoFactorProvider') + String twoFactorProvider; + /// 双因素认证验证码 + @JsonKey(name: 'twoFactorCode') + String twoFactorCode; + + @override + String toFormUrlencodedData() { + return '${super.toFormUrlencodedData()}&phone_number=$phoneNumber&phone_verify_code=$code&twoFactorProvider=twoFactorProvider&twoFactorCode=$twoFactorCode'; + } + + factory TwoFactorPhoneNumberTokenRequest.fromJson(Map json) => _$TwoFactorPhoneNumberTokenRequestFromJson(json); + + @override + Map toJson() => _$TwoFactorPhoneNumberTokenRequestToJson(this); +} + +/// 身份认证手机验证请求承载体 +@JsonSerializable() +class PhoneNumberTokenRequest extends TokenRequest { + PhoneNumberTokenRequest({ + required clientId, + clientSecret, + required this.phoneNumber, + required this.code, + }) : super(grantType: 'phone_verify', clientId: clientId, clientSecret: clientSecret); + /// 手机号 + // ignore: non_constant_identifier_names + @JsonKey(name: 'phone_number') + late String phoneNumber; + /// 验证码 + // ignore: non_constant_identifier_names + @JsonKey(name: 'phone_verify_code') + late String code; + + @override + String toFormUrlencodedData() { + return '${super.toFormUrlencodedData()}&phone_number=$phoneNumber&phone_verify_code=$code'; + } + + factory PhoneNumberTokenRequest.fromJson(Map json) => _$PhoneNumberTokenRequestFromJson(json); + Map toJson() => _$PhoneNumberTokenRequestToJson(this); +} + +/// 双因素身份认证密码认证请求承载体 +@JsonSerializable() +class TwoFactorPasswordTokenRequest extends PasswordTokenRequest { + TwoFactorPasswordTokenRequest({ + required super.clientId, + super.clientSecret, + required super.userName, + required super.password, + required this.twoFactorProvider, + required this.twoFactorCode, + }); + /// 双因素认证提供者 + @JsonKey(name: 'twoFactorProvider') + String twoFactorProvider; + /// 双因素认证验证码 + @JsonKey(name: 'twoFactorCode') + String twoFactorCode; + + @override + String toFormUrlencodedData() { + return '${super.toFormUrlencodedData()}&twoFactorProvider=$twoFactorProvider&twoFactorCode=$twoFactorCode'; + } + + factory TwoFactorPasswordTokenRequest.fromJson(Map json) => _$TwoFactorPasswordTokenRequestFromJson(json); + + @override + Map toJson() => _$TwoFactorPasswordTokenRequestToJson(this); +} + +/// 身份认证密码验证请求承载体 +@JsonSerializable() +class PasswordTokenRequest extends TokenRequest { + PasswordTokenRequest({ + required clientId, + clientSecret, + required this.userName, + required this.password, + }) : super( + grantType: 'password', + clientId: clientId, + clientSecret: clientSecret, + ); + /// 用户名 + @JsonKey(name: 'username') + String userName; + /// 密码 + @JsonKey(name: 'password') + String password; + + @override + String toFormUrlencodedData() { + return '${super.toFormUrlencodedData()}&username=$userName&password=$password'; + } + + factory PasswordTokenRequest.fromJson(Map json) => _$PasswordTokenRequestFromJson(json); + Map toJson() => _$PasswordTokenRequestToJson(this); +} + +/// 刷新令牌请求承载体 +@JsonSerializable() +class RefreshTokenRequest extends TokenRequest { + RefreshTokenRequest({ + required String clientId, + String? clientSecret, + required this.refreshToken, + }) : super( + grantType: 'refresh_token', + clientId: clientId, + clientSecret: clientSecret, + ); + /// 刷新令牌 + // ignore: non_constant_identifier_names + @JsonKey(name: 'refresh_token') + late String refreshToken; + + @override + String toFormUrlencodedData() { + return '${super.toFormUrlencodedData()}&refresh_token=$refreshToken'; + } + + factory RefreshTokenRequest.fromJson(Map json) => _$RefreshTokenRequestFromJson(json); + Map toJson() => _$RefreshTokenRequestToJson(this); +} + +/// 身份认证请求承载体 +abstract class TokenRequest { + TokenRequest({ + required this.grantType, + required this.clientId, + this.clientSecret, + }); + /// 认证类型 + // ignore: non_constant_identifier_names + @JsonKey(name: 'grant_type') + late String grantType; + /// 客户端标识 + // ignore: non_constant_identifier_names + @JsonKey(name: 'client_id') + late String clientId; + /// 客户端密钥 + // ignore: non_constant_identifier_names + @JsonKey(name: 'client_secret') + String? clientSecret; + + String toFormUrlencodedData() { + return 'grant_type=$grantType&client_id=$clientId&client_secret=$clientSecret'; + } +} + +/// 双因素认证请求承载 +abstract class TwoFactorRequest { + TwoFactorRequest({ + required this.twoFactorProvider, + required this.twoFactorCode, + }); + /// 双因素认证提供者 + @JsonKey(name: 'twoFactorProvider') + String twoFactorProvider; + /// 双因素认证验证码 + @JsonKey(name: 'twoFactorCode') + String twoFactorCode; +} + +/// 身份认证令牌承载体 +@JsonSerializable() +class Token { + Token({ + required this.accessToken, + this.expiresIn, + this.tokenType, + this.refreshToken, + this.scope, + }); + /// 令牌 + @JsonKey(name: 'access_token') + String accessToken; + /// 过期时间 + @JsonKey(name: 'expires_in') + int? expiresIn; + /// 令牌类型 + @JsonKey(name: 'token_type') + String? tokenType; + /// 刷新令牌 + @JsonKey(name: 'refresh_token') + String? refreshToken; + /// 范围 + @JsonKey(name: 'scope') + String? scope; + + factory Token.fromJson(Map json) => _$TokenFromJson(json); + Map toJson() => _$TokenToJson(this); +} + +@JsonSerializable() +class UserProfile { + UserProfile({ + required this.id, + required this.userName, + this.avatarUrl, + this.name, + this.surName, + this.email, + this.emailVerified, + this.phoneNumber, + this.phoneNumberVerified, + }); + @JsonKey(name: 'sub') + String id; + @JsonKey(name: 'name') + String userName; + @JsonKey(name: 'avatarUrl') + String? avatarUrl; + @JsonKey(name: 'given_name') + String? name; + @JsonKey(name: 'family_name') + String? surName; + @JsonKey(name: 'email') + String? email; + @JsonKey(name: 'email_verified') + String? emailVerified; + @JsonKey(name: 'phoneNumber') + String? phoneNumber; + @JsonKey(name: 'phone_number_verified') + String? phoneNumberVerified; + + bool get isEmailVerified => emailVerified?.toLowerCase() == 'true'; + bool get isPhoneNumberVerified => phoneNumberVerified?.toLowerCase() == 'true'; + + factory UserProfile.fromJson(Map json) => _$UserProfileFromJson(json); + Map toJson() => _$UserProfileToJson(this); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/models/auth.g.dart b/apps/flutter/core/lib/models/auth.g.dart new file mode 100644 index 000000000..b406e56bc --- /dev/null +++ b/apps/flutter/core/lib/models/auth.g.dart @@ -0,0 +1,167 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PortalTokenRequest _$PortalTokenRequestFromJson(Map json) => + PortalTokenRequest( + clientId: json['client_id'], + clientSecret: json['client_secret'], + userName: json['username'] as String, + password: json['password'] as String, + enterpriseId: json['enterpriseId'] as String?, + )..grantType = json['grant_type'] as String; + +Map _$PortalTokenRequestToJson(PortalTokenRequest instance) => + { + 'grant_type': instance.grantType, + 'client_id': instance.clientId, + 'client_secret': instance.clientSecret, + 'username': instance.userName, + 'password': instance.password, + 'enterpriseId': instance.enterpriseId, + }; + +TwoFactorPhoneNumberTokenRequest _$TwoFactorPhoneNumberTokenRequestFromJson( + Map json) => + TwoFactorPhoneNumberTokenRequest( + clientId: json['client_id'], + clientSecret: json['client_secret'], + phoneNumber: json['phone_number'] as String, + code: json['phone_verify_code'] as String, + twoFactorProvider: json['twoFactorProvider'] as String, + twoFactorCode: json['twoFactorCode'] as String, + )..grantType = json['grant_type'] as String; + +Map _$TwoFactorPhoneNumberTokenRequestToJson( + TwoFactorPhoneNumberTokenRequest instance) => + { + 'grant_type': instance.grantType, + 'client_id': instance.clientId, + 'client_secret': instance.clientSecret, + 'phone_number': instance.phoneNumber, + 'phone_verify_code': instance.code, + 'twoFactorProvider': instance.twoFactorProvider, + 'twoFactorCode': instance.twoFactorCode, + }; + +PhoneNumberTokenRequest _$PhoneNumberTokenRequestFromJson( + Map json) => + PhoneNumberTokenRequest( + clientId: json['client_id'], + clientSecret: json['client_secret'], + phoneNumber: json['phone_number'] as String, + code: json['phone_verify_code'] as String, + )..grantType = json['grant_type'] as String; + +Map _$PhoneNumberTokenRequestToJson( + PhoneNumberTokenRequest instance) => + { + 'grant_type': instance.grantType, + 'client_id': instance.clientId, + 'client_secret': instance.clientSecret, + 'phone_number': instance.phoneNumber, + 'phone_verify_code': instance.code, + }; + +TwoFactorPasswordTokenRequest _$TwoFactorPasswordTokenRequestFromJson( + Map json) => + TwoFactorPasswordTokenRequest( + clientId: json['client_id'], + clientSecret: json['client_secret'], + userName: json['username'] as String, + password: json['password'] as String, + twoFactorProvider: json['twoFactorProvider'] as String, + twoFactorCode: json['twoFactorCode'] as String, + )..grantType = json['grant_type'] as String; + +Map _$TwoFactorPasswordTokenRequestToJson( + TwoFactorPasswordTokenRequest instance) => + { + 'grant_type': instance.grantType, + 'client_id': instance.clientId, + 'client_secret': instance.clientSecret, + 'username': instance.userName, + 'password': instance.password, + 'twoFactorProvider': instance.twoFactorProvider, + 'twoFactorCode': instance.twoFactorCode, + }; + +PasswordTokenRequest _$PasswordTokenRequestFromJson( + Map json) => + PasswordTokenRequest( + clientId: json['client_id'], + clientSecret: json['client_secret'], + userName: json['username'] as String, + password: json['password'] as String, + )..grantType = json['grant_type'] as String; + +Map _$PasswordTokenRequestToJson( + PasswordTokenRequest instance) => + { + 'grant_type': instance.grantType, + 'client_id': instance.clientId, + 'client_secret': instance.clientSecret, + 'username': instance.userName, + 'password': instance.password, + }; + +RefreshTokenRequest _$RefreshTokenRequestFromJson(Map json) => + RefreshTokenRequest( + clientId: json['client_id'] as String, + clientSecret: json['client_secret'] as String?, + refreshToken: json['refresh_token'] as String, + )..grantType = json['grant_type'] as String; + +Map _$RefreshTokenRequestToJson( + RefreshTokenRequest instance) => + { + 'grant_type': instance.grantType, + 'client_id': instance.clientId, + 'client_secret': instance.clientSecret, + 'refresh_token': instance.refreshToken, + }; + +Token _$TokenFromJson(Map json) => Token( + accessToken: json['access_token'] as String, + expiresIn: json['expires_in'] as int?, + tokenType: json['token_type'] as String?, + refreshToken: json['refresh_token'] as String?, + scope: json['scope'] as String?, + ); + +Map _$TokenToJson(Token instance) => { + 'access_token': instance.accessToken, + 'expires_in': instance.expiresIn, + 'token_type': instance.tokenType, + 'refresh_token': instance.refreshToken, + 'scope': instance.scope, + }; + +UserProfile _$UserProfileFromJson(Map json) => UserProfile( + id: json['sub'] as String, + userName: json['name'] as String, + avatarUrl: json['avatarUrl'] as String?, + name: json['given_name'] as String?, + surName: json['family_name'] as String?, + email: json['email'] as String?, + emailVerified: json['email_verified'] as String?, + phoneNumber: json['phoneNumber'] as String?, + phoneNumberVerified: json['phone_number_verified'] as String?, + ); + +Map _$UserProfileToJson(UserProfile instance) => + { + 'sub': instance.id, + 'name': instance.userName, + 'avatarUrl': instance.avatarUrl, + 'given_name': instance.name, + 'family_name': instance.surName, + 'email': instance.email, + 'email_verified': instance.emailVerified, + 'phoneNumber': instance.phoneNumber, + 'phone_number_verified': instance.phoneNumberVerified, + }; diff --git a/apps/flutter/core/lib/models/common.dart b/apps/flutter/core/lib/models/common.dart new file mode 100644 index 000000000..8942605dc --- /dev/null +++ b/apps/flutter/core/lib/models/common.dart @@ -0,0 +1,17 @@ +class Localization { + Localization( + this.culture, + this.resources, + ); + String culture; + List resources; +} + +class LocalizationResource { + LocalizationResource( + this.resourceName, + this.texts, + ); + String resourceName; + Map texts; +} diff --git a/apps/flutter/core/lib/models/index.dart b/apps/flutter/core/lib/models/index.dart new file mode 100644 index 000000000..7048bdbc3 --- /dev/null +++ b/apps/flutter/core/lib/models/index.dart @@ -0,0 +1,8 @@ +export 'abp.dto.dart'; +export 'abp.error.dart'; +export 'auth.dart'; +export 'common.dart'; +export 'oauth.dart'; +export 'session.dart'; +export 'theme.dart'; +export 'wrapper.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/models/oauth.dart b/apps/flutter/core/lib/models/oauth.dart new file mode 100644 index 000000000..908795d77 --- /dev/null +++ b/apps/flutter/core/lib/models/oauth.dart @@ -0,0 +1,31 @@ +class LoginParams { + LoginParams({ + required this.username, + required this.password, + }); + String username; + String password; +} + +class SmsLoginParams { + SmsLoginParams({ + required this.phonenumber, + required this.code, + }); + String phonenumber; + String code; +} + +class PortalLoginParams extends LoginParams { + PortalLoginParams({ + this.enterpriseId, + required super.username, + required super.password, + }); + String? enterpriseId; +} + +class RefreshTokenParams { + RefreshTokenParams(this.refreshToken); + String refreshToken; +} diff --git a/apps/flutter/core/lib/models/session.dart b/apps/flutter/core/lib/models/session.dart new file mode 100644 index 000000000..d8ab12c03 --- /dev/null +++ b/apps/flutter/core/lib/models/session.dart @@ -0,0 +1,33 @@ +import 'package:core/abstracts/copy.with.dart'; +import 'package:core/models/auth.dart'; +import 'package:core/proxy/volo/abp/asp-net-core/index.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'session.g.dart'; + +/// 企业平台认证请求承载体 +@JsonSerializable() +class Session extends CloneObject { + Session({ + this.language, + this.profile, + this.tenant, + this.token, + }); + String? language; + UserProfile? profile; + CurrentTenantDto? tenant; + Token? token; + + factory Session.fromJson(Map json) => _$SessionFromJson(json); + + Map toJson() => _$SessionToJson(this); + + @override + Session clone() => Session( + language: language, + profile: profile, + tenant: tenant, + token: token, + ); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/models/session.g.dart b/apps/flutter/core/lib/models/session.g.dart new file mode 100644 index 000000000..feb3e7157 --- /dev/null +++ b/apps/flutter/core/lib/models/session.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'session.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Session _$SessionFromJson(Map json) => Session( + language: json['language'] as String?, + profile: json['profile'] == null + ? null + : UserProfile.fromJson(json['profile'] as Map), + tenant: json['tenant'] == null + ? null + : CurrentTenantDto.fromJson(json['tenant'] as Map), + token: json['token'] == null + ? null + : Token.fromJson(json['token'] as Map), + ); + +Map _$SessionToJson(Session instance) => { + 'language': instance.language, + 'profile': instance.profile, + 'tenant': instance.tenant, + 'token': instance.token, + }; diff --git a/apps/flutter/core/lib/models/theme.dart b/apps/flutter/core/lib/models/theme.dart new file mode 100644 index 000000000..8906fea62 --- /dev/null +++ b/apps/flutter/core/lib/models/theme.dart @@ -0,0 +1,7 @@ +class Theme { + String? mode = 'light'; + String? primaryColor; + String? primaryColorDark; + String? primaryColorLight; + String? scaffoldBackgroundColor; +} \ No newline at end of file diff --git a/apps/flutter/core/lib/models/wrapper.dart b/apps/flutter/core/lib/models/wrapper.dart new file mode 100644 index 000000000..34f17eeb4 --- /dev/null +++ b/apps/flutter/core/lib/models/wrapper.dart @@ -0,0 +1,21 @@ +class Wrapper { + Wrapper({ + required this.code, + required this.message, + required this.result, + this.details, + }); + String code; + String message; + String? details; + T? result; + + factory Wrapper.fromJson(dynamic json) { + return Wrapper( + code: json['code'] as String, + message: json['message'] as String, + result: json['result'] as T?, + details: json['details'] as String?, + ); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/modularity/index.dart b/apps/flutter/core/lib/modularity/index.dart new file mode 100644 index 000000000..7cf0d4a3b --- /dev/null +++ b/apps/flutter/core/lib/modularity/index.dart @@ -0,0 +1,2 @@ +export 'module.dart'; +export 'module.key.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/modularity/module.dart b/apps/flutter/core/lib/modularity/module.dart new file mode 100644 index 000000000..4f581b334 --- /dev/null +++ b/apps/flutter/core/lib/modularity/module.dart @@ -0,0 +1,94 @@ +import 'package:get/get.dart'; + +import 'module.key.dart'; + +abstract class Module { + static final Map _initModuleMap = {}; + List get dependencies => const []; + + List get routes => const []; + + Future configureServicesAsync() { + return Future.sync(() => configureServices()); + } + + void configureServices() { + + } + + T inject( + T dependency, + { + String? tag, + bool permanent = false, + InstanceBuilderCallback? builder, + }) => Get.put(dependency, tag: tag, permanent: permanent, builder: builder); + + void create( + InstanceBuilderCallback builder, + { + String? tag, + bool permanent = true, + } + ) => Get.create(builder, tag: tag, permanent: permanent); + + void lazyInject( + InstanceBuilderCallback builder, + { + String? tag, + bool fenix = false, + }) => Get.lazyPut(builder, tag: tag, fenix: fenix); + + Future injectAsync( + AsyncInstanceBuilderCallback builder, + { + String? tag, + bool permanent = false, + }) => Get.putAsync(builder, tag: tag, permanent: permanent); + + bool isInjected({String? tag}) => Get.isRegistered(tag: tag); + + Future>> initAsync() async { + final routeMap = >{}; + for (var dependency in dependencies) { + if (_initModuleMap.containsKey(dependency)) { + continue; + } + await dependency.configureServicesAsync(); + var childrenRoute = await dependency.initAsync(); + routeMap.addAll(childrenRoute); + _initModuleMap[dependency] = true; + } + await configureServicesAsync(); + routeMap.assign(ModuleKey(toString()), routes); + _initModuleMap[this] = true; + return routeMap; + } + + Map> init() { + final routeMap = >{}; + for (var dependency in dependencies) { + if (_initModuleMap.containsKey(dependency)) { + continue; + } + dependency.configureServices(); + var childrenRoute = dependency.init(); + routeMap.addAll(childrenRoute); + _initModuleMap[dependency] = true; + } + configureServices(); + routeMap.assign(ModuleKey(toString()), routes); + _initModuleMap[this] = true; + return routeMap; + } + + List getRoutes() { + List findRoutes = []; + findRoutes.addAll(routes); + for (var dependency in dependencies) { + findRoutes.addAll(dependency.routes); + } + + return findRoutes; + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/modularity/module.key.dart b/apps/flutter/core/lib/modularity/module.key.dart new file mode 100644 index 000000000..a0090c9d0 --- /dev/null +++ b/apps/flutter/core/lib/modularity/module.key.dart @@ -0,0 +1,4 @@ +class ModuleKey { + ModuleKey(this.name); + final String name; +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/index.dart b/apps/flutter/core/lib/proxy/index.dart new file mode 100644 index 000000000..4cf9eb691 --- /dev/null +++ b/apps/flutter/core/lib/proxy/index.dart @@ -0,0 +1,2 @@ +export './volo/index.dart'; +export './lingyun/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/index.dart b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/index.dart new file mode 100644 index 000000000..ac325f2a9 --- /dev/null +++ b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/index.dart @@ -0,0 +1 @@ +export './mvc/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/index.dart b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/index.dart new file mode 100644 index 000000000..845ecc22b --- /dev/null +++ b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/index.dart @@ -0,0 +1 @@ +export './localization/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/localization/index.dart b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/localization/index.dart new file mode 100644 index 000000000..3c206e708 --- /dev/null +++ b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/localization/index.dart @@ -0,0 +1 @@ +export 'language.service.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/localization/language.service.dart b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/localization/language.service.dart new file mode 100644 index 000000000..90e50e2c1 --- /dev/null +++ b/apps/flutter/core/lib/proxy/lingyun/abp/asp-net-core/mvc/localization/language.service.dart @@ -0,0 +1,17 @@ +import 'package:core/models/abp.dto.dart'; +import 'package:core/proxy/volo/abp/localization/models.dart'; +import 'package:core/services/rest.service.dart'; +import 'package:get/get.dart'; + +class LanguageService { + RestService get _restService => Get.find(); + + Future> getList() { + return _restService.get('/api/abp/localization/languages') + .then((res) { + return ListResultDto( + items: (res.data['items'] as List).map((e) => LanguageInfo.fromJson(e)).toList(), + ); + }); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/lingyun/abp/index.dart b/apps/flutter/core/lib/proxy/lingyun/abp/index.dart new file mode 100644 index 000000000..66eeaee59 --- /dev/null +++ b/apps/flutter/core/lib/proxy/lingyun/abp/index.dart @@ -0,0 +1 @@ +export './asp-net-core/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/lingyun/index.dart b/apps/flutter/core/lib/proxy/lingyun/index.dart new file mode 100644 index 000000000..8e3fd405e --- /dev/null +++ b/apps/flutter/core/lib/proxy/lingyun/index.dart @@ -0,0 +1 @@ +export './abp/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/index.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/index.dart new file mode 100644 index 000000000..ac325f2a9 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/index.dart @@ -0,0 +1 @@ +export './mvc/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/api-exploring/abp-api-definition.service.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/api-exploring/abp-api-definition.service.dart new file mode 100644 index 000000000..6b41f3fe5 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/api-exploring/abp-api-definition.service.dart @@ -0,0 +1,15 @@ + +import 'package:core/proxy/volo/abp/http/modeling/index.dart'; +import 'package:core/services/rest.service.dart'; +import 'package:get/get.dart'; + +class AbpApiDefinitionService { + final RestService _restService = Get.find(); + + Future getByModel(ApplicationApiDescriptionModelRequestDto model) { + return _restService.get('/api/abp/api-definition', + queryParameters: { + 'includeTypes': model.includeTypes + }).then((res) => ApplicationApiDescriptionModel.fromJson(res.data)); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/api-exploring/index.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/api-exploring/index.dart new file mode 100644 index 000000000..02c56d8cd --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/api-exploring/index.dart @@ -0,0 +1 @@ +export 'abp-api-definition.service.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service.dart new file mode 100644 index 000000000..9336eeaa3 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service.dart @@ -0,0 +1,16 @@ +import 'package:core/proxy/volo/abp/asp-net-core/mvc/application-configurations/index.dart'; +import 'package:core/services/rest.service.dart'; +import 'package:get/get.dart'; + +class AbpApplicationConfigurationService { + RestService get _restService => Get.find(); + + Future get(ApplicationConfigurationRequestOptions options) { + return _restService.get('/api/abp/application-configuration', + queryParameters: { + 'includeLocalizationResources': options.includeLocalizationResources + }).then((res) { + return ApplicationConfigurationDto.fromJson(res.data); + }); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service.dart new file mode 100644 index 000000000..ecccaf64b --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service.dart @@ -0,0 +1,16 @@ +import 'package:get/get.dart'; + +import 'models.dart'; +import 'package:core/services/rest.service.dart'; + +class AbpApplicationLocalizationService { + RestService get _restService => Get.find(); + + Future get(ApplicationLocalizationRequestDto input) { + return _restService.get('/api/abp/application-localization', + queryParameters: { + 'cultureName': input.cultureName, + 'onlyDynamics': input.onlyDynamics + }).then((res) => ApplicationLocalizationDto.fromJson(res.data)); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/index.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/index.dart new file mode 100644 index 000000000..310ae7430 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/index.dart @@ -0,0 +1,4 @@ +export 'models.dart'; +export './object-extending/index.dart'; +export 'abp-application-configuration.service.dart'; +export 'abp-application-localization.service.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.dart new file mode 100644 index 000000000..4492ba29b --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.dart @@ -0,0 +1,321 @@ +import 'package:core/abstracts/copy.with.dart'; +import 'package:core/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/index.dart'; +import 'package:core/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/index.dart'; +import 'package:core/proxy/volo/abp/localization/index.dart'; +import 'package:core/proxy/volo/abp/models.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'models.g.dart'; + +@JsonSerializable() +class ApplicationConfigurationRequestOptions { + ApplicationConfigurationRequestOptions({ + this.includeLocalizationResources, + }); + bool? includeLocalizationResources = false; + + factory ApplicationConfigurationRequestOptions.fromJson(Map json) => _$ApplicationConfigurationRequestOptionsFromJson(json); + Map toJson() => _$ApplicationConfigurationRequestOptionsToJson(this); +} + +@JsonSerializable() +class ApplicationLocalizationRequestDto { + ApplicationLocalizationRequestDto({ + required this.cultureName, + this.onlyDynamics, + }); + late String cultureName; + bool? onlyDynamics = false; + + factory ApplicationLocalizationRequestDto.fromJson(Map json) => _$ApplicationLocalizationRequestDtoFromJson(json); + Map toJson() => _$ApplicationLocalizationRequestDtoToJson(this); +} + +@JsonSerializable() +class ApplicationConfigurationDto extends CloneObject { + ApplicationConfigurationDto({ + this.timing, + this.clock, + this.localization, + this.auth, + this.setting, + this.currentUser, + this.features, + this.globalFeatures, + this.multiTenancy, + this.currentTenant, + this.objectExtensions, + this.extraProperties, + }); + TimingDto? timing = TimingDto(); + ClockDto? clock = ClockDto(); + ApplicationLocalizationConfigurationDto? localization = ApplicationLocalizationConfigurationDto(); + ApplicationAuthConfigurationDto? auth; + ApplicationSettingConfigurationDto? setting; + CurrentUserDto? currentUser; + ApplicationFeatureConfigurationDto? features; + ApplicationGlobalFeatureConfigurationDto? globalFeatures; + MultiTenancyInfoDto? multiTenancy; + CurrentTenantDto? currentTenant; + ObjectExtensionsDto? objectExtensions; + Map? extraProperties; + + factory ApplicationConfigurationDto.fromJson(Map json) => _$ApplicationConfigurationDtoFromJson(json); + Map toJson() => _$ApplicationConfigurationDtoToJson(this); + + @override + ApplicationConfigurationDto clone() => ApplicationConfigurationDto( + timing: timing, + clock: clock, + localization: localization, + auth: auth, + setting: setting, + currentTenant: currentTenant, + currentUser: currentUser, + features: features, + globalFeatures: globalFeatures, + multiTenancy: multiTenancy, + objectExtensions: objectExtensions, + extraProperties: extraProperties, + ); +} + +@JsonSerializable() +class ApplicationLocalizationDto { + ApplicationLocalizationDto({ + this.resources, + }); + Map? resources = {}; + + factory ApplicationLocalizationDto.fromJson(Map json) => _$ApplicationLocalizationDtoFromJson(json); + Map toJson() => _$ApplicationLocalizationDtoToJson(this); +} + +@JsonSerializable() +class ApplicationGlobalFeatureConfigurationDto { + ApplicationGlobalFeatureConfigurationDto({ + this.enabledFeatures, + }); + List? enabledFeatures = []; + + factory ApplicationGlobalFeatureConfigurationDto.fromJson(Map json) => _$ApplicationGlobalFeatureConfigurationDtoFromJson(json); + Map toJson() => _$ApplicationGlobalFeatureConfigurationDtoToJson(this); +} + +@JsonSerializable() +class ApplicationFeatureConfigurationDto { + ApplicationFeatureConfigurationDto({ + this.values, + }); + Map? values = {}; + + factory ApplicationFeatureConfigurationDto.fromJson(Map json) => _$ApplicationFeatureConfigurationDtoFromJson(json); + Map toJson() => _$ApplicationFeatureConfigurationDtoToJson(this); +} + +@JsonSerializable() +class CurrentUserDto { + CurrentUserDto({ + this.isAuthenticated, + this.id, + this.tenantId, + this.impersonatorUserId, + this.impersonatorTenantId, + this.impersonatorUserName, + this.impersonatorTenantName, + this.userName, + this.name, + this.surName, + this.email, + this.emailVerified, + this.phoneNumber, + this.phoneNumberVerified, + this.roles, + }); + bool? isAuthenticated; + String? id; + String? tenantId; + String? impersonatorUserId; + String? impersonatorTenantId; + String? impersonatorUserName; + String? impersonatorTenantName; + String? userName; + String? name; + String? surName; + String? email; + bool? emailVerified; + String? phoneNumber; + bool? phoneNumberVerified; + List? roles = []; + + factory CurrentUserDto.fromJson(Map json) => _$CurrentUserDtoFromJson(json); + Map toJson() => _$CurrentUserDtoToJson(this); +} + +@JsonSerializable() +class ApplicationSettingConfigurationDto { + ApplicationSettingConfigurationDto({ + this.values, + }); + Map? values = {}; + + factory ApplicationSettingConfigurationDto.fromJson(Map json) => _$ApplicationSettingConfigurationDtoFromJson(json); + Map toJson() => _$ApplicationSettingConfigurationDtoToJson(this); +} + +@JsonSerializable() +class ApplicationAuthConfigurationDto { + ApplicationAuthConfigurationDto({ + this.grantedPolicies, + }); + Map? grantedPolicies = {}; + + factory ApplicationAuthConfigurationDto.fromJson(Map json) => _$ApplicationAuthConfigurationDtoFromJson(json); + Map toJson() => _$ApplicationAuthConfigurationDtoToJson(this); +} + +@JsonSerializable() +class ApplicationLocalizationConfigurationDto { + ApplicationLocalizationConfigurationDto({ + this.values, + this.resources, + this.languages, + this.currentCulture, + this.defaultResourceName, + this.languagesMap, + this.languageFilesMap, + }); + Map>? values = {}; + Map? resources = {}; + List? languages = []; + CurrentCultureDto? currentCulture = CurrentCultureDto(); + String? defaultResourceName = ''; + Map>? languagesMap = {}; + Map>? languageFilesMap = {}; + + factory ApplicationLocalizationConfigurationDto.fromJson(Map json) => _$ApplicationLocalizationConfigurationDtoFromJson(json); + Map toJson() => _$ApplicationLocalizationConfigurationDtoToJson(this); +} + + +@JsonSerializable() +class CurrentCultureDto { + CurrentCultureDto({ + this.name, + this.cultureName, + this.displayName, + this.englishName, + this.threeLetterIsoLanguageName, + this.twoLetterIsoLanguageName, + this.isRightToLeft, + this.nativeName, + this.dateTimeFormat, + }); + String? name; + String? cultureName; + String? displayName; + String? englishName; + String? threeLetterIsoLanguageName; + String? twoLetterIsoLanguageName; + bool? isRightToLeft; + String? nativeName; + DateTimeFormatDto? dateTimeFormat; + + factory CurrentCultureDto.fromJson(Map json) => _$CurrentCultureDtoFromJson(json); + Map toJson() => _$CurrentCultureDtoToJson(this); +} + +@JsonSerializable() +class DateTimeFormatDto { + DateTimeFormatDto({ + this.calendarAlgorithmType, + this.dateTimeFormatLong, + this.shortDatePattern, + this.fullDateTimePattern, + this.dateSeparator, + this.shortTimePattern, + this.longTimePattern, + }); + String? calendarAlgorithmType; + String? dateTimeFormatLong; + String? shortDatePattern; + String? fullDateTimePattern; + String? dateSeparator; + String? shortTimePattern; + String? longTimePattern; + + factory DateTimeFormatDto.fromJson(Map json) => _$DateTimeFormatDtoFromJson(json); + Map toJson() => _$DateTimeFormatDtoToJson(this); +} + +@JsonSerializable() +class ApplicationLocalizationResourceDto { + ApplicationLocalizationResourceDto({ + this.texts, + this.baseResources, + }); + Map? texts = {}; + List? baseResources = []; + + factory ApplicationLocalizationResourceDto.fromJson(Map json) => _$ApplicationLocalizationResourceDtoFromJson(json); + Map toJson() => _$ApplicationLocalizationResourceDtoToJson(this); +} + +@JsonSerializable() +class ClockDto { + ClockDto({ + this.kind, + }); + String? kind; + + factory ClockDto.fromJson(Map json) => _$ClockDtoFromJson(json); + Map toJson() => _$ClockDtoToJson(this); +} + +@JsonSerializable() +class TimingDto { + TimingDto({ + this.timeZone, + }); + TimeZone? timeZone; + + factory TimingDto.fromJson(Map json) => _$TimingDtoFromJson(json); + Map toJson() => _$TimingDtoToJson(this); +} + +@JsonSerializable() +class TimeZone { + TimeZone({ + this.iana, + this.windows, + }); + + IanaTimeZone? iana; + WindowsTimeZone? windows; + + factory TimeZone.fromJson(Map json) => _$TimeZoneFromJson(json); + Map toJson() => _$TimeZoneToJson(this); +} + +@JsonSerializable() +class WindowsTimeZone { + WindowsTimeZone({ + this.timeZoneId, + }); + + String? timeZoneId; + + factory WindowsTimeZone.fromJson(Map json) => _$WindowsTimeZoneFromJson(json); + Map toJson() => _$WindowsTimeZoneToJson(this); +} + +@JsonSerializable() +class IanaTimeZone { + IanaTimeZone({ + this.timeZoneName, + }); + String? timeZoneName; + + factory IanaTimeZone.fromJson(Map json) => _$IanaTimeZoneFromJson(json); + Map toJson() => _$IanaTimeZoneToJson(this); +} diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.g.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.g.dart new file mode 100644 index 000000000..12dfe14c4 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/models.g.dart @@ -0,0 +1,385 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ApplicationConfigurationRequestOptions + _$ApplicationConfigurationRequestOptionsFromJson( + Map json) => + ApplicationConfigurationRequestOptions( + includeLocalizationResources: + json['includeLocalizationResources'] as bool?, + ); + +Map _$ApplicationConfigurationRequestOptionsToJson( + ApplicationConfigurationRequestOptions instance) => + { + 'includeLocalizationResources': instance.includeLocalizationResources, + }; + +ApplicationLocalizationRequestDto _$ApplicationLocalizationRequestDtoFromJson( + Map json) => + ApplicationLocalizationRequestDto( + cultureName: json['cultureName'] as String, + onlyDynamics: json['onlyDynamics'] as bool?, + ); + +Map _$ApplicationLocalizationRequestDtoToJson( + ApplicationLocalizationRequestDto instance) => + { + 'cultureName': instance.cultureName, + 'onlyDynamics': instance.onlyDynamics, + }; + +ApplicationConfigurationDto _$ApplicationConfigurationDtoFromJson( + Map json) => + ApplicationConfigurationDto( + timing: json['timing'] == null + ? null + : TimingDto.fromJson(json['timing'] as Map), + clock: json['clock'] == null + ? null + : ClockDto.fromJson(json['clock'] as Map), + localization: json['localization'] == null + ? null + : ApplicationLocalizationConfigurationDto.fromJson( + json['localization'] as Map), + auth: json['auth'] == null + ? null + : ApplicationAuthConfigurationDto.fromJson( + json['auth'] as Map), + setting: json['setting'] == null + ? null + : ApplicationSettingConfigurationDto.fromJson( + json['setting'] as Map), + currentUser: json['currentUser'] == null + ? null + : CurrentUserDto.fromJson( + json['currentUser'] as Map), + features: json['features'] == null + ? null + : ApplicationFeatureConfigurationDto.fromJson( + json['features'] as Map), + globalFeatures: json['globalFeatures'] == null + ? null + : ApplicationGlobalFeatureConfigurationDto.fromJson( + json['globalFeatures'] as Map), + multiTenancy: json['multiTenancy'] == null + ? null + : MultiTenancyInfoDto.fromJson( + json['multiTenancy'] as Map), + currentTenant: json['currentTenant'] == null + ? null + : CurrentTenantDto.fromJson( + json['currentTenant'] as Map), + objectExtensions: json['objectExtensions'] == null + ? null + : ObjectExtensionsDto.fromJson( + json['objectExtensions'] as Map), + extraProperties: (json['extraProperties'] as Map?)?.map( + (k, e) => MapEntry(k, e as Object), + ), + ); + +Map _$ApplicationConfigurationDtoToJson( + ApplicationConfigurationDto instance) => + { + 'timing': instance.timing, + 'clock': instance.clock, + 'localization': instance.localization, + 'auth': instance.auth, + 'setting': instance.setting, + 'currentUser': instance.currentUser, + 'features': instance.features, + 'globalFeatures': instance.globalFeatures, + 'multiTenancy': instance.multiTenancy, + 'currentTenant': instance.currentTenant, + 'objectExtensions': instance.objectExtensions, + 'extraProperties': instance.extraProperties, + }; + +ApplicationLocalizationDto _$ApplicationLocalizationDtoFromJson( + Map json) => + ApplicationLocalizationDto( + resources: (json['resources'] as Map?)?.map( + (k, e) => MapEntry( + k, + ApplicationLocalizationResourceDto.fromJson( + e as Map)), + ), + ); + +Map _$ApplicationLocalizationDtoToJson( + ApplicationLocalizationDto instance) => + { + 'resources': instance.resources, + }; + +ApplicationGlobalFeatureConfigurationDto + _$ApplicationGlobalFeatureConfigurationDtoFromJson( + Map json) => + ApplicationGlobalFeatureConfigurationDto( + enabledFeatures: (json['enabledFeatures'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$ApplicationGlobalFeatureConfigurationDtoToJson( + ApplicationGlobalFeatureConfigurationDto instance) => + { + 'enabledFeatures': instance.enabledFeatures, + }; + +ApplicationFeatureConfigurationDto _$ApplicationFeatureConfigurationDtoFromJson( + Map json) => + ApplicationFeatureConfigurationDto( + values: (json['values'] as Map?)?.map( + (k, e) => MapEntry(k, e as String?), + ), + ); + +Map _$ApplicationFeatureConfigurationDtoToJson( + ApplicationFeatureConfigurationDto instance) => + { + 'values': instance.values, + }; + +CurrentUserDto _$CurrentUserDtoFromJson(Map json) => + CurrentUserDto( + isAuthenticated: json['isAuthenticated'] as bool?, + id: json['id'] as String?, + tenantId: json['tenantId'] as String?, + impersonatorUserId: json['impersonatorUserId'] as String?, + impersonatorTenantId: json['impersonatorTenantId'] as String?, + impersonatorUserName: json['impersonatorUserName'] as String?, + impersonatorTenantName: json['impersonatorTenantName'] as String?, + userName: json['userName'] as String?, + name: json['name'] as String?, + surName: json['surName'] as String?, + email: json['email'] as String?, + emailVerified: json['emailVerified'] as bool?, + phoneNumber: json['phoneNumber'] as String?, + phoneNumberVerified: json['phoneNumberVerified'] as bool?, + roles: + (json['roles'] as List?)?.map((e) => e as String).toList(), + ); + +Map _$CurrentUserDtoToJson(CurrentUserDto instance) => + { + 'isAuthenticated': instance.isAuthenticated, + 'id': instance.id, + 'tenantId': instance.tenantId, + 'impersonatorUserId': instance.impersonatorUserId, + 'impersonatorTenantId': instance.impersonatorTenantId, + 'impersonatorUserName': instance.impersonatorUserName, + 'impersonatorTenantName': instance.impersonatorTenantName, + 'userName': instance.userName, + 'name': instance.name, + 'surName': instance.surName, + 'email': instance.email, + 'emailVerified': instance.emailVerified, + 'phoneNumber': instance.phoneNumber, + 'phoneNumberVerified': instance.phoneNumberVerified, + 'roles': instance.roles, + }; + +ApplicationSettingConfigurationDto _$ApplicationSettingConfigurationDtoFromJson( + Map json) => + ApplicationSettingConfigurationDto( + values: (json['values'] as Map?)?.map( + (k, e) => MapEntry(k, e as String?), + ), + ); + +Map _$ApplicationSettingConfigurationDtoToJson( + ApplicationSettingConfigurationDto instance) => + { + 'values': instance.values, + }; + +ApplicationAuthConfigurationDto _$ApplicationAuthConfigurationDtoFromJson( + Map json) => + ApplicationAuthConfigurationDto( + grantedPolicies: (json['grantedPolicies'] as Map?)?.map( + (k, e) => MapEntry(k, e as bool), + ), + ); + +Map _$ApplicationAuthConfigurationDtoToJson( + ApplicationAuthConfigurationDto instance) => + { + 'grantedPolicies': instance.grantedPolicies, + }; + +ApplicationLocalizationConfigurationDto + _$ApplicationLocalizationConfigurationDtoFromJson( + Map json) => + ApplicationLocalizationConfigurationDto( + values: (json['values'] as Map?)?.map( + (k, e) => MapEntry(k, Map.from(e as Map)), + ), + resources: (json['resources'] as Map?)?.map( + (k, e) => MapEntry( + k, + ApplicationLocalizationResourceDto.fromJson( + e as Map)), + ), + languages: (json['languages'] as List?) + ?.map((e) => LanguageInfo.fromJson(e as Map)) + .toList(), + currentCulture: json['currentCulture'] == null + ? null + : CurrentCultureDto.fromJson( + json['currentCulture'] as Map), + defaultResourceName: json['defaultResourceName'] as String?, + languagesMap: (json['languagesMap'] as Map?)?.map( + (k, e) => MapEntry( + k, + (e as List) + .map((e) => StringValue.fromJson(e as Map)) + .toList()), + ), + languageFilesMap: + (json['languageFilesMap'] as Map?)?.map( + (k, e) => MapEntry( + k, + (e as List) + .map((e) => StringValue.fromJson(e as Map)) + .toList()), + ), + ); + +Map _$ApplicationLocalizationConfigurationDtoToJson( + ApplicationLocalizationConfigurationDto instance) => + { + 'values': instance.values, + 'resources': instance.resources, + 'languages': instance.languages, + 'currentCulture': instance.currentCulture, + 'defaultResourceName': instance.defaultResourceName, + 'languagesMap': instance.languagesMap, + 'languageFilesMap': instance.languageFilesMap, + }; + +CurrentCultureDto _$CurrentCultureDtoFromJson(Map json) => + CurrentCultureDto( + name: json['name'] as String?, + cultureName: json['cultureName'] as String?, + displayName: json['displayName'] as String?, + englishName: json['englishName'] as String?, + threeLetterIsoLanguageName: json['threeLetterIsoLanguageName'] as String?, + twoLetterIsoLanguageName: json['twoLetterIsoLanguageName'] as String?, + isRightToLeft: json['isRightToLeft'] as bool?, + nativeName: json['nativeName'] as String?, + dateTimeFormat: json['dateTimeFormat'] == null + ? null + : DateTimeFormatDto.fromJson( + json['dateTimeFormat'] as Map), + ); + +Map _$CurrentCultureDtoToJson(CurrentCultureDto instance) => + { + 'name': instance.name, + 'cultureName': instance.cultureName, + 'displayName': instance.displayName, + 'englishName': instance.englishName, + 'threeLetterIsoLanguageName': instance.threeLetterIsoLanguageName, + 'twoLetterIsoLanguageName': instance.twoLetterIsoLanguageName, + 'isRightToLeft': instance.isRightToLeft, + 'nativeName': instance.nativeName, + 'dateTimeFormat': instance.dateTimeFormat, + }; + +DateTimeFormatDto _$DateTimeFormatDtoFromJson(Map json) => + DateTimeFormatDto( + calendarAlgorithmType: json['calendarAlgorithmType'] as String?, + dateTimeFormatLong: json['dateTimeFormatLong'] as String?, + shortDatePattern: json['shortDatePattern'] as String?, + fullDateTimePattern: json['fullDateTimePattern'] as String?, + dateSeparator: json['dateSeparator'] as String?, + shortTimePattern: json['shortTimePattern'] as String?, + longTimePattern: json['longTimePattern'] as String?, + ); + +Map _$DateTimeFormatDtoToJson(DateTimeFormatDto instance) => + { + 'calendarAlgorithmType': instance.calendarAlgorithmType, + 'dateTimeFormatLong': instance.dateTimeFormatLong, + 'shortDatePattern': instance.shortDatePattern, + 'fullDateTimePattern': instance.fullDateTimePattern, + 'dateSeparator': instance.dateSeparator, + 'shortTimePattern': instance.shortTimePattern, + 'longTimePattern': instance.longTimePattern, + }; + +ApplicationLocalizationResourceDto _$ApplicationLocalizationResourceDtoFromJson( + Map json) => + ApplicationLocalizationResourceDto( + texts: (json['texts'] as Map?)?.map( + (k, e) => MapEntry(k, e as String?), + ), + baseResources: (json['baseResources'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$ApplicationLocalizationResourceDtoToJson( + ApplicationLocalizationResourceDto instance) => + { + 'texts': instance.texts, + 'baseResources': instance.baseResources, + }; + +ClockDto _$ClockDtoFromJson(Map json) => ClockDto( + kind: json['kind'] as String?, + ); + +Map _$ClockDtoToJson(ClockDto instance) => { + 'kind': instance.kind, + }; + +TimingDto _$TimingDtoFromJson(Map json) => TimingDto( + timeZone: json['timeZone'] == null + ? null + : TimeZone.fromJson(json['timeZone'] as Map), + ); + +Map _$TimingDtoToJson(TimingDto instance) => { + 'timeZone': instance.timeZone, + }; + +TimeZone _$TimeZoneFromJson(Map json) => TimeZone( + iana: json['iana'] == null + ? null + : IanaTimeZone.fromJson(json['iana'] as Map), + windows: json['windows'] == null + ? null + : WindowsTimeZone.fromJson(json['windows'] as Map), + ); + +Map _$TimeZoneToJson(TimeZone instance) => { + 'iana': instance.iana, + 'windows': instance.windows, + }; + +WindowsTimeZone _$WindowsTimeZoneFromJson(Map json) => + WindowsTimeZone( + timeZoneId: json['timeZoneId'] as String?, + ); + +Map _$WindowsTimeZoneToJson(WindowsTimeZone instance) => + { + 'timeZoneId': instance.timeZoneId, + }; + +IanaTimeZone _$IanaTimeZoneFromJson(Map json) => IanaTimeZone( + timeZoneName: json['timeZoneName'] as String?, + ); + +Map _$IanaTimeZoneToJson(IanaTimeZone instance) => + { + 'timeZoneName': instance.timeZoneName, + }; diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/index.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/index.dart new file mode 100644 index 000000000..0f453b509 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/index.dart @@ -0,0 +1 @@ +export 'models.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/models.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/models.dart new file mode 100644 index 000000000..b30163753 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/models.dart @@ -0,0 +1,225 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'models.g.dart'; + +@JsonSerializable() +class EntityExtensionDto { + EntityExtensionDto({ + this.properties, + this.configuration, + }); + Map? properties; + Map? configuration; + + factory EntityExtensionDto.fromJson(Map json) => _$EntityExtensionDtoFromJson(json); + Map toJson() => _$EntityExtensionDtoToJson(this); +} + +@JsonSerializable() +class ExtensionEnumDto { + ExtensionEnumDto({ + this.localizationResource, + this.fields, + }); + String? localizationResource; + Iterable? fields = []; + + factory ExtensionEnumDto.fromJson(Map json) => _$ExtensionEnumDtoFromJson(json); + Map toJson() => _$ExtensionEnumDtoToJson(this); +} + +@JsonSerializable() +class ExtensionEnumFieldDto { + ExtensionEnumFieldDto({ + this.name, + this.value, + }); + String? name; + dynamic value; + + factory ExtensionEnumFieldDto.fromJson(Map json) => _$ExtensionEnumFieldDtoFromJson(json); + Map toJson() => _$ExtensionEnumFieldDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyApiCreateDto { + ExtensionPropertyApiCreateDto({ + required this.isAvailable, + }); + final bool isAvailable; + + factory ExtensionPropertyApiCreateDto.fromJson(Map json) => _$ExtensionPropertyApiCreateDtoFromJson(json); + Map toJson() => _$ExtensionPropertyApiCreateDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyApiDto { + ExtensionPropertyApiDto({ + this.onGet, + this.onCreate, + this.onUpdate, + }); + ExtensionPropertyApiGetDto? onGet; + ExtensionPropertyApiCreateDto? onCreate; + ExtensionPropertyApiUpdateDto? onUpdate; + + factory ExtensionPropertyApiDto.fromJson(Map json) => _$ExtensionPropertyApiDtoFromJson(json); + Map toJson() => _$ExtensionPropertyApiDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyApiGetDto { + ExtensionPropertyApiGetDto({ + required this.isAvailable, + }); + final bool isAvailable; + + factory ExtensionPropertyApiGetDto.fromJson(Map json) => _$ExtensionPropertyApiGetDtoFromJson(json); + Map toJson() => _$ExtensionPropertyApiGetDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyApiUpdateDto { + ExtensionPropertyApiUpdateDto({ + required this.isAvailable, + }); + final bool isAvailable; + + factory ExtensionPropertyApiUpdateDto.fromJson(Map json) => _$ExtensionPropertyApiUpdateDtoFromJson(json); + Map toJson() => _$ExtensionPropertyApiUpdateDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyAttributeDto { + ExtensionPropertyAttributeDto({ + this.typeSimple, + this.config, + }); + String? typeSimple; + Map? config; + + factory ExtensionPropertyAttributeDto.fromJson(Map json) => _$ExtensionPropertyAttributeDtoFromJson(json); + Map toJson() => _$ExtensionPropertyAttributeDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyDto { + ExtensionPropertyDto({ + this.type, + this.typeSimple, + this.displayName, + this.api, + this.ui, + this.attributes, + this.configuration, + this.defaultValue, + }); + String? type; + String? typeSimple; + LocalizableStringDto? displayName; + ExtensionPropertyApiDto? api; + ExtensionPropertyUiDto? ui; + Iterable? attributes = []; + Map? configuration; + dynamic defaultValue; + + factory ExtensionPropertyDto.fromJson(Map json) => _$ExtensionPropertyDtoFromJson(json); + Map toJson() => _$ExtensionPropertyDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyUiDto { + ExtensionPropertyUiDto({ + this.onTable, + this.onCreateForm, + this.onEditForm, + this.lookup, + }); + ExtensionPropertyUiTableDto? onTable; + ExtensionPropertyUiFormDto? onCreateForm; + ExtensionPropertyUiFormDto? onEditForm; + ExtensionPropertyUiLookupDto? lookup; + + factory ExtensionPropertyUiDto.fromJson(Map json) => _$ExtensionPropertyUiDtoFromJson(json); + Map toJson() => _$ExtensionPropertyUiDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyUiFormDto { + ExtensionPropertyUiFormDto({ + required this.isAvailable, + }); + final bool isAvailable; + + factory ExtensionPropertyUiFormDto.fromJson(Map json) => _$ExtensionPropertyUiFormDtoFromJson(json); + Map toJson() => _$ExtensionPropertyUiFormDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyUiLookupDto { + ExtensionPropertyUiLookupDto({ + this.url, + this.resultListPropertyName, + this.displayPropertyName, + this.valuePropertyName, + this.filterParamName, + }); + String? url; + String? resultListPropertyName; + String? displayPropertyName; + String? valuePropertyName; + String? filterParamName; + + factory ExtensionPropertyUiLookupDto.fromJson(Map json) => _$ExtensionPropertyUiLookupDtoFromJson(json); + Map toJson() => _$ExtensionPropertyUiLookupDtoToJson(this); +} + +@JsonSerializable() +class ExtensionPropertyUiTableDto { + ExtensionPropertyUiTableDto({ + required this.isAvailable, + }); + final bool isAvailable; + + factory ExtensionPropertyUiTableDto.fromJson(Map json) => _$ExtensionPropertyUiTableDtoFromJson(json); + Map toJson() => _$ExtensionPropertyUiTableDtoToJson(this); +} + +@JsonSerializable() +class LocalizableStringDto { + LocalizableStringDto({ + this.name, + this.resource, + }); + String? name; + String? resource; + + factory LocalizableStringDto.fromJson(Map json) => _$LocalizableStringDtoFromJson(json); + Map toJson() => _$LocalizableStringDtoToJson(this); +} + +@JsonSerializable() +class ModuleExtensionDto { + ModuleExtensionDto({ + this.entities, + this.configuration, + }); + Map? entities; + Map? configuration; + + factory ModuleExtensionDto.fromJson(Map json) => _$ModuleExtensionDtoFromJson(json); + Map toJson() => _$ModuleExtensionDtoToJson(this); +} + +@JsonSerializable() +class ObjectExtensionsDto { + ObjectExtensionsDto({ + this.modules, + this.enums, + }); + Map? modules; + Map? enums; + + factory ObjectExtensionsDto.fromJson(Map json) => _$ObjectExtensionsDtoFromJson(json); + Map toJson() => _$ObjectExtensionsDtoToJson(this); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/models.g.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/models.g.dart new file mode 100644 index 000000000..67a0225b9 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/application-configurations/object-extending/models.g.dart @@ -0,0 +1,281 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +EntityExtensionDto _$EntityExtensionDtoFromJson(Map json) => + EntityExtensionDto( + properties: (json['properties'] as Map?)?.map( + (k, e) => MapEntry( + k, ExtensionPropertyDto.fromJson(e as Map)), + ), + configuration: json['configuration'] as Map?, + ); + +Map _$EntityExtensionDtoToJson(EntityExtensionDto instance) => + { + 'properties': instance.properties, + 'configuration': instance.configuration, + }; + +ExtensionEnumDto _$ExtensionEnumDtoFromJson(Map json) => + ExtensionEnumDto( + localizationResource: json['localizationResource'] as String?, + fields: (json['fields'] as List?)?.map( + (e) => ExtensionEnumFieldDto.fromJson(e as Map)), + ); + +Map _$ExtensionEnumDtoToJson(ExtensionEnumDto instance) => + { + 'localizationResource': instance.localizationResource, + 'fields': instance.fields?.toList(), + }; + +ExtensionEnumFieldDto _$ExtensionEnumFieldDtoFromJson( + Map json) => + ExtensionEnumFieldDto( + name: json['name'] as String?, + value: json['value'], + ); + +Map _$ExtensionEnumFieldDtoToJson( + ExtensionEnumFieldDto instance) => + { + 'name': instance.name, + 'value': instance.value, + }; + +ExtensionPropertyApiCreateDto _$ExtensionPropertyApiCreateDtoFromJson( + Map json) => + ExtensionPropertyApiCreateDto( + isAvailable: json['isAvailable'] as bool, + ); + +Map _$ExtensionPropertyApiCreateDtoToJson( + ExtensionPropertyApiCreateDto instance) => + { + 'isAvailable': instance.isAvailable, + }; + +ExtensionPropertyApiDto _$ExtensionPropertyApiDtoFromJson( + Map json) => + ExtensionPropertyApiDto( + onGet: json['onGet'] == null + ? null + : ExtensionPropertyApiGetDto.fromJson( + json['onGet'] as Map), + onCreate: json['onCreate'] == null + ? null + : ExtensionPropertyApiCreateDto.fromJson( + json['onCreate'] as Map), + onUpdate: json['onUpdate'] == null + ? null + : ExtensionPropertyApiUpdateDto.fromJson( + json['onUpdate'] as Map), + ); + +Map _$ExtensionPropertyApiDtoToJson( + ExtensionPropertyApiDto instance) => + { + 'onGet': instance.onGet, + 'onCreate': instance.onCreate, + 'onUpdate': instance.onUpdate, + }; + +ExtensionPropertyApiGetDto _$ExtensionPropertyApiGetDtoFromJson( + Map json) => + ExtensionPropertyApiGetDto( + isAvailable: json['isAvailable'] as bool, + ); + +Map _$ExtensionPropertyApiGetDtoToJson( + ExtensionPropertyApiGetDto instance) => + { + 'isAvailable': instance.isAvailable, + }; + +ExtensionPropertyApiUpdateDto _$ExtensionPropertyApiUpdateDtoFromJson( + Map json) => + ExtensionPropertyApiUpdateDto( + isAvailable: json['isAvailable'] as bool, + ); + +Map _$ExtensionPropertyApiUpdateDtoToJson( + ExtensionPropertyApiUpdateDto instance) => + { + 'isAvailable': instance.isAvailable, + }; + +ExtensionPropertyAttributeDto _$ExtensionPropertyAttributeDtoFromJson( + Map json) => + ExtensionPropertyAttributeDto( + typeSimple: json['typeSimple'] as String?, + config: json['config'] as Map?, + ); + +Map _$ExtensionPropertyAttributeDtoToJson( + ExtensionPropertyAttributeDto instance) => + { + 'typeSimple': instance.typeSimple, + 'config': instance.config, + }; + +ExtensionPropertyDto _$ExtensionPropertyDtoFromJson( + Map json) => + ExtensionPropertyDto( + type: json['type'] as String?, + typeSimple: json['typeSimple'] as String?, + displayName: json['displayName'] == null + ? null + : LocalizableStringDto.fromJson( + json['displayName'] as Map), + api: json['api'] == null + ? null + : ExtensionPropertyApiDto.fromJson( + json['api'] as Map), + ui: json['ui'] == null + ? null + : ExtensionPropertyUiDto.fromJson(json['ui'] as Map), + attributes: (json['attributes'] as List?)?.map((e) => + ExtensionPropertyAttributeDto.fromJson(e as Map)), + configuration: json['configuration'] as Map?, + defaultValue: json['defaultValue'], + ); + +Map _$ExtensionPropertyDtoToJson( + ExtensionPropertyDto instance) => + { + 'type': instance.type, + 'typeSimple': instance.typeSimple, + 'displayName': instance.displayName, + 'api': instance.api, + 'ui': instance.ui, + 'attributes': instance.attributes?.toList(), + 'configuration': instance.configuration, + 'defaultValue': instance.defaultValue, + }; + +ExtensionPropertyUiDto _$ExtensionPropertyUiDtoFromJson( + Map json) => + ExtensionPropertyUiDto( + onTable: json['onTable'] == null + ? null + : ExtensionPropertyUiTableDto.fromJson( + json['onTable'] as Map), + onCreateForm: json['onCreateForm'] == null + ? null + : ExtensionPropertyUiFormDto.fromJson( + json['onCreateForm'] as Map), + onEditForm: json['onEditForm'] == null + ? null + : ExtensionPropertyUiFormDto.fromJson( + json['onEditForm'] as Map), + lookup: json['lookup'] == null + ? null + : ExtensionPropertyUiLookupDto.fromJson( + json['lookup'] as Map), + ); + +Map _$ExtensionPropertyUiDtoToJson( + ExtensionPropertyUiDto instance) => + { + 'onTable': instance.onTable, + 'onCreateForm': instance.onCreateForm, + 'onEditForm': instance.onEditForm, + 'lookup': instance.lookup, + }; + +ExtensionPropertyUiFormDto _$ExtensionPropertyUiFormDtoFromJson( + Map json) => + ExtensionPropertyUiFormDto( + isAvailable: json['isAvailable'] as bool, + ); + +Map _$ExtensionPropertyUiFormDtoToJson( + ExtensionPropertyUiFormDto instance) => + { + 'isAvailable': instance.isAvailable, + }; + +ExtensionPropertyUiLookupDto _$ExtensionPropertyUiLookupDtoFromJson( + Map json) => + ExtensionPropertyUiLookupDto( + url: json['url'] as String?, + resultListPropertyName: json['resultListPropertyName'] as String?, + displayPropertyName: json['displayPropertyName'] as String?, + valuePropertyName: json['valuePropertyName'] as String?, + filterParamName: json['filterParamName'] as String?, + ); + +Map _$ExtensionPropertyUiLookupDtoToJson( + ExtensionPropertyUiLookupDto instance) => + { + 'url': instance.url, + 'resultListPropertyName': instance.resultListPropertyName, + 'displayPropertyName': instance.displayPropertyName, + 'valuePropertyName': instance.valuePropertyName, + 'filterParamName': instance.filterParamName, + }; + +ExtensionPropertyUiTableDto _$ExtensionPropertyUiTableDtoFromJson( + Map json) => + ExtensionPropertyUiTableDto( + isAvailable: json['isAvailable'] as bool, + ); + +Map _$ExtensionPropertyUiTableDtoToJson( + ExtensionPropertyUiTableDto instance) => + { + 'isAvailable': instance.isAvailable, + }; + +LocalizableStringDto _$LocalizableStringDtoFromJson( + Map json) => + LocalizableStringDto( + name: json['name'] as String?, + resource: json['resource'] as String?, + ); + +Map _$LocalizableStringDtoToJson( + LocalizableStringDto instance) => + { + 'name': instance.name, + 'resource': instance.resource, + }; + +ModuleExtensionDto _$ModuleExtensionDtoFromJson(Map json) => + ModuleExtensionDto( + entities: (json['entities'] as Map?)?.map( + (k, e) => + MapEntry(k, EntityExtensionDto.fromJson(e as Map)), + ), + configuration: json['configuration'] as Map?, + ); + +Map _$ModuleExtensionDtoToJson(ModuleExtensionDto instance) => + { + 'entities': instance.entities, + 'configuration': instance.configuration, + }; + +ObjectExtensionsDto _$ObjectExtensionsDtoFromJson(Map json) => + ObjectExtensionsDto( + modules: (json['modules'] as Map?)?.map( + (k, e) => + MapEntry(k, ModuleExtensionDto.fromJson(e as Map)), + ), + enums: (json['enums'] as Map?)?.map( + (k, e) => + MapEntry(k, ExtensionEnumDto.fromJson(e as Map)), + ), + ); + +Map _$ObjectExtensionsDtoToJson( + ObjectExtensionsDto instance) => + { + 'modules': instance.modules, + 'enums': instance.enums, + }; diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/index.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/index.dart new file mode 100644 index 000000000..6eb46e992 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/index.dart @@ -0,0 +1,3 @@ +export 'api-exploring/index.dart'; +export 'application-configurations/index.dart'; +export 'multi-tenancy/index.dart'; diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/abp-tenant.service.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/abp-tenant.service.dart new file mode 100644 index 000000000..6f69cbb5b --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/abp-tenant.service.dart @@ -0,0 +1,18 @@ +import 'package:core/services/rest.service.dart'; +import 'package:get/get.dart'; + +import 'models.dart'; + +class AbpTenantService { + RestService get _restService => Get.find(); + + Future findTenantById(String id) { + return _restService.get('/api/abp/multi-tenancy/tenants/by-id/$id') + .then((res) => FindTenantResultDto.fromJson(res.data)); + } + + Future findTenantByName(String name) { + return _restService.get('/api/abp/multi-tenancy/tenants/by-name/$name') + .then((res) => FindTenantResultDto.fromJson(res.data)); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/index.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/index.dart new file mode 100644 index 000000000..d78500993 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/index.dart @@ -0,0 +1,2 @@ +export 'models.dart'; +export 'abp-tenant.service.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models.dart new file mode 100644 index 000000000..b97169b4c --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models.dart @@ -0,0 +1,46 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'models.g.dart'; + +@JsonSerializable() +class FindTenantResultDto { + FindTenantResultDto({ + this.tenantId, + this.name, + required this.success, + required this.isActive, + }); + late bool success; + String? tenantId; + String? name; + late bool isActive; + + factory FindTenantResultDto.fromJson(Map json) => _$FindTenantResultDtoFromJson(json); + Map toJson() => _$FindTenantResultDtoToJson(this); +} + +@JsonSerializable() +class CurrentTenantDto { + CurrentTenantDto({ + this.id, + this.name, + this.isAvailable, + }); + String? id; + String? name; + bool? isAvailable; + + factory CurrentTenantDto.fromJson(Map json) => _$CurrentTenantDtoFromJson(json); + Map toJson() => _$CurrentTenantDtoToJson(this); +} + +@JsonSerializable() +class MultiTenancyInfoDto { + MultiTenancyInfoDto({ + required this.isEnabled, + }); + late bool isEnabled; + + factory MultiTenancyInfoDto.fromJson(Map json) => _$MultiTenancyInfoDtoFromJson(json); + Map toJson() => _$MultiTenancyInfoDtoToJson(this); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models.g.dart b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models.g.dart new file mode 100644 index 000000000..5cbf4be3b --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/asp-net-core/mvc/multi-tenancy/models.g.dart @@ -0,0 +1,49 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FindTenantResultDto _$FindTenantResultDtoFromJson(Map json) => + FindTenantResultDto( + tenantId: json['tenantId'] as String?, + name: json['name'] as String?, + success: json['success'] as bool, + isActive: json['isActive'] as bool, + ); + +Map _$FindTenantResultDtoToJson( + FindTenantResultDto instance) => + { + 'success': instance.success, + 'tenantId': instance.tenantId, + 'name': instance.name, + 'isActive': instance.isActive, + }; + +CurrentTenantDto _$CurrentTenantDtoFromJson(Map json) => + CurrentTenantDto( + id: json['id'] as String?, + name: json['name'] as String?, + isAvailable: json['isAvailable'] as bool?, + ); + +Map _$CurrentTenantDtoToJson(CurrentTenantDto instance) => + { + 'id': instance.id, + 'name': instance.name, + 'isAvailable': instance.isAvailable, + }; + +MultiTenancyInfoDto _$MultiTenancyInfoDtoFromJson(Map json) => + MultiTenancyInfoDto( + isEnabled: json['isEnabled'] as bool, + ); + +Map _$MultiTenancyInfoDtoToJson( + MultiTenancyInfoDto instance) => + { + 'isEnabled': instance.isEnabled, + }; diff --git a/apps/flutter/core/lib/proxy/volo/abp/http/index.dart b/apps/flutter/core/lib/proxy/volo/abp/http/index.dart new file mode 100644 index 000000000..b0f27c8ff --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/http/index.dart @@ -0,0 +1 @@ +export './modeling/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/http/modeling/index.dart b/apps/flutter/core/lib/proxy/volo/abp/http/modeling/index.dart new file mode 100644 index 000000000..0f453b509 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/http/modeling/index.dart @@ -0,0 +1 @@ +export 'models.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/http/modeling/models.dart b/apps/flutter/core/lib/proxy/volo/abp/http/modeling/models.dart new file mode 100644 index 000000000..c968bad9c --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/http/modeling/models.dart @@ -0,0 +1,239 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'models.g.dart'; + +@JsonSerializable() +class ActionApiDescriptionModel { + ActionApiDescriptionModel({ + this.uniqueName, + this.name, + this.httpMethod, + this.url, + this.supportedVersions, + this.parametersOnMethod, + this.parameters, + this.returnValue, + this.allowAnonymous, + this.implementFrom, + }); + String? uniqueName; + String? name; + String? httpMethod; + String? url; + Iterable? supportedVersions; + Iterable? parametersOnMethod = []; + Iterable? parameters = []; + ReturnValueApiDescriptionModel? returnValue; + bool? allowAnonymous; + String? implementFrom; + + factory ActionApiDescriptionModel.fromJson(Map json) => _$ActionApiDescriptionModelFromJson(json); + Map toJson() => _$ActionApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class MethodParameterApiDescriptionModel { + MethodParameterApiDescriptionModel({ + this.name, + this.typeAsString, + this.type, + this.typeSimple, + this.isOptional, + this.defaultValue, + }); + String? name; + String? typeAsString; + String? type; + String? typeSimple; + bool? isOptional; + dynamic defaultValue; + + factory MethodParameterApiDescriptionModel.fromJson(Map json) => _$MethodParameterApiDescriptionModelFromJson(json); + Map toJson() => _$MethodParameterApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class ParameterApiDescriptionModel { + ParameterApiDescriptionModel({ + this.name, + this.nameOnMethod, + this.jsonName, + this.type, + this.typeSimple, + this.isOptional, + this.defaultValue, + this.constraintTypes, + this.bindingSourceId, + this.descriptorName, + }); + String? nameOnMethod; + String? name; + String? jsonName; + String? type; + String? typeSimple; + bool? isOptional = false; + dynamic defaultValue; + Iterable? constraintTypes = []; + String? bindingSourceId; + String? descriptorName; + + factory ParameterApiDescriptionModel.fromJson(Map json) => _$ParameterApiDescriptionModelFromJson(json); + Map toJson() => _$ParameterApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class ReturnValueApiDescriptionModel { + ReturnValueApiDescriptionModel({ + this.type, + this.typeSimple, + }); + String? type; + String? typeSimple; + + factory ReturnValueApiDescriptionModel.fromJson(Map json) => _$ReturnValueApiDescriptionModelFromJson(json); + Map toJson() => _$ReturnValueApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class PropertyApiDescriptionModel { + PropertyApiDescriptionModel({ + this.name, + this.jsonName, + this.type, + this.typeSimple, + this.isRequired, + this.minLength, + this.maxLength, + this.minimum, + this.maximum, + this.regex, + }); + String? name; + String? jsonName; + String? type; + String? typeSimple; + bool? isRequired = false; + int? minLength; + int? maxLength; + String? minimum; + String? maximum; + String? regex; + + factory PropertyApiDescriptionModel.fromJson(Map json) => _$PropertyApiDescriptionModelFromJson(json); + Map toJson() => _$PropertyApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class TypeApiDescriptionModel { + TypeApiDescriptionModel({ + this.baseType, + this.isEnum, + this.enumNames, + this.enumValues, + this.genericArguments, + this.properties, + }); + String? baseType; + bool? isEnum = false; + Iterable? enumNames = []; + Iterable? enumValues = []; + Iterable? genericArguments = []; + Iterable? properties = []; + + factory TypeApiDescriptionModel.fromJson(Map json) => _$TypeApiDescriptionModelFromJson(json); + Map toJson() => _$TypeApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class InterfaceMethodApiDescriptionModel { + InterfaceMethodApiDescriptionModel({ + this.name, + this.parametersOnMethod, + this.returnValue, + }); + String? name; + Iterable? parametersOnMethod = []; + ReturnValueApiDescriptionModel? returnValue = {} as ReturnValueApiDescriptionModel; + + factory InterfaceMethodApiDescriptionModel.fromJson(Map json) => _$InterfaceMethodApiDescriptionModelFromJson(json); + Map toJson() => _$InterfaceMethodApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class ControllerInterfaceApiDescriptionModel { + ControllerInterfaceApiDescriptionModel({ + this.type, + this.name, + this.methods, + }); + String? type; + String? name; + Iterable? methods = []; + + factory ControllerInterfaceApiDescriptionModel.fromJson(Map json) => _$ControllerInterfaceApiDescriptionModelFromJson(json); + Map toJson() => _$ControllerInterfaceApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class ApplicationApiDescriptionModelRequestDto { + ApplicationApiDescriptionModelRequestDto({ + this.includeTypes, + }); + bool? includeTypes = false; + + factory ApplicationApiDescriptionModelRequestDto.fromJson(Map json) => _$ApplicationApiDescriptionModelRequestDtoFromJson(json); + Map toJson() => _$ApplicationApiDescriptionModelRequestDtoToJson(this); +} + +@JsonSerializable() +class ModuleApiDescriptionModel { + ModuleApiDescriptionModel({ + this.rootPath, + this.remoteServiceName, + this.controllers, + }); + String? rootPath; + String? remoteServiceName; + Map? controllers = {}; + + factory ModuleApiDescriptionModel.fromJson(Map json) => _$ModuleApiDescriptionModelFromJson(json); + Map toJson() => _$ModuleApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class ControllerApiDescriptionModel { + ControllerApiDescriptionModel({ + this.controllerName, + this.controllerGroupName, + this.isRemoteService, + this.isIntegrationService, + this.apiVersion, + this.type, + this.interfaces, + this.actions, + }); + String? controllerName; + String? controllerGroupName; + bool? isRemoteService = true; + bool? isIntegrationService = false; + String? apiVersion; + String? type; + Iterable? interfaces = []; + Map? actions = {}; + + factory ControllerApiDescriptionModel.fromJson(Map json) => _$ControllerApiDescriptionModelFromJson(json); + Map toJson() => _$ControllerApiDescriptionModelToJson(this); +} + +@JsonSerializable() +class ApplicationApiDescriptionModel { + ApplicationApiDescriptionModel({ + this.modules, + this.types, + }); + Map? modules = {}; + Map? types = {}; + + factory ApplicationApiDescriptionModel.fromJson(Map json) => _$ApplicationApiDescriptionModelFromJson(json); + Map toJson() => _$ApplicationApiDescriptionModelToJson(this); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/http/modeling/models.g.dart b/apps/flutter/core/lib/proxy/volo/abp/http/modeling/models.g.dart new file mode 100644 index 000000000..a9cc57d13 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/http/modeling/models.g.dart @@ -0,0 +1,288 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ActionApiDescriptionModel _$ActionApiDescriptionModelFromJson( + Map json) => + ActionApiDescriptionModel( + uniqueName: json['uniqueName'] as String?, + name: json['name'] as String?, + httpMethod: json['httpMethod'] as String?, + url: json['url'] as String?, + supportedVersions: (json['supportedVersions'] as List?) + ?.map((e) => e as String), + parametersOnMethod: (json['parametersOnMethod'] as List?)?.map( + (e) => MethodParameterApiDescriptionModel.fromJson( + e as Map)), + parameters: (json['parameters'] as List?)?.map((e) => + ParameterApiDescriptionModel.fromJson(e as Map)), + returnValue: json['returnValue'] == null + ? null + : ReturnValueApiDescriptionModel.fromJson( + json['returnValue'] as Map), + allowAnonymous: json['allowAnonymous'] as bool?, + implementFrom: json['implementFrom'] as String?, + ); + +Map _$ActionApiDescriptionModelToJson( + ActionApiDescriptionModel instance) => + { + 'uniqueName': instance.uniqueName, + 'name': instance.name, + 'httpMethod': instance.httpMethod, + 'url': instance.url, + 'supportedVersions': instance.supportedVersions?.toList(), + 'parametersOnMethod': instance.parametersOnMethod?.toList(), + 'parameters': instance.parameters?.toList(), + 'returnValue': instance.returnValue, + 'allowAnonymous': instance.allowAnonymous, + 'implementFrom': instance.implementFrom, + }; + +MethodParameterApiDescriptionModel _$MethodParameterApiDescriptionModelFromJson( + Map json) => + MethodParameterApiDescriptionModel( + name: json['name'] as String?, + typeAsString: json['typeAsString'] as String?, + type: json['type'] as String?, + typeSimple: json['typeSimple'] as String?, + isOptional: json['isOptional'] as bool?, + defaultValue: json['defaultValue'], + ); + +Map _$MethodParameterApiDescriptionModelToJson( + MethodParameterApiDescriptionModel instance) => + { + 'name': instance.name, + 'typeAsString': instance.typeAsString, + 'type': instance.type, + 'typeSimple': instance.typeSimple, + 'isOptional': instance.isOptional, + 'defaultValue': instance.defaultValue, + }; + +ParameterApiDescriptionModel _$ParameterApiDescriptionModelFromJson( + Map json) => + ParameterApiDescriptionModel( + name: json['name'] as String?, + nameOnMethod: json['nameOnMethod'] as String?, + jsonName: json['jsonName'] as String?, + type: json['type'] as String?, + typeSimple: json['typeSimple'] as String?, + isOptional: json['isOptional'] as bool?, + defaultValue: json['defaultValue'], + constraintTypes: + (json['constraintTypes'] as List?)?.map((e) => e as String), + bindingSourceId: json['bindingSourceId'] as String?, + descriptorName: json['descriptorName'] as String?, + ); + +Map _$ParameterApiDescriptionModelToJson( + ParameterApiDescriptionModel instance) => + { + 'nameOnMethod': instance.nameOnMethod, + 'name': instance.name, + 'jsonName': instance.jsonName, + 'type': instance.type, + 'typeSimple': instance.typeSimple, + 'isOptional': instance.isOptional, + 'defaultValue': instance.defaultValue, + 'constraintTypes': instance.constraintTypes?.toList(), + 'bindingSourceId': instance.bindingSourceId, + 'descriptorName': instance.descriptorName, + }; + +ReturnValueApiDescriptionModel _$ReturnValueApiDescriptionModelFromJson( + Map json) => + ReturnValueApiDescriptionModel( + type: json['type'] as String?, + typeSimple: json['typeSimple'] as String?, + ); + +Map _$ReturnValueApiDescriptionModelToJson( + ReturnValueApiDescriptionModel instance) => + { + 'type': instance.type, + 'typeSimple': instance.typeSimple, + }; + +PropertyApiDescriptionModel _$PropertyApiDescriptionModelFromJson( + Map json) => + PropertyApiDescriptionModel( + name: json['name'] as String?, + jsonName: json['jsonName'] as String?, + type: json['type'] as String?, + typeSimple: json['typeSimple'] as String?, + isRequired: json['isRequired'] as bool?, + minLength: json['minLength'] as int?, + maxLength: json['maxLength'] as int?, + minimum: json['minimum'] as String?, + maximum: json['maximum'] as String?, + regex: json['regex'] as String?, + ); + +Map _$PropertyApiDescriptionModelToJson( + PropertyApiDescriptionModel instance) => + { + 'name': instance.name, + 'jsonName': instance.jsonName, + 'type': instance.type, + 'typeSimple': instance.typeSimple, + 'isRequired': instance.isRequired, + 'minLength': instance.minLength, + 'maxLength': instance.maxLength, + 'minimum': instance.minimum, + 'maximum': instance.maximum, + 'regex': instance.regex, + }; + +TypeApiDescriptionModel _$TypeApiDescriptionModelFromJson( + Map json) => + TypeApiDescriptionModel( + baseType: json['baseType'] as String?, + isEnum: json['isEnum'] as bool?, + enumNames: (json['enumNames'] as List?)?.map((e) => e as String), + enumValues: json['enumValues'] as List?, + genericArguments: + (json['genericArguments'] as List?)?.map((e) => e as String), + properties: (json['properties'] as List?)?.map((e) => + PropertyApiDescriptionModel.fromJson(e as Map)), + ); + +Map _$TypeApiDescriptionModelToJson( + TypeApiDescriptionModel instance) => + { + 'baseType': instance.baseType, + 'isEnum': instance.isEnum, + 'enumNames': instance.enumNames?.toList(), + 'enumValues': instance.enumValues?.toList(), + 'genericArguments': instance.genericArguments?.toList(), + 'properties': instance.properties?.toList(), + }; + +InterfaceMethodApiDescriptionModel _$InterfaceMethodApiDescriptionModelFromJson( + Map json) => + InterfaceMethodApiDescriptionModel( + name: json['name'] as String?, + parametersOnMethod: (json['parametersOnMethod'] as List?)?.map( + (e) => MethodParameterApiDescriptionModel.fromJson( + e as Map)), + returnValue: json['returnValue'] == null + ? null + : ReturnValueApiDescriptionModel.fromJson( + json['returnValue'] as Map), + ); + +Map _$InterfaceMethodApiDescriptionModelToJson( + InterfaceMethodApiDescriptionModel instance) => + { + 'name': instance.name, + 'parametersOnMethod': instance.parametersOnMethod?.toList(), + 'returnValue': instance.returnValue, + }; + +ControllerInterfaceApiDescriptionModel + _$ControllerInterfaceApiDescriptionModelFromJson( + Map json) => + ControllerInterfaceApiDescriptionModel( + type: json['type'] as String?, + name: json['name'] as String?, + methods: (json['methods'] as List?)?.map((e) => + InterfaceMethodApiDescriptionModel.fromJson( + e as Map)), + ); + +Map _$ControllerInterfaceApiDescriptionModelToJson( + ControllerInterfaceApiDescriptionModel instance) => + { + 'type': instance.type, + 'name': instance.name, + 'methods': instance.methods?.toList(), + }; + +ApplicationApiDescriptionModelRequestDto + _$ApplicationApiDescriptionModelRequestDtoFromJson( + Map json) => + ApplicationApiDescriptionModelRequestDto( + includeTypes: json['includeTypes'] as bool?, + ); + +Map _$ApplicationApiDescriptionModelRequestDtoToJson( + ApplicationApiDescriptionModelRequestDto instance) => + { + 'includeTypes': instance.includeTypes, + }; + +ModuleApiDescriptionModel _$ModuleApiDescriptionModelFromJson( + Map json) => + ModuleApiDescriptionModel( + rootPath: json['rootPath'] as String?, + remoteServiceName: json['remoteServiceName'] as String?, + controllers: (json['controllers'] as Map?)?.map( + (k, e) => MapEntry(k, + ControllerApiDescriptionModel.fromJson(e as Map)), + ), + ); + +Map _$ModuleApiDescriptionModelToJson( + ModuleApiDescriptionModel instance) => + { + 'rootPath': instance.rootPath, + 'remoteServiceName': instance.remoteServiceName, + 'controllers': instance.controllers, + }; + +ControllerApiDescriptionModel _$ControllerApiDescriptionModelFromJson( + Map json) => + ControllerApiDescriptionModel( + controllerName: json['controllerName'] as String?, + controllerGroupName: json['controllerGroupName'] as String?, + isRemoteService: json['isRemoteService'] as bool?, + isIntegrationService: json['isIntegrationService'] as bool?, + apiVersion: json['apiVersion'] as String?, + type: json['type'] as String?, + interfaces: (json['interfaces'] as List?)?.map((e) => + ControllerInterfaceApiDescriptionModel.fromJson( + e as Map)), + actions: (json['actions'] as Map?)?.map( + (k, e) => MapEntry( + k, ActionApiDescriptionModel.fromJson(e as Map)), + ), + ); + +Map _$ControllerApiDescriptionModelToJson( + ControllerApiDescriptionModel instance) => + { + 'controllerName': instance.controllerName, + 'controllerGroupName': instance.controllerGroupName, + 'isRemoteService': instance.isRemoteService, + 'isIntegrationService': instance.isIntegrationService, + 'apiVersion': instance.apiVersion, + 'type': instance.type, + 'interfaces': instance.interfaces?.toList(), + 'actions': instance.actions, + }; + +ApplicationApiDescriptionModel _$ApplicationApiDescriptionModelFromJson( + Map json) => + ApplicationApiDescriptionModel( + modules: (json['modules'] as Map?)?.map( + (k, e) => MapEntry( + k, ModuleApiDescriptionModel.fromJson(e as Map)), + ), + types: (json['types'] as Map?)?.map( + (k, e) => MapEntry( + k, TypeApiDescriptionModel.fromJson(e as Map)), + ), + ); + +Map _$ApplicationApiDescriptionModelToJson( + ApplicationApiDescriptionModel instance) => + { + 'modules': instance.modules, + 'types': instance.types, + }; diff --git a/apps/flutter/core/lib/proxy/volo/abp/index.dart b/apps/flutter/core/lib/proxy/volo/abp/index.dart new file mode 100644 index 000000000..3ca40641d --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/index.dart @@ -0,0 +1,3 @@ +export './asp-net-core/index.dart'; +export './http/index.dart'; +export './localization/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/localization/index.dart b/apps/flutter/core/lib/proxy/volo/abp/localization/index.dart new file mode 100644 index 000000000..0f453b509 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/localization/index.dart @@ -0,0 +1 @@ +export 'models.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/localization/models.dart b/apps/flutter/core/lib/proxy/volo/abp/localization/models.dart new file mode 100644 index 000000000..471149d43 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/localization/models.dart @@ -0,0 +1,22 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'models.g.dart'; + +@JsonSerializable() +class LanguageInfo { + LanguageInfo({ + this.cultureName, + this.uiCultureName, + this.displayName, + this.twoLetterISOLanguageName, + this.flagIcon, + }); + String? cultureName; + String? uiCultureName; + String? displayName; + String? twoLetterISOLanguageName; + String? flagIcon; + + factory LanguageInfo.fromJson(Map json) => _$LanguageInfoFromJson(json); + Map toJson() => _$LanguageInfoToJson(this); +} diff --git a/apps/flutter/core/lib/proxy/volo/abp/localization/models.g.dart b/apps/flutter/core/lib/proxy/volo/abp/localization/models.g.dart new file mode 100644 index 000000000..a6cbcafb0 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/localization/models.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LanguageInfo _$LanguageInfoFromJson(Map json) => LanguageInfo( + cultureName: json['cultureName'] as String?, + uiCultureName: json['uiCultureName'] as String?, + displayName: json['displayName'] as String?, + twoLetterISOLanguageName: json['twoLetterISOLanguageName'] as String?, + flagIcon: json['flagIcon'] as String?, + ); + +Map _$LanguageInfoToJson(LanguageInfo instance) => + { + 'cultureName': instance.cultureName, + 'uiCultureName': instance.uiCultureName, + 'displayName': instance.displayName, + 'twoLetterISOLanguageName': instance.twoLetterISOLanguageName, + 'flagIcon': instance.flagIcon, + }; diff --git a/apps/flutter/core/lib/proxy/volo/abp/models.dart b/apps/flutter/core/lib/proxy/volo/abp/models.dart new file mode 100644 index 000000000..78cc3aa1f --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/models.dart @@ -0,0 +1,23 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'models.g.dart'; + +abstract class NameValue { + NameValue({ + required this.name, + required this.value, + }); + String name; + T value; +} + +@JsonSerializable() +class StringValue extends NameValue { + StringValue({ + required super.name, + required super.value, + }); + + factory StringValue.fromJson(Map json) => _$StringValueFromJson(json); + Map toJson() => _$StringValueToJson(this); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/proxy/volo/abp/models.g.dart b/apps/flutter/core/lib/proxy/volo/abp/models.g.dart new file mode 100644 index 000000000..e45e414f4 --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/abp/models.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'models.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +StringValue _$StringValueFromJson(Map json) => StringValue( + name: json['name'] as String, + value: json['value'] as String, + ); + +Map _$StringValueToJson(StringValue instance) => + { + 'name': instance.name, + 'value': instance.value, + }; diff --git a/apps/flutter/core/lib/proxy/volo/index.dart b/apps/flutter/core/lib/proxy/volo/index.dart new file mode 100644 index 000000000..8e3fd405e --- /dev/null +++ b/apps/flutter/core/lib/proxy/volo/index.dart @@ -0,0 +1 @@ +export './abp/index.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/services/auth.service.dart b/apps/flutter/core/lib/services/auth.service.dart new file mode 100644 index 000000000..d42c84118 --- /dev/null +++ b/apps/flutter/core/lib/services/auth.service.dart @@ -0,0 +1,37 @@ +import 'package:core/models/auth.dart'; +import 'package:core/models/oauth.dart'; +import 'package:get/get.dart'; + +import '../utils/logging.dart'; + +import 'service.base.dart'; + +abstract class AuthService extends ServiceBase { + + static AuthService get to => Get.find(); + + Future password(LoginParams params) { + logger.debug('not implemented'); + return Future.error('not implemented'); + } + + Future portal(PortalLoginParams params) { + logger.debug('not implemented'); + return Future.error('not implemented'); + } + + Future phoneNumber(SmsLoginParams params) { + logger.debug('not implemented'); + return Future.error('not implemented'); + } + + Future refreshToken(RefreshTokenParams params) { + logger.debug('not implemented'); + return Future.error('not implemented'); + } + + Future getProfile() { + logger.debug('not implemented'); + return Future.error('not implemented'); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/config.state.service.dart b/apps/flutter/core/lib/services/config.state.service.dart new file mode 100644 index 000000000..3c9dbd019 --- /dev/null +++ b/apps/flutter/core/lib/services/config.state.service.dart @@ -0,0 +1,131 @@ +import 'dart:async'; +import 'package:core/utils/string.extensions.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'service.base.dart'; +import 'package:core/utils/internal.store.dart'; +import 'package:core/proxy/volo/abp/asp-net-core/mvc/application-configurations/index.dart'; + + +class ConfigStateService extends ServiceBase { + AbpApplicationConfigurationService get abpConfigService => find(); + AbpApplicationLocalizationService get abpApplicationLocalizationService => find(); + final bool? includeLocalizationResources = false; + + final InternalStore _store = InternalStore(state: ApplicationConfigurationDto()); + final PublishSubject _updateSubject = PublishSubject(); + + @override + void onInit() { + super.onInit(); + _initUpdateStream(); + } + + @override + void onClose() { + _updateSubject.close(); + super.onClose(); + } + + _initUpdateStream() { + _updateSubject + .switchMap((_) => Stream.fromFuture(getAbpConfig())) + .switchMap((appState) => Stream.fromFuture(getLocalizationAndCombineWithAppState(appState))) + .listen((appState) => _store.set(appState)); + } + + Future getLocalizationAndCombineWithAppState(ApplicationConfigurationDto appState) { + if (appState.localization?.currentCulture?.cultureName?.isNullOrWhiteSpace() == true) { + throw Exception('culture name should defined'); + } + return getlocalizationResource(appState.localization!.currentCulture!.cultureName!) + .then((localization) { + var abpConfig = appState.cloneWith((state) { + state.localization!.resources = localization.resources; + }); + return abpConfig; + }); + } + + Stream refreshAppState() { + _updateSubject.add(1); + return _store.sliceUpdate((state) => state).take(1); + } + + Future getlocalizationResource(String cultureName) { + return abpApplicationLocalizationService.get(ApplicationLocalizationRequestDto( + cultureName: cultureName, + onlyDynamics: false)); + } + + Future getAbpConfig() { + return abpConfigService.get(ApplicationConfigurationRequestOptions( + includeLocalizationResources: includeLocalizationResources + )); + } + + ApplicationConfigurationDto getAll() { + return _store.state; + } + + ApplicationLocalizationConfigurationDto? getLocalization() { + return _store.state.localization; + } + + Stream getLocalization$() { + return _store.sliceState((state) => state.localization); + } + + String? getFeature(String key) { + return _store.state.features?.values?[key]; + } + + Map getFeatures(Iterable keys) { + Map mapFeatures = {}; + var features = _store.state.features; + if (features == null) { + return mapFeatures; + } + + for (var key in keys) { + mapFeatures[key] = features.values?[key]; + } + + return mapFeatures; + } + + String? getSetting(String key) { + return _store.state.setting?.values?[key]; + } + + Map getSettings(String? keyword) { + var settings = _store.state.setting?.values ?? {}; + if (keyword == null) { + return settings; + } + Map mapSettings = {}; + var keysFound = settings.keys.where((key) => key.contains(keyword)); + + for (var key in keysFound) { + mapSettings[key] = settings[key] ?? ''; + } + + return mapSettings; + } + + ApplicationGlobalFeatureConfigurationDto? getGlobalFeatures() { + return _store.state.globalFeatures; + } + + bool _isGlobalFeatureEnabled( + String key, + ApplicationGlobalFeatureConfigurationDto globalFeatures, + ) { + var features = globalFeatures.enabledFeatures ?? []; + return features.any((fk) => fk == key); + } + + bool getGlobalFeatureIsEnabled(String key) { + return _isGlobalFeatureEnabled(key, _store.state.globalFeatures!); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/index.dart b/apps/flutter/core/lib/services/index.dart new file mode 100644 index 000000000..1ca4f8da8 --- /dev/null +++ b/apps/flutter/core/lib/services/index.dart @@ -0,0 +1,9 @@ +export 'auth.service.dart'; +export 'config.state.service.dart'; +export 'localization.service.dart'; +export 'rest.service.dart'; +export 'storage.service.dart'; +export 'session.service.dart'; +export 'subscription.service.dart'; +export 'theme.service.dart'; +export 'signalr.service.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/services/localization.service.dart b/apps/flutter/core/lib/services/localization.service.dart new file mode 100644 index 000000000..4ac66f66c --- /dev/null +++ b/apps/flutter/core/lib/services/localization.service.dart @@ -0,0 +1,170 @@ +import 'package:core/models/common.dart'; +import 'package:core/services/index.dart'; +import 'package:core/utils/localization.utils.dart'; +import 'package:core/utils/string.extensions.dart'; +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart' hide Rx; +import 'package:rxdart/rxdart.dart'; +import 'package:rxdart_ext/rxdart_ext.dart'; + +import '../proxy/volo/abp/asp-net-core/mvc/index.dart'; +import 'service.base.dart'; + +class LocalizationService extends ServiceBase { + StorageService get storageService => find(); + SessionService get sessionService => find(); + ConfigStateService get configStateService => find(); + + String? get currentLang => sessionService.currentLanguage; + + static LocalizationService get to => Get.find(); + + final Subject _localization$ = BehaviorSubject(); + final BehaviorSubject>> _localizations$ = BehaviorSubject>>.seeded({}); + + @override + void onInit() { + super.onInit(); + _listenToSetLanguage(); + _initLocalizationValues(); + } + + void _initLocalizationValues() { + // var legacyResources$ = configStateService.sliceConfig((config) => config.localization?.values); + // var remoteLocalizations$ = configStateService.sliceConfig((config) => config.localization?.resources); + var currentLanguage$ = sessionService.getLanguage$(); + var localizations$ = configStateService.getLocalization$(); + + // 本地化 + Rx.combineLatest2(currentLanguage$, localizations$, (currentLang, localizations) { + if (currentLang == null || localizations == null) return null; + if (currentLang.isNullOrWhiteSpace() || localizations.resources == null) return null; + var remote = combineLegacyandNewResources(localizations.values, localizations.resources!); + if (remote == null) return null; + List resourceList = []; + remote.forEach((resourceName, resources) { + Map texts = {}; + resources.forEach((key, value) { + if (value == null) return; + texts.putIfAbsent(key, () => value); + }); + resourceList.add(LocalizationResource(resourceName, texts)); + }); + return Localization(currentLang, resourceList); + }).whereNotNull() + .listen((localization) => _localization$.add(localization)); + + _localization$ + .listen((localization) async { + Map> localizations = {}; + Map cultureMap = {}; + for (var resource in localization.resources) { + resource.texts.forEach((key, value) { + cultureMap.putIfAbsent(key, () => value); + }); + } + localizations.putIfAbsent(localization.culture, () => cultureMap); + + Get.clearTranslations(); + Get.addTranslations(localizations); + + await Get.updateLocale(Locale.fromSubtags(languageCode: localization.culture)); + + _localizations$.add(localizations); + }); + } + + void _listenToSetLanguage() { + var lanuage$ = sessionService.onLanguageChange$(); + var localization$ = configStateService.getLocalization$(); + + Rx.combineLatest2(lanuage$, localization$, (lang, localization) { + if (localization?.currentCulture?.cultureName == null) return null; + if (lang == localization?.currentCulture?.cultureName) return null; + return lang; + }).whereNotNull() + .listen((_) => configStateService.refreshAppState()); + } + + Stream localize(String resourceName, String key, {String? defaultValue}) { + return configStateService.getLocalization$() + .map((localization) => LocalizationUtils.createLocalizer(localization)) + .map((localize) => localize(resourceName, key, defaultValue ?? key)); + } + + String localizeSync(String resourceName, String key, {String? defaultValue}) { + var localization = configStateService.getLocalization(); + return LocalizationUtils.createLocalizer(localization)(resourceName, key, defaultValue ?? key); + } + + Stream localizeWithFallback( + List resourceNames, + List keys, + String defaultValue, + ) { + return configStateService.getLocalization$() + .map((localization) => LocalizationUtils.createLocalizerWithFallback(localization!)) + .map((localizeWithFallback) => localizeWithFallback(resourceNames, keys, defaultValue), + ); + } + + String localizeWithFallbackSync( + List resourceNames, + List keys, + String defaultValue, + ) { + var localization = configStateService.getLocalization(); + return LocalizationUtils.createLocalizerWithFallback(localization!)(resourceNames, keys, defaultValue); + } + + Map> getResources() { + return _localizations$.value; + } + + Map? getResource(String resourceName) { + return _localizations$.value[resourceName]; + } + + Stream?> getResource$(String resourceName) { + return _localizations$.map((res) => res[resourceName]); + } + + ApplicationLocalizationResourceDto recursivelyMergeBaseResources(String baseResourceName, Map resource) { + var item = resource[baseResourceName]; + if (item == null) { + return ApplicationLocalizationResourceDto(); + } + item.texts ??= {}; + if (item.baseResources?.isEmpty == true) { + return item; + } + for (var baseResource in item.baseResources!) { + var baseItem = recursivelyMergeBaseResources(baseResource, resource); + baseItem.texts ??= {}; + item.texts!.addAll(baseItem.texts!); + } + + return item; + } + + Map mergeResourcesWithBaseResource(Map resource) { + Map entities = {}; + for (var key in resource.keys) { + var newValue = recursivelyMergeBaseResources(key, resource); + entities.putIfAbsent(key, () => newValue); + } + return entities; + } + + Map>? combineLegacyandNewResources( + Map>? legacy, + Map resource, + ) { + Map>? legacyMerged = legacy; + var mergedResource = mergeResourcesWithBaseResource(resource); + mergedResource.forEach((key, value) { + legacyMerged?.putIfAbsent(key, () => value.texts!); + }); + return legacyMerged; + } +} diff --git a/apps/flutter/core/lib/services/rest.service.dart b/apps/flutter/core/lib/services/rest.service.dart new file mode 100644 index 000000000..fe9387558 --- /dev/null +++ b/apps/flutter/core/lib/services/rest.service.dart @@ -0,0 +1,287 @@ +import 'package:dio/dio.dart'; +import 'package:get/get.dart' hide Response; + +class RestService implements Dio { + RestService({ + required this.dio, + }); + late Dio dio; + + static RestService get to => Get.find(); + + @override + HttpClientAdapter get httpClientAdapter => dio.httpClientAdapter; + + @override + set httpClientAdapter(adapter) => dio.httpClientAdapter = adapter; + + @override + BaseOptions get options => dio.options; + + @override + set options(opt) => dio.options = opt; + + @override + Transformer get transformer => dio.transformer; + + @override + set transformer(trans) => dio.transformer = trans; + + @override + Interceptors get interceptors => dio.interceptors; + + @override + void close({bool force = false}) => dio.close(force: force); + + @override + Future> fetch(RequestOptions requestOptions) => dio.fetch(requestOptions); + + @override + Future> get( + String path, + { + Object? data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onReceiveProgress, + }) => dio.get(path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onReceiveProgress: onReceiveProgress); + + @override + Future> getUri( + Uri uri, { + Object? data, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onReceiveProgress, + }) => dio.getUri(uri, + data: data, + options: options, + cancelToken: cancelToken, + onReceiveProgress: onReceiveProgress); + + @override + Future> post( + String path, { + Object? data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.post(path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> postUri( + Uri uri, { + Object? data, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.postUri(uri, + data: data, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> put( + String path, { + Object? data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.put(path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> putUri( + Uri uri, { + Object? data, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.putUri(uri, + data: data, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> head( + String path, { + Object? data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + }) => dio.head(path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken); + + @override + Future> headUri( + Uri uri, { + Object? data, + Options? options, + CancelToken? cancelToken, + }) => dio.headUri(uri, + data: data, + options: options, + cancelToken: cancelToken); + + @override + Future> delete( + String path, + { + Object? data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + }) => dio.delete(path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken); + + @override + Future> deleteUri( + Uri uri, + { + Object? data, + Options? options, + CancelToken? cancelToken, + }) => dio.deleteUri(uri, + data: data, + options: options, + cancelToken: cancelToken); + + @override + Future download( + String urlPath, savePath, + { + ProgressCallback? onReceiveProgress, + Map? queryParameters, + CancelToken? cancelToken, + bool deleteOnError = true, + String lengthHeader = Headers.contentLengthHeader, + Object? data, + Options? options, + }) => dio.download(urlPath, savePath, + onReceiveProgress: onReceiveProgress, + queryParameters: queryParameters, + cancelToken: cancelToken, + deleteOnError: deleteOnError, + lengthHeader: lengthHeader, + data: data, + options: options); + + @override + Future downloadUri( + Uri uri, savePath, + { + ProgressCallback? onReceiveProgress, + CancelToken? cancelToken, + bool deleteOnError = true, + String lengthHeader = Headers.contentLengthHeader, + Object? data, + Options? options, + }) => dio.downloadUri(uri, savePath, + onReceiveProgress: onReceiveProgress, + cancelToken: cancelToken, + deleteOnError: deleteOnError, + lengthHeader: lengthHeader, + data: data, + options: options); + + @override + Future> patch( + String path, + { + Object? data, + Map? queryParameters, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.patch(path, + data: data, + queryParameters: queryParameters, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> patchUri( + Uri uri, + { + Object? data, + Options? options, + CancelToken? cancelToken, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.patchUri(uri, + data: data, + options: options, + cancelToken: cancelToken, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> request( + String path, + { + Object? data, + Map? queryParameters, + CancelToken? cancelToken, + Options? options, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.request(path, + data: data, + queryParameters: queryParameters, + cancelToken: cancelToken, + options: options, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); + + @override + Future> requestUri( + Uri uri, + { + Object? data, + CancelToken? cancelToken, + Options? options, + ProgressCallback? onSendProgress, + ProgressCallback? onReceiveProgress, + }) => dio.requestUri(uri, + data: data, + cancelToken: cancelToken, + options: options, + onSendProgress: onSendProgress, + onReceiveProgress: onReceiveProgress); +} diff --git a/apps/flutter/core/lib/services/service.base.dart b/apps/flutter/core/lib/services/service.base.dart new file mode 100644 index 000000000..2cf9f7374 --- /dev/null +++ b/apps/flutter/core/lib/services/service.base.dart @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +abstract class ServiceBase extends GetxService { + T find() => Get.find(); +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/session.service.dart b/apps/flutter/core/lib/services/session.service.dart new file mode 100644 index 000000000..78d939b67 --- /dev/null +++ b/apps/flutter/core/lib/services/session.service.dart @@ -0,0 +1,120 @@ +import 'dart:convert'; + +import 'package:core/models/auth.dart'; +import 'package:core/models/session.dart'; +import 'package:core/proxy/index.dart'; +import 'package:core/utils/internal.store.dart'; +import 'package:core/utils/string.extensions.dart'; +import 'package:get/get.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'auth.service.dart'; +import 'storage.service.dart'; +import 'config.state.service.dart'; +import 'service.base.dart'; + +class SessionService extends ServiceBase { + static const String sessionKey = '_abp_session_'; + final InternalStore _store = InternalStore(state: _initState()); + + static SessionService get to => Get.find(); + + AuthService get _authService => find(); + StorageService get _storageService => find(); + ConfigStateService get _configStateService => find(); + + bool get isAuthenticated { + if (_store.state.profile == null || _store.state.token == null) { + return false; + } + + return !_store.state.profile!.id.isNullOrWhiteSpace() && + !_store.state.token!.accessToken.isNullOrWhiteSpace(); + } + + CurrentTenantDto? get tenant{ + return _store.state.tenant; + } + + UserProfile? get profile { + return _store.state.profile; + } + + Token? get token { + return _store.state.token; + } + + String? get currentLanguage { + return _store.state.language; + } + + @override + void onInit() { + super.onInit(); + _initUpdateStream(); + } + + static Session _initState() { + var session = StorageService.initStorage(sessionKey, (value) => Session.fromJson(jsonDecode(value))); + return session ?? Session(); + } + + void _initUpdateStream() { + var token$ = _store.sliceState((state) => state.token); + token$.doOnData((_) => _configStateService.refreshAppState()) + .whereNotNull() + .switchMap((_) => Stream.fromFuture(_authService.getProfile())) + .listen((profile) { + var abpConfig = _configStateService.getAll(); + _store.patch((state) { + state.profile = profile; + state.tenant = abpConfig.currentTenant; + }); + }); + + var session$ = _store.sliceUpdate((state) => state); + session$.listen((session) { + _storageService.setItem(sessionKey, jsonEncode(session.toJson())); + }); + } + + Stream getProfile$() { + return _store.sliceState((state) => state.profile); + } + + Stream getToken$() { + return _store.sliceState((state) => state.token); + } + + Stream getLanguage$() { + return _store.sliceState((state) => state.language); + } + + Stream onLanguageChange$() { + return _store.sliceUpdate((state) => state.language); + } + + void setLanguage(String language) { + if (language == _store.state.language) return; + _store.patch((state) => state.language = language); + } + + void refreshProfile() { + _store.patch((state) { + state.profile = profile; + }); + } + + void refreshToken(Token? token) { + _store.patch((state) { + state.token = token; + }); + } + + void resetSession() { + _store.patch((state) { + state.token = null; + state.profile = null; + }); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/signalr.service.dart b/apps/flutter/core/lib/services/signalr.service.dart new file mode 100644 index 000000000..467f9178c --- /dev/null +++ b/apps/flutter/core/lib/services/signalr.service.dart @@ -0,0 +1,125 @@ +import 'dart:async'; + +import 'package:core/utils/logging.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:signalr_netcore/signalr_client.dart'; + +import 'session.service.dart'; + +class SignalrMessage { + SignalrMessage( + this.method, + this.data, + ); + String method; + List data; +} + +class SignalrService { + SignalrService(String url, + { + bool autoStart = false, + bool automaticReconnect = true, + List? retryDelays, + Future Function()? accessTokenFactory, + }) { + _hubConnection = _createSignalR(url, + autoStart: autoStart, + automaticReconnect: automaticReconnect, + retryDelays: retryDelays, + accessTokenFactory: accessTokenFactory ?? () { + var token = SessionService.to.token; + if (token != null) return Future.value(token.accessToken); + return Future.value(''); + }); + _initHubEvents(); + } + late HubConnection _hubConnection; + + final BehaviorSubject _onClose = BehaviorSubject(); + final BehaviorSubject _onReconnecting = BehaviorSubject(); + final BehaviorSubject _onReconnected = BehaviorSubject(); + final BehaviorSubject _onReceived = BehaviorSubject(); + + static HubConnection _createSignalR( + String url, + { + bool autoStart = false, + bool automaticReconnect = true, + List? retryDelays, + Future Function()? accessTokenFactory, + } + ) { + var httpConnectionOptions = HttpConnectionOptions( + httpClient: WebSupportingHttpClient(logger), + accessTokenFactory: accessTokenFactory, + logger: logger, + logMessageContent: true); + var hubConnectionBuilder = HubConnectionBuilder() + .withUrl(url, options: httpConnectionOptions); + if (automaticReconnect) { + hubConnectionBuilder.withAutomaticReconnect( + retryDelays: retryDelays, + ); + } + return hubConnectionBuilder.build(); + } + + void _initHubEvents() { + _hubConnection.onclose(({error}) { + _onClose.add(error); + }); + _hubConnection.onreconnected(({connectionId}) { + _onReconnected.add(connectionId); + }); + _hubConnection.onreconnecting(({error}) { + _onReconnecting.add(error); + }); + } + + Future? start() { + return _hubConnection.start(); + } + + Future stop() { + return _hubConnection.stop(); + } + + StreamSubscription onClose(Function(Exception?) listen, { bool Function(Exception?)? filter}) { + return _onClose + .where((event) => filter != null ? filter(event) : true) + .listen(listen); + } + + StreamSubscription onReconnecting(Function(Exception?) listen, { bool Function(Exception?)? filter}) { + return _onReconnecting + .where((event) => filter != null ? filter(event) : true) + .listen(listen); + } + + StreamSubscription onReconnected(Function(String?) listen, { bool Function(String?)? filter}) { + return _onReconnected + .where((event) => filter != null ? filter(event) : true) + .listen(listen); + } + + Stream subscribe(String methodName) { + _hubConnection.on(methodName, (data) { + if (data == null) return; + _onReceived.add(SignalrMessage(methodName, data)); + }); + return _onReceived.where((message) => message.method == methodName); + } + + void unsubscribe(String methodName,) { + _hubConnection.off(methodName); + } + + Future send(String methodName, { List? args }) { + return _hubConnection.send(methodName, args: args); + } + + Future invoke(String methodName, { List? args }) { + return _hubConnection.invoke(methodName, args: args); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/storage.service.dart b/apps/flutter/core/lib/services/storage.service.dart new file mode 100644 index 000000000..9cbf11cc9 --- /dev/null +++ b/apps/flutter/core/lib/services/storage.service.dart @@ -0,0 +1,79 @@ +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'service.base.dart'; + +class GetxStorageService extends StorageService { + static late GetStorage _storage; + static Future init([String container = 'GetStorage']) async { + try { + var isInit = await GetStorage.init(container); + if (isInit) { + _storage = GetStorage(container); + } + return isInit; + } catch(err) { + return false; + } + } + + @override + void clear() { + _storage.erase(); + } + + @override + String? getItem(String key) { + if (_storage.hasData(key)) { + return _storage.read(key); + } + return null; + } + + @override + void removeItem(String key) { + if (_storage.hasData(key)) { + _storage.remove(key); + } + } + + @override + void setItem(String key, String value) { + _storage.write(key, value); + } +} + +class StorageService extends ServiceBase { + static final Map _storage = {}; + + static StorageService get to => Get.find(); + + static T? initStorage(String key, T? Function(String) formater) { + return to.getFormat(key, formater); + } + + void clear() { + _storage.clear(); + } + + String? getItem(String key) { + return _storage[key]; + } + + void removeItem(String key) { + _storage.remove(key); + } + + void setItem(String key, String value) { + _storage.update(key, (_) => value, ifAbsent: () => value); + } +} + +extension StorageServiceGetItem on StorageService { + T? getFormat(String key, T? Function(String) formater) { + var item = getItem(key); + if (item != null) { + return formater(item); + } + return null; + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/subscription.service.dart b/apps/flutter/core/lib/services/subscription.service.dart new file mode 100644 index 000000000..b9307f959 --- /dev/null +++ b/apps/flutter/core/lib/services/subscription.service.dart @@ -0,0 +1,52 @@ +import 'dart:async'; +import 'package:rxdart/rxdart.dart'; +import 'package:rxdart_ext/rxdart_ext.dart'; + +class SubscriptionService { + final CompositeSubscription _subscription = CompositeSubscription(); + + bool get isClosed => _subscription.isDisposed; + + void addOne(StreamSubscription subscription) { + subscription.addTo(_subscription); + } + + StreamSubscription subscribe( + Stream source$, + [void Function(T value)? next, + void Function(dynamic error)? error] + ) { + var subscription = source$.listen((value) { + if (next != null) { + next(value); + } + }, onError: (err) { + if (error != null) { + error(err); + } + }); + subscription.addTo(_subscription); + + return subscription; + } + + Future closeAll() async { + await _subscription.cancel(); + } + + Future closeOne(StreamSubscription? subscription) async { + await removeOne(subscription); + if (subscription != null) { + await subscription.cancel(); + } + } + + Future removeOne(StreamSubscription? subscription) async { + if (subscription == null) return; + await _subscription.remove(subscription); + } + + Future reset() async { + await _subscription.clear(); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/services/theme.service.dart b/apps/flutter/core/lib/services/theme.service.dart new file mode 100644 index 000000000..275b40b3d --- /dev/null +++ b/apps/flutter/core/lib/services/theme.service.dart @@ -0,0 +1,79 @@ +import 'package:core/utils/internal.store.dart'; +import 'package:core/utils/theme.utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:get/get.dart'; + +import 'service.base.dart'; +import 'storage.service.dart'; + +class ThemeState { + ThemeState( + this.brightness, + this.colorScheme, + ); + Brightness brightness; + ColorScheme colorScheme; +} + +class ThemeService extends ServiceBase { + static const String themeKey = '_abp_theme_'; + StorageService get storageService => find(); + + final InternalStore _store = InternalStore(state: ThemeState(Brightness.light, ThemeUtils.lightColorScheme)); + + Brightness get currentThemeMode => _store.state.brightness; + ColorScheme get themeColor => _store.state.colorScheme; + + static Brightness getSystemTheme() { + return SchedulerBinding.instance.platformDispatcher.platformBrightness; + } + + void _initState() { + var theme = StorageService.initStorage(themeKey, (value) => value); + + switch (theme) + { + case 'light': return changeThemeMode(ThemeMode.light); + case 'dark': return changeThemeMode(ThemeMode.dark); + case 'system': return changeThemeMode(ThemeMode.system); + } + } + + @override + void onInit() { + super.onInit(); + _initUpdateStream(); + _initState(); + } + + void _initUpdateStream() { + _store.sliceUpdate((state) => state.brightness) + .listen((brightness) { + switch (brightness) + { + case Brightness.dark: + ThemeUtils.currentTheme = ThemeUtils.darkTheme; + ThemeUtils.currentColor = ThemeUtils.darkColorScheme; + storageService.setItem(themeKey, 'dark'); + Get.changeThemeMode(ThemeMode.dark); + return; + case Brightness.light: + ThemeUtils.currentTheme = ThemeUtils.lightTheme; + ThemeUtils.currentColor = ThemeUtils.lightColorScheme; + storageService.setItem(themeKey, 'light'); + Get.changeThemeMode(ThemeMode.light); + return; + } + }); + } + + void changeThemeMode(ThemeMode mode) { + switch (mode) + { + case ThemeMode.dark: _store.patch((state) => state.brightness = Brightness.dark); + case ThemeMode.light: _store.patch((state) => state.brightness = Brightness.light); + case ThemeMode.system: _store.patch((state) => state.brightness = getSystemTheme()); + } + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/tokens/abp.tokens.dart b/apps/flutter/core/lib/tokens/abp.tokens.dart new file mode 100644 index 000000000..e7790fb51 --- /dev/null +++ b/apps/flutter/core/lib/tokens/abp.tokens.dart @@ -0,0 +1,3 @@ +class AbpTokens { + +} diff --git a/apps/flutter/core/lib/tokens/http.token.dart b/apps/flutter/core/lib/tokens/http.token.dart new file mode 100644 index 000000000..24192d455 --- /dev/null +++ b/apps/flutter/core/lib/tokens/http.token.dart @@ -0,0 +1,6 @@ +class HttpTokens { + /// 用户自行处理请求异常,异常程序不进行处理 + static const String ignoreError = "ignore_error"; + /// 请求不携带token + static const String ignoreToken = "ignore_token"; +} \ No newline at end of file diff --git a/apps/flutter/core/lib/tokens/index.dart b/apps/flutter/core/lib/tokens/index.dart new file mode 100644 index 000000000..8d660764e --- /dev/null +++ b/apps/flutter/core/lib/tokens/index.dart @@ -0,0 +1,3 @@ +export 'abp.tokens.dart'; +export 'http.token.dart'; +export 'notifications.token.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/tokens/notifications.token.dart b/apps/flutter/core/lib/tokens/notifications.token.dart new file mode 100644 index 000000000..dbfa4cc24 --- /dev/null +++ b/apps/flutter/core/lib/tokens/notifications.token.dart @@ -0,0 +1,8 @@ +class NotificationTokens { + /// 通知生产者 + static const String producer = "producer"; + /// 通知消费者 + static const String consumer = "consumer"; + /// 通知订阅者(接收通知数据名称, 与Hub方法同名), 定义便于订阅/取消 + static const String receiver = "get-notification"; +} \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/index.dart b/apps/flutter/core/lib/utils/index.dart new file mode 100644 index 000000000..07f1fe796 --- /dev/null +++ b/apps/flutter/core/lib/utils/index.dart @@ -0,0 +1,7 @@ +export 'internal.store.dart'; +export 'localization.utils.dart'; +export 'logging.dart'; +export 'logging.logger.dart'; +export 'logging.logging.dart'; +export 'string.extensions.dart'; +export 'theme.utils.dart'; \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/internal.store.dart b/apps/flutter/core/lib/utils/internal.store.dart new file mode 100644 index 000000000..ddedd4be8 --- /dev/null +++ b/apps/flutter/core/lib/utils/internal.store.dart @@ -0,0 +1,59 @@ +import 'package:rxdart_ext/rxdart_ext.dart'; + +class InternalStore implements DisposableMixin { + InternalStore({ + required State state, + }) { + _state = state; + update$ = BehaviorSubject(); + state$ = BehaviorSubject.seeded(state); + } + late BehaviorSubject update$; + late BehaviorSubject state$; + late State _state; + + State get state => state$.value; + + Stream sliceState( + T Function(State) selector, + { bool Function(T, T)? compareFn }) { + return state$.map((value) => selector(value)) + .distinctUniqueBy((map) => map, equals: compareFn); + } + + Stream sliceUpdate( + T Function(State) selector, + { + bool Function(T)? filterFn, + }) { + return update$.map((value) => selector(value as State)) + .where((state) { + if (filterFn != null) { + return filterFn(state); + } + return state != null; + }); + } + + void set(State state) { + _state = state; + //state$.value = _state; + state$.add(state); + update$.add(state); + } + + void patch(Function(State) update) { + update(_state); + state$.add(_state); + update$.add(_state); + } + + @override + void dispose() { + update$.close(); + state$.close(); + } + + @override + Stream get dispose$ => state$; +} diff --git a/apps/flutter/core/lib/utils/localization.utils.dart b/apps/flutter/core/lib/utils/localization.utils.dart new file mode 100644 index 000000000..c6734fbde --- /dev/null +++ b/apps/flutter/core/lib/utils/localization.utils.dart @@ -0,0 +1,67 @@ +import 'package:core/utils/string.extensions.dart'; + +import '../proxy/volo/abp/asp-net-core/mvc/index.dart'; + +class LocalizationUtils { + static String Function(String resourceName, + String key, + String? defaultValue) createLocalizer(ApplicationLocalizationConfigurationDto? localization) { + return (String resourceName, String key, String? defaultValue) { + if (localization == null || resourceName == '_') return key; + var resource = localization.values?[resourceName]; + if (resource == null) return defaultValue ?? key; + return resource[key] ?? defaultValue ?? key; + }; + } + + static String Function(List resourceNames, List keys, String defaultValue) createLocalizerWithFallback( + ApplicationLocalizationConfigurationDto localization) { + var findLocalization = createLocalizationFinder(localization); + return (List resourceNames, List keys, String defaultValue) { + var localizedText = findLocalization(resourceNames, keys); + return localizedText.localized ?? defaultValue; + }; + } + + static LocalizedText Function(List resourceNames, List keys) createLocalizationFinder( + ApplicationLocalizationConfigurationDto localization) { + var localize = createLocalizer(localization); + return (List resourceNames, List keys) { + if (localization.defaultResourceName.isNullOrWhiteSpace() == false && + resourceNames.contains(localization.defaultResourceName!)) { + resourceNames.add(localization.defaultResourceName!); + } + var resourceCount = resourceNames.length; + var keyCount = keys.length; + + for (var i = 0; i < resourceCount; i++) { + var resourceName = resourceNames[i]; + + for (var j = 0; j < keyCount; j++) { + var key = keys[j]; + var localized = localize(resourceName, key, null); + if (!localized.isNullOrWhiteSpace()) { + return LocalizedText( + resourceName: resourceName, + key: key, + localized: localized, + ); + } + } + } + + return LocalizedText(); + }; + } +} + +class LocalizedText { + LocalizedText({ + this.resourceName, + this.key, + this.localized, + }); + String? resourceName; + String? key; + String? localized; +} \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/logging.dart b/apps/flutter/core/lib/utils/logging.dart new file mode 100644 index 000000000..6fb116e73 --- /dev/null +++ b/apps/flutter/core/lib/utils/logging.dart @@ -0,0 +1,6 @@ +//import '../abstracts/logging.dart'; +//import 'logging.logger.dart'; +import 'logging.logging.dart'; + +//final ILogger logger = LoggingLogger.create('abp'); +final LoggingLogger logger = LoggingLogger.create('abp'); \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/logging.logger.dart b/apps/flutter/core/lib/utils/logging.logger.dart new file mode 100644 index 000000000..f878c4e3b --- /dev/null +++ b/apps/flutter/core/lib/utils/logging.logger.dart @@ -0,0 +1,36 @@ +import 'package:core/abstracts/logging.dart'; +import 'package:logger/logger.dart'; + +class LoggerLogger extends ILogger { + final _innerLogger = Logger(); + + @override + void debug(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.d(message, error, stackTrace); + } + + @override + void info(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.i(message, error, stackTrace); + } + + @override + void warn(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.w(message, error, stackTrace); + } + + @override + void error(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.e(message, error, stackTrace); + } + + @override + void trace(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.wtf(message, error, stackTrace); + } + + @override + void all(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.v(message, error, stackTrace); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/logging.logging.dart b/apps/flutter/core/lib/utils/logging.logging.dart new file mode 100644 index 000000000..b56dc5b57 --- /dev/null +++ b/apps/flutter/core/lib/utils/logging.logging.dart @@ -0,0 +1,122 @@ +import 'dart:async'; + +import 'package:core/abstracts/logging.dart'; +import 'package:logging/logging.dart'; + +class LoggingLogger extends ILogger implements Logger { + LoggingLogger(String name, { Level? level }) { + Logger.root.level = level ?? Level.ALL; + Logger.root.onRecord.listen((record) { + // ignore: avoid_print + print('${record.level.name}: ${record.time}: ${record.message}'); + }); + _innerLogger = Logger(name); + } + late Logger _innerLogger; + + factory LoggingLogger.create(String name, { Level? level }) { + return LoggingLogger(name, level: level); + } + + @override + void debug(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.shout(message, error, stackTrace); + } + + @override + void info(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.fine(message, error, stackTrace); + } + + @override + void warn(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.warning(message, error, stackTrace); + } + + @override + void error(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.severe(message, error, stackTrace); + } + + @override + void trace(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.finer(message, error, stackTrace); + } + + @override + void all(dynamic message, [dynamic error, StackTrace? stackTrace]) { + _innerLogger.log(Level.ALL, message, error, stackTrace); + } + + @override + Level get level => _innerLogger.level; + + @override + set level(l) => _innerLogger.level = l; + + @override + Map get children => _innerLogger.children; + + @override + void clearListeners() { + _innerLogger.clearListeners(); + } + + @override + void config(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.config(message, error, stackTrace); + } + + @override + void fine(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.fine(message, error, stackTrace); + } + + @override + void finer(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.finer(message, error, stackTrace); + } + + @override + void finest(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.finest(message, error, stackTrace); + } + + @override + String get fullName => _innerLogger.fullName; + + @override + bool isLoggable(Level value) => _innerLogger.isLoggable(value); + + @override + String get name => _innerLogger.name; + + @override + Stream get onLevelChanged => _innerLogger.onLevelChanged; + + @override + Stream get onRecord => _innerLogger.onRecord; + + @override + Logger? get parent => _innerLogger.parent; + + @override + void severe(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.severe(message, error, stackTrace); + } + + @override + void shout(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.shout(message, error, stackTrace); + } + + @override + void warning(Object? message, [Object? error, StackTrace? stackTrace]) { + _innerLogger.warning(message, error, stackTrace); + } + + @override + void log(Level logLevel, Object? message, [Object? error, StackTrace? stackTrace, Zone? zone]) { + _innerLogger.log(logLevel, message, error, stackTrace); + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/string.extensions.dart b/apps/flutter/core/lib/utils/string.extensions.dart new file mode 100644 index 000000000..5d15fb146 --- /dev/null +++ b/apps/flutter/core/lib/utils/string.extensions.dart @@ -0,0 +1,19 @@ +import 'package:get/get.dart'; + +extension StringNullableUitl on String? { + bool isNullOrWhiteSpace() { + if (GetUtils.isNullOrBlank(this) == true) { + return true; + } + return false; + } +} + +extension StringUitl on String { + bool isNullOrWhiteSpace() { + if (GetUtils.isNullOrBlank(this) == true) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/apps/flutter/core/lib/utils/theme.utils.dart b/apps/flutter/core/lib/utils/theme.utils.dart new file mode 100644 index 000000000..1e0f57d77 --- /dev/null +++ b/apps/flutter/core/lib/utils/theme.utils.dart @@ -0,0 +1,79 @@ +import 'package:flutter/material.dart'; + +class ThemeUtils { + + static ColorScheme currentColor = lightColorScheme; + static ThemeData currentTheme = lightTheme; + + static ThemeData lightTheme = ThemeData.light(); + + static ColorScheme lightColorScheme = const ColorScheme( + brightness: Brightness.light, + primary: Color(0xffe65100), + onPrimary: Color(0xffffffff), + primaryContainer: Color(0xffffcc80), + onPrimaryContainer: Color(0xff14110b), + secondary: Color(0xff2979ff), + onSecondary: Color(0xffffffff), + secondaryContainer: Color(0xffe4eaff), + onSecondaryContainer: Color(0xff131314), + tertiary: Color(0xff2962ff), + onTertiary: Color(0xffffffff), + tertiaryContainer: Color(0xffcbd6ff), + onTertiaryContainer: Color(0xff111214), + error: Color(0xffb00020), + onError: Color(0xffffffff), + errorContainer: Color(0xfffcd8df), + onErrorContainer: Color(0xff141213), + background: Color(0xfffefaf8), + onBackground: Color(0xff090909), + surface: Color(0xfffefaf8), + onSurface: Color(0xff090909), + surfaceVariant: Color(0xffede5e0), + onSurfaceVariant: Color(0xff121111), + outline: Color(0xff7c7c7c), + outlineVariant: Color(0xffc8c8c8), + shadow: Color(0xff000000), + scrim: Color(0xff000000), + inverseSurface: Color(0xff161210), + onInverseSurface: Color(0xfff5f5f5), + inversePrimary: Color(0xffffcf99), + surfaceTint: Color(0xffe65100), + ); + + static ThemeData darkTheme = ThemeData.dark(); + + static ColorScheme darkColorScheme = const ColorScheme( + brightness: Brightness.dark, + primary: Color(0xffffb300), + onPrimary: Color(0xff141204), + primaryContainer: Color(0xffc87200), + onPrimaryContainer: Color(0xfffff1df), + secondary: Color(0xff82b1ff), + onSecondary: Color(0xff0e1114), + secondaryContainer: Color(0xff3770cf), + onSecondaryContainer: Color(0xffe8f1ff), + tertiary: Color(0xff448aff), + onTertiary: Color(0xfff4f9ff), + tertiaryContainer: Color(0xff0b429c), + onTertiaryContainer: Color(0xffe1eaf8), + error: Color(0xffcf6679), + onError: Color(0xff140c0d), + errorContainer: Color(0xffb1384e), + onErrorContainer: Color(0xfffbe8ec), + background: Color(0xff1d1910), + onBackground: Color(0xffedecec), + surface: Color(0xff1d1910), + onSurface: Color(0xffedecec), + surfaceVariant: Color(0xff463f2c), + onSurfaceVariant: Color(0xffe1e0dd), + outline: Color(0xff7d7676), + outlineVariant: Color(0xff2e2c2c), + shadow: Color(0xff000000), + scrim: Color(0xff000000), + inverseSurface: Color(0xfffffbf2), + onInverseSurface: Color(0xff141312), + inversePrimary: Color(0xff775b0e), + surfaceTint: Color(0xffffb300), + ); +} \ No newline at end of file diff --git a/apps/flutter/core/linux/flutter/generated_plugin_registrant.cc b/apps/flutter/core/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/apps/flutter/core/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/apps/flutter/core/linux/flutter/generated_plugin_registrant.h b/apps/flutter/core/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/apps/flutter/core/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/core/linux/flutter/generated_plugins.cmake b/apps/flutter/core/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2e1de87a7 --- /dev/null +++ b/apps/flutter/core/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/core/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/apps/flutter/core/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 000000000..5887b0b01 --- /dev/null +++ b/apps/flutter/core/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\core +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/core/macos/Flutter/ephemeral/flutter_export_environment.sh b/apps/flutter/core/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100644 index 000000000..e7c40ce04 --- /dev/null +++ b/apps/flutter/core/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\core" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/core/pubspec.yaml b/apps/flutter/core/pubspec.yaml new file mode 100644 index 000000000..85b344404 --- /dev/null +++ b/apps/flutter/core/pubspec.yaml @@ -0,0 +1,70 @@ +name: core +description: A new Flutter package project. +version: 0.0.1 +homepage: +publish_to: none + +environment: + sdk: '>=3.0.5 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + dio: + + get: + get_storage: + rxdart: + rxdart_ext: + logger: + logging: + signalr_netcore: ^1.3.4 + json_annotation: ^4.8.1 + flutter_app_environment: ^1.0.1 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + + build_runner: ^2.4.5 + json_serializable: ^6.7.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/apps/flutter/core/test/abp_storage_service.test.dart b/apps/flutter/core/test/abp_storage_service.test.dart new file mode 100644 index 000000000..ebbf7bb40 --- /dev/null +++ b/apps/flutter/core/test/abp_storage_service.test.dart @@ -0,0 +1,21 @@ +import 'package:core/core.module.dart'; +import 'package:core/services/storage.service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get/get.dart'; + +void main() { + test('set storage', () async { + var module = CoreModule(); + await module.initAsync(); + var storage = Get.find(); + + storage.setItem('key', 'value'); + expect(storage.getItem('key'), 'value'); + + storage.removeItem('key'); + expect(storage.getItem('key'), null); + + storage.clear(); + expect(storage.getItem('key'), null); + }); +} diff --git a/apps/flutter/core/windows/flutter/generated_plugin_registrant.cc b/apps/flutter/core/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/apps/flutter/core/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/apps/flutter/core/windows/flutter/generated_plugin_registrant.h b/apps/flutter/core/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/apps/flutter/core/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/core/windows/flutter/generated_plugins.cmake b/apps/flutter/core/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..b93c4c30c --- /dev/null +++ b/apps/flutter/core/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/dev_app/.gitignore b/apps/flutter/dev_app/.gitignore new file mode 100644 index 000000000..bceef1d48 --- /dev/null +++ b/apps/flutter/dev_app/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +# Environment config +/res/config/development.json \ No newline at end of file diff --git a/apps/flutter/dev_app/.metadata b/apps/flutter/dev_app/.metadata new file mode 100644 index 000000000..30d90a7ef --- /dev/null +++ b/apps/flutter/dev_app/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: android + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: ios + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: linux + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: macos + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: web + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + - platform: windows + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/apps/flutter/dev_app/README.md b/apps/flutter/dev_app/README.md new file mode 100644 index 000000000..f6c8d16bb --- /dev/null +++ b/apps/flutter/dev_app/README.md @@ -0,0 +1,16 @@ +# dev_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/apps/flutter/dev_app/analysis_options.yaml b/apps/flutter/dev_app/analysis_options.yaml new file mode 100644 index 000000000..61b6c4de1 --- /dev/null +++ b/apps/flutter/dev_app/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/apps/flutter/dev_app/android/.gitignore b/apps/flutter/dev_app/android/.gitignore new file mode 100644 index 000000000..6f568019d --- /dev/null +++ b/apps/flutter/dev_app/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/apps/flutter/dev_app/android/app/build.gradle b/apps/flutter/dev_app/android/app/build.gradle new file mode 100644 index 000000000..d9a41eba1 --- /dev/null +++ b/apps/flutter/dev_app/android/app/build.gradle @@ -0,0 +1,72 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + namespace "com.example.dev_app" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.dev_app" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/apps/flutter/dev_app/android/app/src/debug/AndroidManifest.xml b/apps/flutter/dev_app/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..399f6981d --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/apps/flutter/dev_app/android/app/src/main/AndroidManifest.xml b/apps/flutter/dev_app/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..75cb28c0d --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/android/app/src/main/kotlin/com/example/abp_flutter/MainActivity.kt b/apps/flutter/dev_app/android/app/src/main/kotlin/com/example/abp_flutter/MainActivity.kt new file mode 100644 index 000000000..a308b3e76 --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/main/kotlin/com/example/abp_flutter/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.dev_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/apps/flutter/dev_app/android/app/src/main/res/drawable-v21/launch_background.xml b/apps/flutter/dev_app/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 000000000..f74085f3f --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/apps/flutter/dev_app/android/app/src/main/res/drawable/launch_background.xml b/apps/flutter/dev_app/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 000000000..304732f88 --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/apps/flutter/dev_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/flutter/dev_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..db77bb4b7 Binary files /dev/null and b/apps/flutter/dev_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/apps/flutter/dev_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/flutter/dev_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..17987b79b Binary files /dev/null and b/apps/flutter/dev_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/apps/flutter/dev_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/apps/flutter/dev_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..09d439148 Binary files /dev/null and b/apps/flutter/dev_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/apps/flutter/dev_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/flutter/dev_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d5f1c8d34 Binary files /dev/null and b/apps/flutter/dev_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/apps/flutter/dev_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/flutter/dev_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..4d6372eeb Binary files /dev/null and b/apps/flutter/dev_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/apps/flutter/dev_app/android/app/src/main/res/values-night/styles.xml b/apps/flutter/dev_app/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..06952be74 --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/apps/flutter/dev_app/android/app/src/main/res/values/styles.xml b/apps/flutter/dev_app/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..cb1ef8805 --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/apps/flutter/dev_app/android/app/src/profile/AndroidManifest.xml b/apps/flutter/dev_app/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 000000000..399f6981d --- /dev/null +++ b/apps/flutter/dev_app/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/apps/flutter/dev_app/android/build.gradle b/apps/flutter/dev_app/android/build.gradle new file mode 100644 index 000000000..f7eb7f63c --- /dev/null +++ b/apps/flutter/dev_app/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.3.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/apps/flutter/dev_app/android/gradle.properties b/apps/flutter/dev_app/android/gradle.properties new file mode 100644 index 000000000..94adc3a3f --- /dev/null +++ b/apps/flutter/dev_app/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/apps/flutter/dev_app/android/gradle/wrapper/gradle-wrapper.properties b/apps/flutter/dev_app/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..3c472b99c --- /dev/null +++ b/apps/flutter/dev_app/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/apps/flutter/dev_app/android/settings.gradle b/apps/flutter/dev_app/android/settings.gradle new file mode 100644 index 000000000..44e62bcf0 --- /dev/null +++ b/apps/flutter/dev_app/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/apps/flutter/dev_app/ios/.gitignore b/apps/flutter/dev_app/ios/.gitignore new file mode 100644 index 000000000..7a7f9873a --- /dev/null +++ b/apps/flutter/dev_app/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/apps/flutter/dev_app/ios/Flutter/AppFrameworkInfo.plist b/apps/flutter/dev_app/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000..9625e105d --- /dev/null +++ b/apps/flutter/dev_app/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/apps/flutter/dev_app/ios/Flutter/Debug.xcconfig b/apps/flutter/dev_app/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/apps/flutter/dev_app/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/apps/flutter/dev_app/ios/Flutter/Release.xcconfig b/apps/flutter/dev_app/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000..592ceee85 --- /dev/null +++ b/apps/flutter/dev_app/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/apps/flutter/dev_app/ios/Runner.xcodeproj/project.pbxproj b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..da2f8097a --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,613 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807E294A63A400263BE5 /* Frameworks */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/apps/flutter/dev_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/flutter/dev_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..e42adcb34 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/ios/Runner.xcworkspace/contents.xcworkspacedata b/apps/flutter/dev_app/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/flutter/dev_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/flutter/dev_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/apps/flutter/dev_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/flutter/dev_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..d36b1fab2 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 000000000..dc9ada472 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 000000000..7353c41ec Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 000000000..797d452e4 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 000000000..6ed2d933e Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 000000000..4cd7b0099 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 000000000..fe730945a Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 000000000..321773cd8 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 000000000..797d452e4 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 000000000..502f463a9 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 000000000..e9f5fea27 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 000000000..84ac32ae7 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 000000000..8953cba09 Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 000000000..0467bf12a Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 000000000..0bedcf2fd --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 000000000..9da19eaca Binary files /dev/null and b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000..89c2725b7 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/apps/flutter/dev_app/ios/Runner/Base.lproj/LaunchScreen.storyboard b/apps/flutter/dev_app/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000..f2e259c7c --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/ios/Runner/Base.lproj/Main.storyboard b/apps/flutter/dev_app/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000..f3c28516f --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/ios/Runner/Info.plist b/apps/flutter/dev_app/ios/Runner/Info.plist new file mode 100644 index 000000000..5817c0bef --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Abp Flutter + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + dev_app + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/apps/flutter/dev_app/ios/Runner/Runner-Bridging-Header.h b/apps/flutter/dev_app/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000..308a2a560 --- /dev/null +++ b/apps/flutter/dev_app/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/apps/flutter/dev_app/lib/interceptors/api.append.header.interceptor.dart b/apps/flutter/dev_app/lib/interceptors/api.append.header.interceptor.dart new file mode 100644 index 000000000..797fcc030 --- /dev/null +++ b/apps/flutter/dev_app/lib/interceptors/api.append.header.interceptor.dart @@ -0,0 +1,18 @@ +import 'package:core/services/session.service.dart'; +import 'package:core/utils/string.extensions.dart'; +import 'package:dio/dio.dart'; + +class AppendHeaderInterceptor extends Interceptor { + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { + var language = SessionService.to.currentLanguage; + if (!language.isNullOrWhiteSpace()) { + options.headers['Accept-Language'] = language; + } + var tenant = SessionService.to.tenant; + if (tenant != null && tenant.isAvailable == true) { + options.headers['__tenant'] = tenant.id; + } + return handler.next(options); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/interceptors/api.exception.interceptor.dart b/apps/flutter/dev_app/lib/interceptors/api.exception.interceptor.dart new file mode 100644 index 000000000..c0905e35c --- /dev/null +++ b/apps/flutter/dev_app/lib/interceptors/api.exception.interceptor.dart @@ -0,0 +1,37 @@ +import 'package:dev_app/utils/loading.dart'; +import 'package:core/tokens/http.token.dart'; +import 'package:dio/dio.dart'; +import 'package:get/get.dart'; + +class ExceptionInterceptor extends Interceptor { + ExceptionInterceptor(); + + @override + void onError(DioException err, ErrorInterceptorHandler handler) { + if (err.requestOptions.extra.containsKey(HttpTokens.ignoreError)) { + return handler.next(err); + } + var errorMessage = err.message ?? '网络请求失败'; + if (err.response != null) { + if (err.response!.statusCode == 401) { + errorMessage = '您的会话已超时, 请重新登录'; + _showErrorToast(errorMessage); + Get.toNamed('/account/login'); + return; + } + + if (err.response?.data?['error_description'] != null) { + errorMessage = err.response!.data['error_description']; + _showErrorToast(errorMessage); + return handler.next(err); + } + } + + _showErrorToast(errorMessage); + return handler.next(err); + } + + void _showErrorToast(String errorMessage) { + Loading.toast(errorMessage); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/interceptors/index.dart b/apps/flutter/dev_app/lib/interceptors/index.dart new file mode 100644 index 000000000..cda3e2916 --- /dev/null +++ b/apps/flutter/dev_app/lib/interceptors/index.dart @@ -0,0 +1,2 @@ +export 'api.exception.interceptor.dart'; +export 'api.append.header.interceptor.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/main.dart b/apps/flutter/dev_app/lib/main.dart new file mode 100644 index 000000000..3e3a9532d --- /dev/null +++ b/apps/flutter/dev_app/lib/main.dart @@ -0,0 +1,48 @@ +import 'package:dev_app/main.module.dart'; +import 'package:dev_app/utils/localization.dart'; +import 'package:core/utils/theme.utils.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:core/utils/logging.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; + +Future main() async { + final module = MainModule(); + await module.initAsync(); + + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + MainModule module = Get.find(); + return GetMaterialApp( + theme: ThemeUtils.lightTheme, + darkTheme: ThemeUtils.darkTheme, + themeMode: ThemeMode.system, + initialRoute: '/', + getPages: module.getRoutes(), + debugShowMaterialGrid: false, + enableLog: true, + builder: EasyLoading.init(), + translations: AbpTranslations(Get.find()), + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + logWriterCallback: (String text, {bool isError = false}) { + if (isError) { + logger.error(text); + } else { + logger.info(text); + } + }, + //supportedLocales: AbpLocalizations.supportedLocales, + ); + } +} diff --git a/apps/flutter/dev_app/lib/main.module.dart b/apps/flutter/dev_app/lib/main.module.dart new file mode 100644 index 000000000..0a311bfcf --- /dev/null +++ b/apps/flutter/dev_app/lib/main.module.dart @@ -0,0 +1,133 @@ +import 'package:dev_app/pages/index.dart'; +import 'package:dev_app/utils/loading.dart'; +import 'package:account/index.dart'; +import 'package:components/index.dart'; +import 'package:core/modularity/index.dart'; +import 'package:core/index.dart'; +import 'package:dio/dio.dart'; +import 'package:flex_color_scheme/flex_color_scheme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; +import 'package:notifications/notifications.module.dart'; + +import 'interceptors/index.dart'; + +class MainModule extends Module { + @override + List get dependencies => [ + CoreModule(), + AccountModule(), + NotificationsModule(), + ]; + + @override + List get routes => [ + GetPage( + name: '/', + page: () => const MainPage(), + bindings: [ + MainBinding(), + HomeBinding(), + WorkBinding(), + CenterBinding(), + ], + ), + ...PublicRoute.routes, + ...CenterRoute.routes, + ...SystemRoute.routes, + ]; + + @override + void configureServices() { + inject(this); + + inject(SignalrService('${Environment.current.baseUrl}/signalr-hubs/notifications'), + tag: NotificationTokens.producer, + permanent: true); + + lazyInject(() { + var dio = Dio(BaseOptions( + baseUrl: Environment.current.baseUrl, + )); + dio.interceptors.add(LoggerInterceptor()); + dio.interceptors.add(OAuthApiInterceptor()); + dio.interceptors.add(AppendHeaderInterceptor()); + dio.interceptors.add(AbpWrapperRemoteServiceErrorInterceptor()); + dio.interceptors.add(WrapperResultInterceptor()); + dio.interceptors.add(ExceptionInterceptor()); + + return RestService(dio: dio); + }, fenix: true); + + lazyInject(() => OAuthService( + clientId: Environment.current.clientId, + clientSecret: Environment.current.clientSecret + ), fenix: true); + } + + @override + Future>> initAsync() async { + WidgetsFlutterBinding.ensureInitialized(); + await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + await Environment.initAsync(); + Loading(); + + var moduleRoutes = await super.initAsync(); + + initComponent(); + initThemeData(); + + return moduleRoutes; + } + + void initComponent() { + if (!Environment.current.staticFilesUrl.isNullOrWhiteSpace()) { + AvatarConfig.baseUrl = Environment.current.staticFilesUrl!; + } else { + AvatarConfig.baseUrl = '${Environment.current.baseUrl}/api/files/static/users/p/'; + } + } + + void initThemeData() { + ThemeUtils.lightTheme = FlexThemeData.light( + scheme: FlexScheme.amber, + surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold, + blendLevel: 7, + subThemesData: const FlexSubThemesData( + blendOnLevel: 10, + blendOnColors: false, + useTextTheme: true, + useM2StyleDividerInM3: true, + thinBorderWidth: 0.5, + thickBorderWidth: 0.5, + defaultRadius: 0.0, + cardRadius: 6.0, + ), + visualDensity: FlexColorScheme.comfortablePlatformDensity, + useMaterial3: true, + swapLegacyOnMaterial3: true, + // To use the Playground font, add GoogleFonts package and uncomment + // fontFamily: GoogleFonts.notoSans().fontFamily, + ); + ThemeUtils.darkTheme = FlexThemeData.dark( + scheme: FlexScheme.amber, + surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold, + blendLevel: 13, + subThemesData: const FlexSubThemesData( + blendOnLevel: 20, + useTextTheme: true, + useM2StyleDividerInM3: true, + thinBorderWidth: 0.5, + thickBorderWidth: 0.5, + defaultRadius: 0.0, + cardRadius: 6.0, + ), + visualDensity: FlexColorScheme.comfortablePlatformDensity, + useMaterial3: true, + swapLegacyOnMaterial3: true, + // To use the Playground font, add GoogleFonts package and uncomment + // fontFamily: GoogleFonts.notoSans().fontFamily, + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/index.dart b/apps/flutter/dev_app/lib/pages/center/index.dart new file mode 100644 index 000000000..73851406a --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/index.dart @@ -0,0 +1 @@ +export './settings/index.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/route.center.dart b/apps/flutter/dev_app/lib/pages/center/route.center.dart new file mode 100644 index 000000000..46ba57c9f --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/route.center.dart @@ -0,0 +1,14 @@ +import 'package:get/get.dart'; + +import 'index.dart'; +import 'route.name.dart'; + +class CenterRoute { + static List routes = [ + GetPage( + name: CenterRoutes.settings, + page: () => const CenterSettingsPage(), + binding: CenterSettingsBinding(), + ), + ]; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/route.name.dart b/apps/flutter/dev_app/lib/pages/center/route.name.dart new file mode 100644 index 000000000..d7742238f --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/route.name.dart @@ -0,0 +1,4 @@ +class CenterRoutes { + static String settings = '/center/settings'; + static String info = '/center/info'; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/binding.dart b/apps/flutter/dev_app/lib/pages/center/settings/binding.dart new file mode 100644 index 000000000..25e8dbc78 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import 'controller.dart'; + +class CenterSettingsBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => CenterSettingsController()); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/controller.dart b/apps/flutter/dev_app/lib/pages/center/settings/controller.dart new file mode 100644 index 000000000..e28e670e7 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/controller.dart @@ -0,0 +1,70 @@ +import 'package:dev_app/pages/center/settings/state.dart'; +import 'package:core/services/session.service.dart'; +import 'package:core/services/theme.service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_picker/flutter_picker.dart'; +import 'package:get/get.dart'; + +class CenterSettingsController extends GetxController { + SessionService get sessionService => Get.find(); + ThemeService get themeService => Get.find(); + + final Rx _state = Rx(CenterState(false)); + CenterState get state => _state.value; + + @override + void onInit() { + super.onInit(); + sessionService.getProfile$() + .listen((profile) { + _state.update((val) { + val!.isAuthenticated = sessionService.isAuthenticated; + }); + }); + } + + void logout() { + sessionService.resetSession(); + } + + void navigateTo(String route) { + Get.toNamed(route); + } + + /// 主题索引映射 + final Map themeModeMap = { + 0: ThemeMode.light, + 1: ThemeMode.dark, + 2: ThemeMode.system, + }; + /// 当前主题索引 + int get themeModeIndex { + switch (themeService.currentThemeMode) { + case Brightness.light: return 0; + case Brightness.dark: return 1; + default: return 2; + } + } + + /// 切换主题色对话框 + void showThemeModalPicker(BuildContext context) { + var picker = Picker( + adapter: PickerDataAdapter( + pickerData: ['Theme:Light'.tr, 'Theme:Dark'.tr, 'Theme:System'.tr ], + isArray: false, + ), + selecteds: [themeModeIndex], + title: Text('Label:Theme'.tr), + cancelText: 'Lable:Cancel'.tr, + confirmText: 'Lable:Confirm'.tr, + height: 210, + itemExtent: 40, + selectedTextStyle: const TextStyle(color: Colors.blue), + onConfirm: (picker, indexs) { + themeService.changeThemeMode(themeModeMap[indexs[0]]!); + }, + backgroundColor: Theme.of(context).colorScheme.background, + ); + picker.showModal(context); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/index.dart b/apps/flutter/dev_app/lib/pages/center/settings/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/state.dart b/apps/flutter/dev_app/lib/pages/center/settings/state.dart new file mode 100644 index 000000000..4447adf26 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/state.dart @@ -0,0 +1,4 @@ +class CenterState { + CenterState(this.isAuthenticated); + bool isAuthenticated; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/view.dart b/apps/flutter/dev_app/lib/pages/center/settings/view.dart new file mode 100644 index 000000000..55a44a6aa --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/view.dart @@ -0,0 +1,43 @@ +import 'package:dev_app/pages/system/route.name.dart'; +import 'package:account/pages/route.name.dart'; +import 'package:notifications/pages/route.name.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'controller.dart'; +import 'widget/index.dart'; + +class CenterSettingsPage extends GetView { + const CenterSettingsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Center:Settings'.tr), + ), + body: ListView( + children: [ + ActionCard( + onSwitchTheme: () { + controller.showThemeModalPicker(context); + }, + onNotifierSettings: () { + controller.navigateTo(NotificationRoutes.manageNotifier); + }, + onSystemSettings: () { + controller.navigateTo(SystemRoutes.settings); + }, + onAccountSettings: () { + controller.navigateTo(AccountRoutes.profile); + }, + ), + Obx(() => ButtonGroup( + isAuthenticated: controller.state.isAuthenticated, + onLogout: controller.logout, + )), + ], + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/widget/action_card.dart b/apps/flutter/dev_app/lib/pages/center/settings/widget/action_card.dart new file mode 100644 index 000000000..113bd907a --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/widget/action_card.dart @@ -0,0 +1,75 @@ + + +import 'package:components/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class ActionCard extends StatelessWidget { + const ActionCard({ + super.key, + this.onSwitchTheme, + this.onAccountSettings, + this.onSystemSettings, + this.onNotifierSettings, + this.onCleanCache, + }); + + final VoidCallback? onSwitchTheme; + final VoidCallback? onAccountSettings; + final VoidCallback? onSystemSettings; + final VoidCallback? onNotifierSettings; + final VoidCallback? onCleanCache; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only(top: 12), + child: Column( + children: [ + /// 主题设置 + _actionButton( + title: 'Label:SwitchTheme'.tr, + onTap: onSwitchTheme, + ), + /// 账号设置 + _actionButton( + title: 'Label:AccountSettings'.tr, + onTap: onAccountSettings, + ), + _actionButton( + title: 'Label:SystemSettings'.tr, + onTap: onSystemSettings, + ), + _actionButton( + title: 'Label:NotifierSettings'.tr, + onTap: onNotifierSettings, + ), + _actionButton( + title: 'Label:CleanCache'.tr, + onTap: onCleanCache, + ), + ], + ), + ); + } + + Widget _actionButton( + { + required String title, + IconData? prefixIcon, + Color? prefixIconColor, + VoidCallback? onTap, + } + ) { + return Container( + height: 50, + alignment: Alignment.center, + child: ActionButton( + title: title, + onTap: onTap, + prefixIcon: prefixIcon, + prefixIconColor: prefixIconColor, + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/widget/button_group.dart b/apps/flutter/dev_app/lib/pages/center/settings/widget/button_group.dart new file mode 100644 index 000000000..390821a35 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/widget/button_group.dart @@ -0,0 +1,47 @@ +import 'package:components/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class ButtonGroup extends StatelessWidget { + const ButtonGroup({ + super.key, + this.isAuthenticated, + this.onLogout, + }); + + final bool? isAuthenticated; + final VoidCallback? onLogout; + + @override + Widget build(BuildContext context) { + final media = MediaQuery.of(context).size; + return Container( + padding: const EdgeInsets.only(top: 16), + child: Column( + children: [ + Container( + height: 44, + width: media.width / 1.2, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(22)) + ), + child: _logoutButton(), + ), + ], + ), + ); + } + + Widget _logoutButton() { + if (isAuthenticated == true) { + return BottomButton( + title: 'Label:Logout'.tr, + onPressed: () { + onLogout?.call(); + }, + ); + } + + return Empty.none; + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/widget/index.dart b/apps/flutter/dev_app/lib/pages/center/settings/widget/index.dart new file mode 100644 index 000000000..b3c9b8f27 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/widget/index.dart @@ -0,0 +1,2 @@ +export 'action_card.dart'; +export 'button_group.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/center/settings/widget/user_info_card.dart b/apps/flutter/dev_app/lib/pages/center/settings/widget/user_info_card.dart new file mode 100644 index 000000000..5ceb4c048 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/center/settings/widget/user_info_card.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +import '../controller.dart'; + +class UserInfoCard extends StatelessWidget { + const UserInfoCard({ + super.key, + required this.controller, + }); + + final CenterSettingsController controller; + + @override + Widget build(BuildContext context) { + return Container(); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/index.dart b/apps/flutter/dev_app/lib/pages/index.dart new file mode 100644 index 000000000..5c8afa8d6 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/index.dart @@ -0,0 +1,7 @@ +export './main/index.dart'; +export './center/index.dart'; +export './center/route.center.dart'; +export './public/index.dart'; +export './public/route.public.dart'; +export './system/index.dart'; +export './system/route.system.dart'; diff --git a/apps/flutter/dev_app/lib/pages/main/binding.dart b/apps/flutter/dev_app/lib/pages/main/binding.dart new file mode 100644 index 000000000..791d2bfdd --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/main/binding.dart @@ -0,0 +1,13 @@ +import 'package:core/services/subscription.service.dart'; +import 'package:core/tokens/index.dart'; +import 'package:get/get.dart'; + +import 'controller.dart'; + +class MainBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => MainController()); + Get.lazyPut(() => SubscriptionService(), tag: NotificationTokens.consumer); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/main/controller.dart b/apps/flutter/dev_app/lib/pages/main/controller.dart new file mode 100644 index 000000000..2dc45ad36 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/main/controller.dart @@ -0,0 +1,56 @@ +import 'package:get/get.dart'; +import 'package:core/config/index.dart'; +import 'package:core/services/config.state.service.dart'; +import 'package:core/services/session.service.dart'; +import 'package:core/services/signalr.service.dart'; +import 'package:core/services/subscription.service.dart'; +import 'package:core/tokens/index.dart'; +import 'package:core/utils/index.dart'; +import 'package:notifications/models/notification.dart'; + +class MainController extends GetxController { + final RxInt _pageIndex = RxInt(0); + int get currentIndex => _pageIndex.value; + + SessionService get sessionService => Get.find(); + ConfigStateService get configStateService => Get.find(); + SubscriptionService get subscriptionService => Get.find(tag: NotificationTokens.consumer); + SignalrService get signalrService => Get.find(tag: NotificationTokens.producer); + + @override + void onInit() async { + super.onInit(); + subscriptionService.addOne(signalrService.onClose(logger.debug)); + subscriptionService.addOne(signalrService.onReconnected(logger.debug)); + subscriptionService.addOne(signalrService.onReconnecting(logger.debug)); + subscriptionService.subscribe( + signalrService.subscribe(NotificationTokens.receiver), + (message) { + var notification = NotificationInfo.fromJson(message.data.first as dynamic); + logger.debug(notification); + }, + ); + sessionService.getToken$() + .listen((token) async { + if (token == null) { + await signalrService.stop(); + } else { + await signalrService.start(); + } + }); + if (sessionService.currentLanguage.isNullOrWhiteSpace()) { + sessionService.setLanguage(Environment.current.defaultLanguage ?? 'en'); + } + } + + @override + void onClose() { + subscriptionService.closeAll() + .whenComplete(() => signalrService.stop()); + super.onClose(); + } + + void setCurrentIndex(int index) { + _pageIndex.value = index; + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/main/index.dart b/apps/flutter/dev_app/lib/pages/main/index.dart new file mode 100644 index 000000000..c476a7281 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/main/index.dart @@ -0,0 +1,3 @@ +export 'view.dart'; +export 'binding.dart'; +export 'controller.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/main/view.dart b/apps/flutter/dev_app/lib/pages/main/view.dart new file mode 100644 index 000000000..7b7945ea0 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/main/view.dart @@ -0,0 +1,48 @@ +import 'package:dev_app/pages/public/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'controller.dart'; + +class MainPage extends GetView { + const MainPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + bottomNavigationBar: Obx(() => BottomNavigationBar( + onTap: (int index) { + controller.setCurrentIndex(index); + }, + currentIndex: controller.currentIndex, + items: [ + _bottomNavigationBarItem(Icons.home, 'Page:Home'.tr), + _bottomNavigationBarItem(Icons.layers, 'Page:Work'.tr), + _bottomNavigationBarItem(Icons.person, 'Page:Center'.tr), + ], + )), + body: Obx(() => [ + Container( + alignment: Alignment.center, + child: const HomePage(), + ), + Container( + alignment: Alignment.center, + child: const WorkPage(), + ), + Container( + alignment: Alignment.center, + child: const CenterPage(), + ), + ][controller.currentIndex]), + ); + } + + BottomNavigationBarItem _bottomNavigationBarItem(IconData activeIcon, String title){ + return BottomNavigationBarItem( + icon: Icon(activeIcon), // 图标 + activeIcon: Icon(activeIcon), // 高亮图标 + label: title, // 标题 背景色,仅在 BottomNavigatinBar 中生效,在 iOS 风格组件中无效 + ); + } +} diff --git a/apps/flutter/dev_app/lib/pages/public/center/binding.dart b/apps/flutter/dev_app/lib/pages/public/center/binding.dart new file mode 100644 index 000000000..86c32d2d8 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'controller.dart'; + +class CenterBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => CenterController()); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/controller.dart b/apps/flutter/dev_app/lib/pages/public/center/controller.dart new file mode 100644 index 000000000..e33b8f7ca --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/controller.dart @@ -0,0 +1,50 @@ +import 'package:core/models/auth.dart'; +import 'package:core/services/session.service.dart'; +import 'package:get/get.dart'; + +import 'state.dart'; + +class CenterController extends GetxController { + SessionService get sessionService => Get.find(); + + final Rx _state = Rx(CenterState(isAuthenticated: false)); + CenterState get state => _state.value; + + bool get isAuthenticated => state.isAuthenticated; + UserProfile? get profile => state.profile; + Token? get token => state.token; + + @override + void onInit() { + super.onInit(); + sessionService.getProfile$() + .listen((event) { + _state.update((val) { + val?.profile = event; + val?.isAuthenticated = sessionService.isAuthenticated; + }); + }); + sessionService.getToken$() + .listen((event) { + _state.update((val) { + val?.token = event; + }); + }); + } + + String get userName { + return !isAuthenticated ? 'Label:Anonymous'.tr : profile!.userName; + } + + String get phoneNumber { + return !isAuthenticated ? '' : profile!.phoneNumber ?? 'Label:PhoneNumberNotBound'.tr; + } + + void redirectToRoute(String route) { + Get.toNamed(route); + } + + void changeLocale(String locale) { + sessionService.setLanguage(locale); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/index.dart b/apps/flutter/dev_app/lib/pages/public/center/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/state.dart b/apps/flutter/dev_app/lib/pages/public/center/state.dart new file mode 100644 index 000000000..ec29fb9a6 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/state.dart @@ -0,0 +1,12 @@ +import 'package:core/models/auth.dart'; + +class CenterState { + CenterState({ + required this.isAuthenticated, + this.token, + this.profile, + }); + Token? token; + UserProfile? profile; + bool isAuthenticated; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/view.dart b/apps/flutter/dev_app/lib/pages/public/center/view.dart new file mode 100644 index 000000000..5c9599c7e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/view.dart @@ -0,0 +1,55 @@ +import 'package:dev_app/pages/center/route.name.dart'; +import 'package:account/pages/route.name.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import './widget/index.dart'; +import 'controller.dart'; + +class CenterPage extends GetView { + const CenterPage({super.key}); + + @override + Widget build(BuildContext context) { + return ListView( + children: [ + Stack( + children: [ + const StatusBar(), + Container( + height: 100, + margin: const EdgeInsets.only(top: 130, left: 20, right: 20), + child: Obx(() => UserCard( + avatarUrl: controller.profile?.avatarUrl, + takeToken: controller.token?.accessToken, + userName: controller.userName, + phoneNumber: controller.phoneNumber, + onTap: () { + if (!controller.isAuthenticated) { + controller.redirectToRoute(AccountRoutes.login); + } + else + { + controller.redirectToRoute(AccountRoutes.profile); + } + }, + )), + ), + ], + ), + Container( + margin: const EdgeInsets.only(top: 20, left: 20, right: 20), + child: ActionCard( + onHelp: () { + //controller.redirectToRoute('/center/help'); + }, + onFeedback: () { + //controller.redirectToRoute('/center/feedback'); + }, + onSettings: () => controller.redirectToRoute(CenterRoutes.settings), + onInfo: () => controller.redirectToRoute(CenterRoutes.info), + )), + ], + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/widget/action_card.dart b/apps/flutter/dev_app/lib/pages/public/center/widget/action_card.dart new file mode 100644 index 000000000..e7845255e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/widget/action_card.dart @@ -0,0 +1,73 @@ +import 'package:components/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class ActionCard extends StatelessWidget { + const ActionCard({ + super.key, + this.onHelp, + this.onFeedback, + this.onSettings, + this.onInfo, + }); + + final VoidCallback? onHelp; + final VoidCallback? onFeedback; + final VoidCallback? onSettings; + final VoidCallback? onInfo; + + @override + Widget build(BuildContext context) { + return Card( + child: Column( + children: [ + _actionButton( + title: 'Center:Help'.tr, + prefixIcon: Icons.help, + prefixIconColor: Colors.blue, + onTap: onHelp, + ), + _actionButton( + title: 'Center:Feedback'.tr, + prefixIcon: Icons.feedback, + prefixIconColor: Colors.orange, + onTap: onFeedback, + ), + _actionButton( + title: 'Center:Settings'.tr, + prefixIcon: Icons.settings, + prefixIconColor: Colors.red, + onTap: onSettings, + ), + _actionButton( + title: 'Center:Info'.tr, + prefixIcon: Icons.info, + prefixIconColor: Colors.greenAccent, + onTap: onInfo, + ), + ], + ), + ); + } + + Widget _actionButton( + { + required String title, + required IconData prefixIcon, + required Color prefixIconColor, + VoidCallback? onTap, + } + ) { + return Container( + height: 50, + alignment: Alignment.center, + margin: const EdgeInsets.only(left: 10, right: 10, top: 10), + child: ActionButton( + title: title, + prefixIcon: prefixIcon, + prefixIconColor: prefixIconColor, + onTap: onTap, + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/widget/index.dart b/apps/flutter/dev_app/lib/pages/public/center/widget/index.dart new file mode 100644 index 000000000..39ec42281 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/widget/index.dart @@ -0,0 +1,3 @@ +export './user_card.dart'; +export './status_bar.dart'; +export 'action_card.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/widget/status_bar.dart b/apps/flutter/dev_app/lib/pages/public/center/widget/status_bar.dart new file mode 100644 index 000000000..8b3abe403 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/widget/status_bar.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +class StatusBar extends StatelessWidget { + const StatusBar({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Container( + height: 190, + decoration: const BoxDecoration( + color: Color.fromARGB(255, 98, 168, 200), + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/center/widget/user_card.dart b/apps/flutter/dev_app/lib/pages/public/center/widget/user_card.dart new file mode 100644 index 000000000..8fa3bfb00 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/center/widget/user_card.dart @@ -0,0 +1,60 @@ +import 'package:components/index.dart'; +import 'package:flutter/material.dart'; + +class UserCard extends StatelessWidget { + const UserCard({ + super.key, + required this.userName, + required this.phoneNumber, + this.avatarUrl, + this.takeToken, + this.onTap, + }); + + final String userName; + final String phoneNumber; + final String? avatarUrl; + final String? takeToken; + final VoidCallback? onTap; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + borderRadius: const BorderRadius.all(Radius.circular(12)), + child: Card( + child: Row( + children: [ + Container( + margin: const EdgeInsets.only(left: 10), + width: 50, + child: Avatar( + url: avatarUrl, + hintText: userName, + takeToken: takeToken, + ), + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(userName, + style: Theme.of(context).textTheme.titleMedium, + ), + Opacity( + opacity: 0.6, + child: Text(phoneNumber, + style: Theme.of(context).textTheme.bodySmall, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/home/binding.dart b/apps/flutter/dev_app/lib/pages/public/home/binding.dart new file mode 100644 index 000000000..22303b1cb --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/home/binding.dart @@ -0,0 +1,9 @@ +import 'controller.dart'; +import 'package:get/get.dart'; + +class HomeBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => HomeController()); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/home/controller.dart b/apps/flutter/dev_app/lib/pages/public/home/controller.dart new file mode 100644 index 000000000..751849dfe --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/home/controller.dart @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +class HomeController extends GetxController { + +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/home/index.dart b/apps/flutter/dev_app/lib/pages/public/home/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/home/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/home/view.dart b/apps/flutter/dev_app/lib/pages/public/home/view.dart new file mode 100644 index 000000000..3d28ce29a --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/home/view.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +import 'controller.dart'; +import 'package:get/get.dart'; + +class HomePage extends GetView { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return Center( + child: Text('Page:Home'.tr), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/index.dart b/apps/flutter/dev_app/lib/pages/public/index.dart new file mode 100644 index 000000000..aee3141ae --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/index.dart @@ -0,0 +1,3 @@ +export './center/index.dart'; +export './home/index.dart'; +export './work/index.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/route.name.dart b/apps/flutter/dev_app/lib/pages/public/route.name.dart new file mode 100644 index 000000000..4361f2488 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/route.name.dart @@ -0,0 +1,5 @@ +class PublicRoutes { + static String home = '/home'; + static String work = '/work'; + static String center = '/center'; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/route.public.dart b/apps/flutter/dev_app/lib/pages/public/route.public.dart new file mode 100644 index 000000000..b4d6a39f5 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/route.public.dart @@ -0,0 +1,24 @@ +import 'package:get/get.dart'; + +import 'index.dart'; +import 'route.name.dart'; + +class PublicRoute { + static List routes = [ + GetPage( + name: PublicRoutes.home, + page: () => const HomePage(), + binding: HomeBinding(), + ), + GetPage( + name: PublicRoutes.work, + page: () => const WorkPage(), + binding: WorkBinding(), + ), + GetPage( + name: PublicRoutes.center, + page: () => const CenterPage(), + binding: CenterBinding(), + ), + ]; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/work/binding.dart b/apps/flutter/dev_app/lib/pages/public/work/binding.dart new file mode 100644 index 000000000..82fbb0166 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/work/binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'controller.dart'; + +class WorkBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => WorkController()); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/work/controller.dart b/apps/flutter/dev_app/lib/pages/public/work/controller.dart new file mode 100644 index 000000000..a03b6acd8 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/work/controller.dart @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +class WorkController extends GetxController { + +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/work/index.dart b/apps/flutter/dev_app/lib/pages/public/work/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/work/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/public/work/view.dart b/apps/flutter/dev_app/lib/pages/public/work/view.dart new file mode 100644 index 000000000..9a5b37d69 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/public/work/view.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +import 'controller.dart'; +import 'package:get/get.dart'; + +class WorkPage extends GetView { + const WorkPage({super.key}); + + @override + Widget build(BuildContext context) { + return Center( + child: Text('Page:Work'.tr), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/index.dart b/apps/flutter/dev_app/lib/pages/system/index.dart new file mode 100644 index 000000000..73851406a --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/index.dart @@ -0,0 +1 @@ +export './settings/index.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/route.name.dart b/apps/flutter/dev_app/lib/pages/system/route.name.dart new file mode 100644 index 000000000..7c7d39274 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/route.name.dart @@ -0,0 +1,3 @@ +class SystemRoutes { + static String settings = '/system/settings'; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/route.system.dart b/apps/flutter/dev_app/lib/pages/system/route.system.dart new file mode 100644 index 000000000..a4b48178c --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/route.system.dart @@ -0,0 +1,14 @@ +import 'index.dart'; +import 'package:get/get.dart'; + +import 'route.name.dart'; + +class SystemRoute { + static List routes = [ + GetPage( + name: SystemRoutes.settings, + page: () => const SystemSettingsPage(), + binding: SystemSettingsBinding(), + ), + ]; +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/binding.dart b/apps/flutter/dev_app/lib/pages/system/settings/binding.dart new file mode 100644 index 000000000..15b1ffe41 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import 'controller.dart'; + +class SystemSettingsBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => SystemSettingsController()); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/controller.dart b/apps/flutter/dev_app/lib/pages/system/settings/controller.dart new file mode 100644 index 000000000..b26160553 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/controller.dart @@ -0,0 +1,56 @@ +import 'package:core/services/index.dart'; +import 'package:core/utils/string.extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'state.dart'; + +class SystemSettingsController extends GetxController { + SessionService get sessionService => Get.find(); + ConfigStateService get configStateService => Get.find(); + + final Rx _state = Rx(SettingsState( + languages: [], + )); + SettingsState get state => _state.value; + + bool inProgress = false; + GlobalKey formKey = GlobalKey(); + + void onLanguageChange(String? language) { + _state.update((val) { + val?.language = language; + }); + } + + void submit() { + if (formKey.currentState?.validate() == false || inProgress) { + return; + } + if (!state.language.isNullOrWhiteSpace()) { + sessionService.setLanguage(state.language!); + } + } + + void _initLanguages() { + var localization = configStateService.getLocalization(); + _state.update((val) { + val?.languages = localization?.languages; + }); + } + + @override + void onInit() { + super.onInit(); + _initLanguages(); + _state.update((val) { + val?.language = sessionService.currentLanguage; + }); + } + + @override + void onClose() { + _state.close(); + super.onClose(); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/index.dart b/apps/flutter/dev_app/lib/pages/system/settings/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/state.dart b/apps/flutter/dev_app/lib/pages/system/settings/state.dart new file mode 100644 index 000000000..594956b4f --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/state.dart @@ -0,0 +1,16 @@ +import 'package:core/abstracts/copy.with.dart'; +import 'package:core/proxy/volo/abp/localization/index.dart'; + +class SettingsState extends CloneObject { + SettingsState({ + this.language, + this.languages, + }); + String? language; + List? languages; + + @override + SettingsState clone() => SettingsState( + language: language, + ); +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/view.dart b/apps/flutter/dev_app/lib/pages/system/settings/view.dart new file mode 100644 index 000000000..a224d7ee8 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/view.dart @@ -0,0 +1,47 @@ +import 'package:components/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'controller.dart'; +import './widget/index.dart'; + +class SystemSettingsPage extends GetView { + const SystemSettingsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Label:SystemSettings'.tr), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + child: Column( + children: [ + Expanded( + child: Form( + key: controller.formKey, + child: Column( + children: [ + Obx(() => LanguageCard( + defaultLanguage: controller.state.language, + languages: controller.state.languages, + onChange: controller.onLanguageChange, + )), + ], + ), + ), + ), + BottomButton( + title: 'Label:Submit'.tr, + onPressed: controller.submit, + titleStyle: const TextStyle( + letterSpacing: 2, + ), + ), + ], + ), + )), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/widget/index.dart b/apps/flutter/dev_app/lib/pages/system/settings/widget/index.dart new file mode 100644 index 000000000..d20de8fe3 --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/widget/index.dart @@ -0,0 +1 @@ +export 'language.dart'; \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/pages/system/settings/widget/language.dart b/apps/flutter/dev_app/lib/pages/system/settings/widget/language.dart new file mode 100644 index 000000000..1e73158ec --- /dev/null +++ b/apps/flutter/dev_app/lib/pages/system/settings/widget/language.dart @@ -0,0 +1,59 @@ +import 'package:core/proxy/volo/abp/localization/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class LanguageCard extends StatelessWidget { + const LanguageCard({ + super.key, + this.defaultLanguage, + this.languages, + this.onChange, + }); + + final String? defaultLanguage; + final List? languages; + final void Function(String? value)? onChange; + + List> _languageList() { + if (languages?.isEmpty == true) return []; + List> languageItems = []; + for (var language in languages!) { + languageItems.add( + DropdownMenuItem( + value: language.cultureName, + enabled: language.cultureName != defaultLanguage, + child: Text(language.displayName!), + ) + ); + } + return languageItems; + } + + @override + Widget build(BuildContext context) { + return ExpansionTile( + initiallyExpanded: true, + title: Text('Languages'.tr, + style: Theme.of(context).textTheme.titleMedium, + ), + children: [ + ListTile( + title: Text('DisplayName:Abp.Localization.DefaultLanguage'.tr), + subtitle: Text('Description:Abp.Localization.DefaultLanguage'.tr), + trailing: DropdownButton( + onChanged: onChange, + value: defaultLanguage, + items: _languageList(), + ), + ), + // _actionButton( + // title: '系统语言', + // suffix: Text('请选择'), + // onTap: () { + + // }, + // ), + ], + ); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/utils/loading.dart b/apps/flutter/dev_app/lib/utils/loading.dart new file mode 100644 index 000000000..d4e0476d3 --- /dev/null +++ b/apps/flutter/dev_app/lib/utils/loading.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; + +class Loading { + Loading() { + EasyLoading.instance + ..displayDuration = const Duration(milliseconds: 2000) + ..indicatorType = EasyLoadingIndicatorType.ring + ..loadingStyle = EasyLoadingStyle.custom + ..indicatorSize = 35.0 + ..lineWidth = 2 + ..radius = 10.0 + ..progressColor = Colors.white + ..backgroundColor = Colors.black.withOpacity(0.7) + ..indicatorColor = Colors.white + ..textColor = Colors.white + ..maskColor = Colors.black.withOpacity(0.6) + ..userInteractions = true + ..dismissOnTap = false + ..maskType = EasyLoadingMaskType.custom; + } + + static void show([String? text]) { + EasyLoading.instance.userInteractions = false; + EasyLoading.show(status: text ?? 'Loading...'); + } + + static void toast(String text) { + EasyLoading.showToast(text); + } + + static void dismiss() { + EasyLoading.instance.userInteractions = true; + EasyLoading.dismiss(); + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/lib/utils/localization.dart b/apps/flutter/dev_app/lib/utils/localization.dart new file mode 100644 index 000000000..e3c977e58 --- /dev/null +++ b/apps/flutter/dev_app/lib/utils/localization.dart @@ -0,0 +1,9 @@ +import 'package:core/services/localization.service.dart'; +import 'package:get/get.dart'; + +class AbpTranslations extends Translations { + AbpTranslations(this.localizationService); + final LocalizationService localizationService; + @override + Map> get keys => localizationService.getResources(); +} \ No newline at end of file diff --git a/apps/flutter/dev_app/linux/.gitignore b/apps/flutter/dev_app/linux/.gitignore new file mode 100644 index 000000000..d3896c984 --- /dev/null +++ b/apps/flutter/dev_app/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/apps/flutter/dev_app/linux/CMakeLists.txt b/apps/flutter/dev_app/linux/CMakeLists.txt new file mode 100644 index 000000000..10df4492c --- /dev/null +++ b/apps/flutter/dev_app/linux/CMakeLists.txt @@ -0,0 +1,139 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "dev_app") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.dev_app") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/apps/flutter/dev_app/linux/flutter/CMakeLists.txt b/apps/flutter/dev_app/linux/flutter/CMakeLists.txt new file mode 100644 index 000000000..d5bd01648 --- /dev/null +++ b/apps/flutter/dev_app/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/apps/flutter/dev_app/linux/flutter/generated_plugin_registrant.cc b/apps/flutter/dev_app/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/apps/flutter/dev_app/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/apps/flutter/dev_app/linux/flutter/generated_plugin_registrant.h b/apps/flutter/dev_app/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/apps/flutter/dev_app/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/dev_app/linux/flutter/generated_plugins.cmake b/apps/flutter/dev_app/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2e1de87a7 --- /dev/null +++ b/apps/flutter/dev_app/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/dev_app/linux/main.cc b/apps/flutter/dev_app/linux/main.cc new file mode 100644 index 000000000..e7c5c5437 --- /dev/null +++ b/apps/flutter/dev_app/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/apps/flutter/dev_app/linux/my_application.cc b/apps/flutter/dev_app/linux/my_application.cc new file mode 100644 index 000000000..4ccd18ef5 --- /dev/null +++ b/apps/flutter/dev_app/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "dev_app"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "dev_app"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/apps/flutter/dev_app/linux/my_application.h b/apps/flutter/dev_app/linux/my_application.h new file mode 100644 index 000000000..72271d5e4 --- /dev/null +++ b/apps/flutter/dev_app/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/apps/flutter/dev_app/macos/.gitignore b/apps/flutter/dev_app/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/apps/flutter/dev_app/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/apps/flutter/dev_app/macos/Flutter/Flutter-Debug.xcconfig b/apps/flutter/dev_app/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..c2efd0b60 --- /dev/null +++ b/apps/flutter/dev_app/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/apps/flutter/dev_app/macos/Flutter/Flutter-Release.xcconfig b/apps/flutter/dev_app/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..c2efd0b60 --- /dev/null +++ b/apps/flutter/dev_app/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/apps/flutter/dev_app/macos/Runner.xcodeproj/project.pbxproj b/apps/flutter/dev_app/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..abdc679d6 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,695 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* dev_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "dev_app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* dev_app.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* dev_app.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dev_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/dev_app"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dev_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/dev_app"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/dev_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/dev_app"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/apps/flutter/dev_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/flutter/dev_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/apps/flutter/dev_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/flutter/dev_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..c6cb55247 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/macos/Runner.xcworkspace/contents.xcworkspacedata b/apps/flutter/dev_app/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..1d526a16e --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/flutter/dev_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/flutter/dev_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 000000000..82b6f9d9a Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 000000000..13b35eba5 Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 000000000..0a3f5fa40 Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 000000000..bdb57226d Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 000000000..f083318e0 Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 000000000..326c0e72c Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 000000000..2f1632cfd Binary files /dev/null and b/apps/flutter/dev_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/apps/flutter/dev_app/macos/Runner/Base.lproj/MainMenu.xib b/apps/flutter/dev_app/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..80e867a4e --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/macos/Runner/Configs/AppInfo.xcconfig b/apps/flutter/dev_app/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..0c2e0c581 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = dev_app + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.abpFlutter + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/apps/flutter/dev_app/macos/Runner/Configs/Debug.xcconfig b/apps/flutter/dev_app/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/apps/flutter/dev_app/macos/Runner/Configs/Release.xcconfig b/apps/flutter/dev_app/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/apps/flutter/dev_app/macos/Runner/Configs/Warnings.xcconfig b/apps/flutter/dev_app/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/apps/flutter/dev_app/macos/Runner/DebugProfile.entitlements b/apps/flutter/dev_app/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..dddb8a30c --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/apps/flutter/dev_app/macos/Runner/Info.plist b/apps/flutter/dev_app/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/apps/flutter/dev_app/macos/Runner/Release.entitlements b/apps/flutter/dev_app/macos/Runner/Release.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/apps/flutter/dev_app/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/apps/flutter/dev_app/pubspec.lock b/apps/flutter/dev_app/pubspec.lock new file mode 100644 index 000000000..2aed3ee66 --- /dev/null +++ b/apps/flutter/dev_app/pubspec.lock @@ -0,0 +1,534 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + account: + dependency: "direct main" + description: + path: "../account" + relative: true + source: path + version: "0.0.1" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.17.1" + components: + dependency: "direct main" + description: + path: "../components" + relative: true + source: path + version: "0.0.1" + core: + dependency: "direct main" + description: + path: "../core" + relative: true + source: path + version: "0.0.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.3" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + dart_either: + dependency: transitive + description: + name: dart_either + sha256: "928895b8266ac5906eb4e2993fead563a73b17fc86eec6b40172100d56ca2507" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + dio: + dependency: "direct main" + description: + name: dio + sha256: a9d76e72985d7087eb7c5e7903224ae52b337131518d127c554b9405936752b8 + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.1+1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "6.1.4" + flex_color_scheme: + dependency: "direct main" + description: + name: flex_color_scheme + sha256: "5be124fa61821a684c0628ca5f687a8512db06738f784516278688eb727a3ef1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "7.1.2" + flex_seed_scheme: + dependency: transitive + description: + name: flex_seed_scheme + sha256: "29c12aba221eb8a368a119685371381f8035011d18de5ba277ad11d7dfb8657f" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_app_environment: + dependency: transitive + description: + name: flutter_app_environment + sha256: "329cef61e9fa42bdae560d1a86fdf37dd242cd0efff9b2f5f2a7ca1081b6809a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + flutter_easyloading: + dependency: "direct main" + description: + name: flutter_easyloading + sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.5" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_picker: + dependency: "direct main" + description: + name: flutter_picker + sha256: "2f94c6eefba8697b07e3cd008b75f06b4ba7053cb26d23ae0fcd5932b7dc75af" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.0" + flutter_spinkit: + dependency: transitive + description: + name: flutter_spinkit + sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + get: + dependency: "direct main" + description: + name: get + sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.6.5" + get_storage: + dependency: "direct main" + description: + name: get_storage + sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + http: + dependency: transitive + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.13.6" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.2" + intl: + dependency: transitive + description: + name: intl + sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.18.0" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.8.1" + lints: + dependency: transitive + description: + name: lints + sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + logger: + dependency: transitive + description: + name: logger + sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" + logging: + dependency: "direct dev" + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.15" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.0" + message_pack_dart: + dependency: transitive + description: + name: message_pack_dart + sha256: "71b9f0ff60e5896e60b337960bb535380d7dba3297b457ac763ccae807385b59" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + meta: + dependency: transitive + description: + name: meta + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.1" + notifications: + dependency: "direct main" + description: + path: "../notifications" + relative: true + source: path + version: "0.0.1" + path: + dependency: transitive + description: + name: path + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.15" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.27" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.3" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.11" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.6" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.7" + platform: + dependency: transitive + description: + name: platform + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + process: + dependency: transitive + description: + name: process + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.2.4" + rxdart: + dependency: "direct main" + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.27.7" + rxdart_ext: + dependency: "direct main" + description: + name: rxdart_ext + sha256: ca0b07216b4568e70d88154efd893ded54cf8cea43276c66baae245a843c326f + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.9" + signalr_netcore: + dependency: "direct dev" + description: + name: signalr_netcore + sha256: "400ced9b03644706fbbc317fd50f4f08c2c0ae4d164082365788f1734b904437" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.4" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.1" + sse_client: + dependency: transitive + description: + name: sse_client + sha256: "71bd826430b41ab20a69d85bf2dfe9f11cfe222938e681ada1aea71fc8adf348" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.11.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.1" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.2" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" + win32: + dependency: transitive + description: + name: win32 + sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.5" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" +sdks: + dart: ">=3.0.5 <4.0.0" + flutter: ">=3.10.0" diff --git a/apps/flutter/dev_app/pubspec.yaml b/apps/flutter/dev_app/pubspec.yaml new file mode 100644 index 000000000..21c92ee01 --- /dev/null +++ b/apps/flutter/dev_app/pubspec.yaml @@ -0,0 +1,114 @@ +name: dev_app +description: A new Flutter project. +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# 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. +version: 1.0.0+1 + +environment: + sdk: '>=3.0.5 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + core: + path: '../core' + components: + path: '../components' + + # Modules + account: + path: '../account' + notifications: + path: '../notifications' + + dio: + flutter_easyloading: + flutter_picker: + get: + get_storage: + rxdart: + rxdart_ext: + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + flex_color_scheme: ^7.1.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 + + logging: ^1.0.1 + signalr_netcore: ^1.3.4 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - res/config/ + - res/images/ + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/apps/flutter/dev_app/res/config/demo.json b/apps/flutter/dev_app/res/config/demo.json new file mode 100644 index 000000000..2bf590388 --- /dev/null +++ b/apps/flutter/dev_app/res/config/demo.json @@ -0,0 +1,10 @@ +{ + "baseUrl": "http://127.0.0.1:30000", + "clientId": "abp-flutter", + "clientSecret": "1q2w3e*", + "authority": "http://127.0.0.1:30000", + "uploadFilesUrl": "", + "staticFilesUrl": "", + "tenantKey": "__tenant", + "defaultLanguage": "en" +} \ No newline at end of file diff --git a/apps/flutter/dev_app/test/widget_test.dart b/apps/flutter/dev_app/test/widget_test.dart new file mode 100644 index 000000000..e39b0234c --- /dev/null +++ b/apps/flutter/dev_app/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:dev_app/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/apps/flutter/dev_app/translation.json b/apps/flutter/dev_app/translation.json new file mode 100644 index 000000000..de59c063e --- /dev/null +++ b/apps/flutter/dev_app/translation.json @@ -0,0 +1,43 @@ +{ + "culture": "en", + "texts": { + "Center:Feedback": "Feedback", + "Center:Help": "Help", + "Center:Info": "Info", + "Center:Settings": "Settings", + "Label:AccountSettings": "Account Settings", + "Label:Anonymous": "Anonymous", + "Label:CleanCache": "Clean Cache", + "Label:ClickToLogin": "Click to login", + "Label:EnableNotificationSubTitle": "Enable to support global notifications", + "Label:EnableNotificationTitle": "Enable Notification", + "Label:ForgotPassword": "Forgot password?", + "Label:Login": "Login", + "Label:LoginSubTitle": "Log in to continue", + "Label:LoginTitle": "Welcome to login", + "Label:Logout": "Logout", + "Label:NoAccount": "No account?", + "Label:NotificationsSubTitle": "List of supported notification types", + "Label:NotificationsTitle": "Notifications", + "Label:NotifierSettings": "Notifier Settings", + "Label:PasswordRequired": "Please enter password", + "Label:PhoneNumberNotBound": "PhoneNumber Not Bound", + "Label:Submit": "Submit", + "Label:SwitchTheme": "Switch Theme", + "Label:SystemSettings": "System Settings", + "Label:Theme": "Theme", + "Label:UserNameRequired": "Please enter your username", + "Lable:Cancel": "Cancel", + "Lable:Confirm": "Confirm", + "Lable:LoginToPortal": "Login To Portal", + "Page:Center": "Center", + "Page:Home": "Home", + "Page:Notification": "Notification", + "Page:UserInfo": "User Info", + "Page:UserProfile": "User profile", + "Page:Work": "Work", + "Theme:Dark": "Dark", + "Theme:Light": "Light", + "Theme:System": "System" + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/translation.zh-Hansjson b/apps/flutter/dev_app/translation.zh-Hansjson new file mode 100644 index 000000000..c104de8aa --- /dev/null +++ b/apps/flutter/dev_app/translation.zh-Hansjson @@ -0,0 +1,43 @@ +{ + "culture": "zh-Hans", + "texts": { + "Center:Feedback": "意见反馈", + "Center:Help": "在线帮助", + "Center:Info": "关于", + "Center:Settings": "设置", + "Label:AccountSettings": "账号设置", + "Label:Anonymous": "游客", + "Label:CleanCache": "清理缓存", + "Label:ClickToLogin": "点击去登录", + "Label:EnableNotificationSubTitle": "启用以支持全局通知", + "Label:EnableNotificationTitle": "启用通知", + "Label:ForgotPassword": "忘记密码?", + "Label:Login": "登录", + "Label:LoginSubTitle": "登录后继续使用", + "Label:LoginTitle": "欢迎回来", + "Label:Logout": "退出登录", + "Label:NoAccount": "没有账号?", + "Label:NotificationsSubTitle": "支持的通知类型列表", + "Label:NotificationsTitle": "通知列表", + "Label:NotifierSettings": "通知设置", + "Label:PasswordRequired": "请输入密码", + "Label:PhoneNumberNotBound": "未绑定手机号", + "Label:Submit": "提交", + "Label:SwitchTheme": "切换主题", + "Label:SystemSettings": "系统设置", + "Label:Theme": "主题", + "Label:UserNameRequired": "请输入用户名", + "Lable:Cancel": "取消", + "Lable:Confirm": "确认", + "Lable:LoginToPortal": "登录到门户", + "Page:Center": "个人中心", + "Page:Home": "首页", + "Page:Notification": "通知设置", + "Page:UserInfo": "用户信息", + "Page:UserProfile": "个人信息", + "Page:Work": "工作", + "Theme:Dark": "深色", + "Theme:Light": "浅色", + "Theme:System": "跟随系统" + } +} \ No newline at end of file diff --git a/apps/flutter/dev_app/web/favicon.png b/apps/flutter/dev_app/web/favicon.png new file mode 100644 index 000000000..8aaa46ac1 Binary files /dev/null and b/apps/flutter/dev_app/web/favicon.png differ diff --git a/apps/flutter/dev_app/web/icons/Icon-192.png b/apps/flutter/dev_app/web/icons/Icon-192.png new file mode 100644 index 000000000..b749bfef0 Binary files /dev/null and b/apps/flutter/dev_app/web/icons/Icon-192.png differ diff --git a/apps/flutter/dev_app/web/icons/Icon-512.png b/apps/flutter/dev_app/web/icons/Icon-512.png new file mode 100644 index 000000000..88cfd48df Binary files /dev/null and b/apps/flutter/dev_app/web/icons/Icon-512.png differ diff --git a/apps/flutter/dev_app/web/icons/Icon-maskable-192.png b/apps/flutter/dev_app/web/icons/Icon-maskable-192.png new file mode 100644 index 000000000..eb9b4d76e Binary files /dev/null and b/apps/flutter/dev_app/web/icons/Icon-maskable-192.png differ diff --git a/apps/flutter/dev_app/web/icons/Icon-maskable-512.png b/apps/flutter/dev_app/web/icons/Icon-maskable-512.png new file mode 100644 index 000000000..d69c56691 Binary files /dev/null and b/apps/flutter/dev_app/web/icons/Icon-maskable-512.png differ diff --git a/apps/flutter/dev_app/web/index.html b/apps/flutter/dev_app/web/index.html new file mode 100644 index 000000000..cf5b00131 --- /dev/null +++ b/apps/flutter/dev_app/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + dev_app + + + + + + + + + + diff --git a/apps/flutter/dev_app/web/manifest.json b/apps/flutter/dev_app/web/manifest.json new file mode 100644 index 000000000..b44f62f0c --- /dev/null +++ b/apps/flutter/dev_app/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "dev_app", + "short_name": "dev_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/apps/flutter/dev_app/windows/.gitignore b/apps/flutter/dev_app/windows/.gitignore new file mode 100644 index 000000000..d492d0d98 --- /dev/null +++ b/apps/flutter/dev_app/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/apps/flutter/dev_app/windows/CMakeLists.txt b/apps/flutter/dev_app/windows/CMakeLists.txt new file mode 100644 index 000000000..565f3d298 --- /dev/null +++ b/apps/flutter/dev_app/windows/CMakeLists.txt @@ -0,0 +1,102 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(dev_app LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "dev_app") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/apps/flutter/dev_app/windows/flutter/CMakeLists.txt b/apps/flutter/dev_app/windows/flutter/CMakeLists.txt new file mode 100644 index 000000000..930d2071a --- /dev/null +++ b/apps/flutter/dev_app/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/apps/flutter/dev_app/windows/flutter/generated_plugin_registrant.cc b/apps/flutter/dev_app/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/apps/flutter/dev_app/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/apps/flutter/dev_app/windows/flutter/generated_plugin_registrant.h b/apps/flutter/dev_app/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/apps/flutter/dev_app/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/dev_app/windows/flutter/generated_plugins.cmake b/apps/flutter/dev_app/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..b93c4c30c --- /dev/null +++ b/apps/flutter/dev_app/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/dev_app/windows/runner/CMakeLists.txt b/apps/flutter/dev_app/windows/runner/CMakeLists.txt new file mode 100644 index 000000000..394917c05 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/apps/flutter/dev_app/windows/runner/Runner.rc b/apps/flutter/dev_app/windows/runner/Runner.rc new file mode 100644 index 000000000..fd6188164 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "dev_app" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "dev_app" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "dev_app.exe" "\0" + VALUE "ProductName", "dev_app" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/apps/flutter/dev_app/windows/runner/flutter_window.cpp b/apps/flutter/dev_app/windows/runner/flutter_window.cpp new file mode 100644 index 000000000..b25e363ef --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/flutter_window.cpp @@ -0,0 +1,66 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/apps/flutter/dev_app/windows/runner/flutter_window.h b/apps/flutter/dev_app/windows/runner/flutter_window.h new file mode 100644 index 000000000..6da0652f0 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/apps/flutter/dev_app/windows/runner/main.cpp b/apps/flutter/dev_app/windows/runner/main.cpp new file mode 100644 index 000000000..607eb8c62 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"dev_app", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/apps/flutter/dev_app/windows/runner/resource.h b/apps/flutter/dev_app/windows/runner/resource.h new file mode 100644 index 000000000..66a65d1e4 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/apps/flutter/dev_app/windows/runner/resources/app_icon.ico b/apps/flutter/dev_app/windows/runner/resources/app_icon.ico new file mode 100644 index 000000000..c04e20caf Binary files /dev/null and b/apps/flutter/dev_app/windows/runner/resources/app_icon.ico differ diff --git a/apps/flutter/dev_app/windows/runner/runner.exe.manifest b/apps/flutter/dev_app/windows/runner/runner.exe.manifest new file mode 100644 index 000000000..a42ea7687 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/apps/flutter/dev_app/windows/runner/utils.cpp b/apps/flutter/dev_app/windows/runner/utils.cpp new file mode 100644 index 000000000..b2b08734d --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/apps/flutter/dev_app/windows/runner/utils.h b/apps/flutter/dev_app/windows/runner/utils.h new file mode 100644 index 000000000..3879d5475 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/apps/flutter/dev_app/windows/runner/win32_window.cpp b/apps/flutter/dev_app/windows/runner/win32_window.cpp new file mode 100644 index 000000000..60608d0fe --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/apps/flutter/dev_app/windows/runner/win32_window.h b/apps/flutter/dev_app/windows/runner/win32_window.h new file mode 100644 index 000000000..e901dde68 --- /dev/null +++ b/apps/flutter/dev_app/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/apps/flutter/notifications/.flutter-plugins b/apps/flutter/notifications/.flutter-plugins new file mode 100644 index 000000000..22453877b --- /dev/null +++ b/apps/flutter/notifications/.flutter-plugins @@ -0,0 +1,6 @@ +# This is a generated file; do not edit or check into version control. +path_provider=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider-2.0.15\\ +path_provider_android=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_android-2.0.27\\ +path_provider_foundation=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_foundation-2.2.4\\ +path_provider_linux=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_linux-2.1.11\\ +path_provider_windows=C:\\Users\\eddlevol\\AppData\\Local\\Pub\\Cache\\hosted\\pub.flutter-io.cn\\path_provider_windows-2.1.7\\ diff --git a/apps/flutter/notifications/.flutter-plugins-dependencies b/apps/flutter/notifications/.flutter-plugins-dependencies new file mode 100644 index 000000000..daa9f9afc --- /dev/null +++ b/apps/flutter/notifications/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.4\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_android-2.0.27\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_foundation-2.2.4\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.1.11\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\eddlevol\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.1.7\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2023-07-16 10:42:55.797565","version":"3.10.5"} \ No newline at end of file diff --git a/apps/flutter/notifications/.gitignore b/apps/flutter/notifications/.gitignore new file mode 100644 index 000000000..96486fd93 --- /dev/null +++ b/apps/flutter/notifications/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/apps/flutter/notifications/.metadata b/apps/flutter/notifications/.metadata new file mode 100644 index 000000000..9596faeed --- /dev/null +++ b/apps/flutter/notifications/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 796c8ef79279f9c774545b3771238c3098dbefab + channel: stable + +project_type: package diff --git a/apps/flutter/notifications/CHANGELOG.md b/apps/flutter/notifications/CHANGELOG.md new file mode 100644 index 000000000..41cc7d819 --- /dev/null +++ b/apps/flutter/notifications/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/apps/flutter/notifications/LICENSE b/apps/flutter/notifications/LICENSE new file mode 100644 index 000000000..ba75c69f7 --- /dev/null +++ b/apps/flutter/notifications/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/apps/flutter/notifications/README.md b/apps/flutter/notifications/README.md new file mode 100644 index 000000000..02fe8ecab --- /dev/null +++ b/apps/flutter/notifications/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/apps/flutter/notifications/analysis_options.yaml b/apps/flutter/notifications/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/apps/flutter/notifications/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/apps/flutter/notifications/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/apps/flutter/notifications/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 000000000..7eb0d9f93 --- /dev/null +++ b/apps/flutter/notifications/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,25 @@ +package io.flutter.plugins; + +import io.flutter.plugin.common.PluginRegistry; +import io.flutter.plugins.pathprovider.PathProviderPlugin; + +/** + * Generated file. Do not edit. + */ +public final class GeneratedPluginRegistrant { + public static void registerWith(PluginRegistry registry) { + if (alreadyRegisteredWith(registry)) { + return; + } + PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); + } + + private static boolean alreadyRegisteredWith(PluginRegistry registry) { + final String key = GeneratedPluginRegistrant.class.getCanonicalName(); + if (registry.hasPlugin(key)) { + return true; + } + registry.registrarFor(key); + return false; + } +} diff --git a/apps/flutter/notifications/android/local.properties b/apps/flutter/notifications/android/local.properties new file mode 100644 index 000000000..1a3be4ff1 --- /dev/null +++ b/apps/flutter/notifications/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=C:\\Users\\eddlevol\\AppData\\Local\\Android\\sdk +flutter.sdk=D:\\Sdk\\Flutter \ No newline at end of file diff --git a/apps/flutter/notifications/ios/Flutter/Generated.xcconfig b/apps/flutter/notifications/ios/Flutter/Generated.xcconfig new file mode 100644 index 000000000..3117bb25c --- /dev/null +++ b/apps/flutter/notifications/ios/Flutter/Generated.xcconfig @@ -0,0 +1,14 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\notifications +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=lib\main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/notifications/ios/Flutter/flutter_export_environment.sh b/apps/flutter/notifications/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 000000000..c9bc9d6c1 --- /dev/null +++ b/apps/flutter/notifications/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\notifications" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/notifications/ios/Runner/GeneratedPluginRegistrant.h b/apps/flutter/notifications/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 000000000..7a8909271 --- /dev/null +++ b/apps/flutter/notifications/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/apps/flutter/notifications/ios/Runner/GeneratedPluginRegistrant.m b/apps/flutter/notifications/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 000000000..c0d0cbad8 --- /dev/null +++ b/apps/flutter/notifications/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,21 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import path_provider_foundation; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]]; +} + +@end diff --git a/apps/flutter/notifications/lib/index.dart b/apps/flutter/notifications/lib/index.dart new file mode 100644 index 000000000..e69de29bb diff --git a/apps/flutter/notifications/lib/models/notification.dart b/apps/flutter/notifications/lib/models/notification.dart new file mode 100644 index 000000000..7b0e868dc --- /dev/null +++ b/apps/flutter/notifications/lib/models/notification.dart @@ -0,0 +1,181 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'notification.g.dart'; + +@JsonEnum() +enum NotificationLifetime { + @JsonValue(0) + persistent, + @JsonValue(1) + onlyOne +} + +@JsonEnum() +enum NotificationType { + @JsonValue(0) + application, + @JsonValue(10) + system, + @JsonValue(20) + user, + @JsonValue(30) + serviceCallback; +} + +@JsonEnum() +enum NotificationContentType { + @JsonValue(0) + text, + @JsonValue(1) + html, + @JsonValue(2) + markdown, + @JsonValue(3) + json; +} + +@JsonEnum() +enum NotificationSeverity { + @JsonValue(0) + success, + @JsonValue(10) + info, + @JsonValue(20) + warn, + @JsonValue(30) + error, + @JsonValue(40) + fatal; +} + +@JsonSerializable() +class NotificationData { + NotificationData({ + required this.type, + required this.extraProperties, + }); + String type; + Map extraProperties; + + factory NotificationData.fromJson(Map json) => _$NotificationDataFromJson(json); + Map toJson() => _$NotificationDataToJson(this); +} + +@JsonSerializable() +class NotificationInfo { + NotificationInfo({ + this.tenantId, + required this.id, + required this.name, + required this.creationTime, + required this.lifetime, + required this.type, + required this.contentType, + required this.severity, + required this.data, + }); + String? tenantId; + String name; + String id; + DateTime creationTime; + NotificationLifetime lifetime; + NotificationType type; + NotificationContentType contentType; + NotificationSeverity severity; + NotificationData data; + + factory NotificationInfo.fromJson(Map json) => _$NotificationInfoFromJson(json); + Map toJson() => _$NotificationInfoToJson(this); +} + +@JsonSerializable() +class NotificationSendDto { + NotificationSendDto({ + required this.name, + this.templateName, + required this.data, + this.culture, + required this.toUserId, + this.toUserName, + this.severity, + }); + String name; + String? templateName; + Map data = {}; + String? culture; + String? toUserId; + String? toUserName; + NotificationSeverity? severity; + factory NotificationSendDto.fromJson(Map json) => _$NotificationSendDtoFromJson(json); + Map toJson() => _$NotificationSendDtoToJson(this); +} + + +@JsonSerializable() +class NotificationDto { + NotificationDto({ + required this.name, + this.displayName, + this.description, + required this.lifetime, + required this.type, + required this.contentType, + }); + String name; + String? displayName; + String? description; + NotificationLifetime lifetime; + NotificationType type; + NotificationContentType contentType; + factory NotificationDto.fromJson(Map json) => _$NotificationDtoFromJson(json); + Map toJson() => _$NotificationDtoToJson(this); +} + + +@JsonSerializable() +class NotificationGroupDto { + NotificationGroupDto({ + required this.name, + this.displayName, + this.notifications, + }); + String name; + String? displayName; + List? notifications = []; + factory NotificationGroupDto.fromJson(Map json) => _$NotificationGroupDtoFromJson(json); + Map toJson() => _$NotificationGroupDtoToJson(this); +} + + +@JsonSerializable() +class NotificationTemplateDto { + NotificationTemplateDto({ + required this.name, + this.description, + this.title, + this.content, + this.culture, + }); + String name; + String? description; + String? title; + String? content; + String? culture; + factory NotificationTemplateDto.fromJson(Map json) => _$NotificationTemplateDtoFromJson(json); + Map toJson() => _$NotificationTemplateDtoToJson(this); +} + +@JsonSerializable() +class UserSubscreNotificationDto { + UserSubscreNotificationDto({ + required this.name, + }); + String name; + factory UserSubscreNotificationDto.fromJson(Map json) => _$UserSubscreNotificationDtoFromJson(json); + Map toJson() => _$UserSubscreNotificationDtoToJson(this); +} + +class SetSubscriptionDto { + SetSubscriptionDto(this.name); + String name; +} diff --git a/apps/flutter/notifications/lib/models/notification.g.dart b/apps/flutter/notifications/lib/models/notification.g.dart new file mode 100644 index 000000000..44047dff7 --- /dev/null +++ b/apps/flutter/notifications/lib/models/notification.g.dart @@ -0,0 +1,168 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'notification.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +NotificationData _$NotificationDataFromJson(Map json) => + NotificationData( + type: json['type'] as String, + extraProperties: json['extraProperties'] as Map, + ); + +Map _$NotificationDataToJson(NotificationData instance) => + { + 'type': instance.type, + 'extraProperties': instance.extraProperties, + }; + +NotificationInfo _$NotificationInfoFromJson(Map json) => + NotificationInfo( + tenantId: json['tenantId'] as String?, + id: json['id'] as String, + name: json['name'] as String, + creationTime: DateTime.parse(json['creationTime'] as String), + lifetime: $enumDecode(_$NotificationLifetimeEnumMap, json['lifetime']), + type: $enumDecode(_$NotificationTypeEnumMap, json['type']), + contentType: + $enumDecode(_$NotificationContentTypeEnumMap, json['contentType']), + severity: $enumDecode(_$NotificationSeverityEnumMap, json['severity']), + data: NotificationData.fromJson(json['data'] as Map), + ); + +Map _$NotificationInfoToJson(NotificationInfo instance) => + { + 'tenantId': instance.tenantId, + 'name': instance.name, + 'id': instance.id, + 'creationTime': instance.creationTime.toIso8601String(), + 'lifetime': _$NotificationLifetimeEnumMap[instance.lifetime]!, + 'type': _$NotificationTypeEnumMap[instance.type]!, + 'contentType': _$NotificationContentTypeEnumMap[instance.contentType]!, + 'severity': _$NotificationSeverityEnumMap[instance.severity]!, + 'data': instance.data, + }; + +const _$NotificationLifetimeEnumMap = { + NotificationLifetime.persistent: 0, + NotificationLifetime.onlyOne: 1, +}; + +const _$NotificationTypeEnumMap = { + NotificationType.application: 0, + NotificationType.system: 10, + NotificationType.user: 20, + NotificationType.serviceCallback: 30, +}; + +const _$NotificationContentTypeEnumMap = { + NotificationContentType.text: 0, + NotificationContentType.html: 1, + NotificationContentType.markdown: 2, + NotificationContentType.json: 3, +}; + +const _$NotificationSeverityEnumMap = { + NotificationSeverity.success: 0, + NotificationSeverity.info: 10, + NotificationSeverity.warn: 20, + NotificationSeverity.error: 30, + NotificationSeverity.fatal: 40, +}; + +NotificationSendDto _$NotificationSendDtoFromJson(Map json) => + NotificationSendDto( + name: json['name'] as String, + templateName: json['templateName'] as String?, + data: json['data'] as Map, + culture: json['culture'] as String?, + toUserId: json['toUserId'] as String?, + toUserName: json['toUserName'] as String?, + severity: + $enumDecodeNullable(_$NotificationSeverityEnumMap, json['severity']), + ); + +Map _$NotificationSendDtoToJson( + NotificationSendDto instance) => + { + 'name': instance.name, + 'templateName': instance.templateName, + 'data': instance.data, + 'culture': instance.culture, + 'toUserId': instance.toUserId, + 'toUserName': instance.toUserName, + 'severity': _$NotificationSeverityEnumMap[instance.severity], + }; + +NotificationDto _$NotificationDtoFromJson(Map json) => + NotificationDto( + name: json['name'] as String, + displayName: json['displayName'] as String?, + description: json['description'] as String?, + lifetime: $enumDecode(_$NotificationLifetimeEnumMap, json['lifetime']), + type: $enumDecode(_$NotificationTypeEnumMap, json['type']), + contentType: + $enumDecode(_$NotificationContentTypeEnumMap, json['contentType']), + ); + +Map _$NotificationDtoToJson(NotificationDto instance) => + { + 'name': instance.name, + 'displayName': instance.displayName, + 'description': instance.description, + 'lifetime': _$NotificationLifetimeEnumMap[instance.lifetime]!, + 'type': _$NotificationTypeEnumMap[instance.type]!, + 'contentType': _$NotificationContentTypeEnumMap[instance.contentType]!, + }; + +NotificationGroupDto _$NotificationGroupDtoFromJson( + Map json) => + NotificationGroupDto( + name: json['name'] as String, + displayName: json['displayName'] as String?, + notifications: (json['notifications'] as List?) + ?.map((e) => NotificationDto.fromJson(e as Map)) + .toList(), + ); + +Map _$NotificationGroupDtoToJson( + NotificationGroupDto instance) => + { + 'name': instance.name, + 'displayName': instance.displayName, + 'notifications': instance.notifications, + }; + +NotificationTemplateDto _$NotificationTemplateDtoFromJson( + Map json) => + NotificationTemplateDto( + name: json['name'] as String, + description: json['description'] as String?, + title: json['title'] as String?, + content: json['content'] as String?, + culture: json['culture'] as String?, + ); + +Map _$NotificationTemplateDtoToJson( + NotificationTemplateDto instance) => + { + 'name': instance.name, + 'description': instance.description, + 'title': instance.title, + 'content': instance.content, + 'culture': instance.culture, + }; + +UserSubscreNotificationDto _$UserSubscreNotificationDtoFromJson( + Map json) => + UserSubscreNotificationDto( + name: json['name'] as String, + ); + +Map _$UserSubscreNotificationDtoToJson( + UserSubscreNotificationDto instance) => + { + 'name': instance.name, + }; diff --git a/apps/flutter/notifications/lib/notifications.module.dart b/apps/flutter/notifications/lib/notifications.module.dart new file mode 100644 index 000000000..fce7bb9dd --- /dev/null +++ b/apps/flutter/notifications/lib/notifications.module.dart @@ -0,0 +1,16 @@ +import 'package:core/modularity/index.dart'; +import 'package:get/get.dart'; +import 'package:notifications/services/index.dart'; + +import './pages/route.notification.dart'; + +class NotificationsModule extends Module { + @override + List get routes => NotificationRoute.routes; + + @override + void configureServices() { + inject(this); + lazyInject(() => NotificationService(), fenix: true); + } +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/index.dart b/apps/flutter/notifications/lib/pages/index.dart new file mode 100644 index 000000000..bc1161bbf --- /dev/null +++ b/apps/flutter/notifications/lib/pages/index.dart @@ -0,0 +1 @@ +export './notifier/index.dart'; \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/notifier/binding.dart b/apps/flutter/notifications/lib/pages/notifier/binding.dart new file mode 100644 index 000000000..7808c4d3b --- /dev/null +++ b/apps/flutter/notifications/lib/pages/notifier/binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import 'controller.dart'; + +class NotifierManageBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => NotifierManageController()); + } +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/notifier/controller.dart b/apps/flutter/notifications/lib/pages/notifier/controller.dart new file mode 100644 index 000000000..30190accf --- /dev/null +++ b/apps/flutter/notifications/lib/pages/notifier/controller.dart @@ -0,0 +1,86 @@ +import 'package:core/services/index.dart'; +import 'package:get/get.dart'; + +import '../../services/index.dart'; +import '../../tokens/index.dart'; +import './state.dart'; + +class NotifierManageController extends GetxController { + NotificationService get notificationService => Get.find(); + SignalrService get signalrService => Get.find(tag: NotificationTokens.producer); + SessionService get sessionService => Get.find(); + + final Rx _state = Rx(NotifierManageState( + isEnabled: true, + groups: [])); + NotifierManageState get state => _state.value; + + void _initNotifierConfig() async { + if (!sessionService.isAuthenticated) return; + var notifiers = await notificationService.getAssignableNotifiersAsync(); + var subscres = await notificationService.getMySubscribedListAsync(); + + List groups = []; + for (var notifierGroup in notifiers.items) { + if (notifierGroup.notifications == null && notifierGroup.notifications?.isEmpty == true) { + continue; + } + + List notifications = []; + for (var notifier in notifierGroup.notifications!) { + notifications.add(Notification( + name: notifier.name, + groupName: notifierGroup.name, + displayName: notifier.displayName ?? notifier.name, + description: notifier.description, + type: notifier.type, + contentType: notifier.contentType, + lifetime: notifier.lifetime, + isSubscribed: subscres.items.any((item) => item.name == notifier.name), + )); + } + + groups.add(NotificationGroup( + name: notifierGroup.name, + displayName: notifierGroup.displayName ?? notifierGroup.name, + notifications: notifications, + )); + } + + _state.update((val) { + val!.groups = groups; + }); + } + + void onSubscribed(Notification notification, bool isSubscribe) async { + if (!isSubscribe) { + await notificationService.unSubscribe(notification.name); + } else { + await notificationService.subscribe(notification.name); + } + _state.update((val) { + var group = val!.find(notification.groupName); + if (group == null) return; + var findNotification = group.find(notification.name); + if (findNotification == null) return; + findNotification.isSubscribed = isSubscribe; + }); + } + + void onNotificationEnabled(bool isEnabled) { + if (!isEnabled) { + signalrService.unsubscribe(NotificationTokens.receiver); + } else { + signalrService.subscribe(NotificationTokens.receiver); + } + _state.update((val) { + val!.isEnabled = isEnabled; + }); + } + + @override + void onInit() { + super.onInit(); + _initNotifierConfig(); + } +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/notifier/index.dart b/apps/flutter/notifications/lib/pages/notifier/index.dart new file mode 100644 index 000000000..e38387d5e --- /dev/null +++ b/apps/flutter/notifications/lib/pages/notifier/index.dart @@ -0,0 +1,3 @@ +export 'binding.dart'; +export 'controller.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/notifier/state.dart b/apps/flutter/notifications/lib/pages/notifier/state.dart new file mode 100644 index 000000000..2cad9fe67 --- /dev/null +++ b/apps/flutter/notifications/lib/pages/notifier/state.dart @@ -0,0 +1,53 @@ + +import 'package:get/get.dart'; + +import '../../models/notification.dart'; + +class NotifierManageState { + NotifierManageState({ + required this.isEnabled, + required this.groups, + }); + bool isEnabled; + List groups; + + NotificationGroup? find(String name) { + return groups.firstWhereOrNull((item) => item.name == name); + } +} + +class NotificationGroup { + NotificationGroup({ + required this.name, + required this.displayName, + required this.notifications, + }); + String name; + String displayName; + List notifications = []; + + Notification? find(String name) { + return notifications.firstWhereOrNull((item) => item.name == name); + } +} + +class Notification { + Notification({ + required this.name, + required this.groupName, + required this.displayName, + required this.isSubscribed, + this.description, + required this.lifetime, + required this.type, + required this.contentType, + }); + String name; + String groupName; + String displayName; + bool isSubscribed; + String? description; + NotificationLifetime lifetime; + NotificationType type; + NotificationContentType contentType; +} diff --git a/apps/flutter/notifications/lib/pages/notifier/view.dart b/apps/flutter/notifications/lib/pages/notifier/view.dart new file mode 100644 index 000000000..5028c2e6f --- /dev/null +++ b/apps/flutter/notifications/lib/pages/notifier/view.dart @@ -0,0 +1,42 @@ + +import 'package:components/pages/index.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'controller.dart'; +import './widget/notifier_card.dart'; + +class NotifierManagePage extends BasePage { + const NotifierManagePage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Page:Notification'.tr), + ), + body: SingleChildScrollView( + child: Column( + children: [ + Obx(() => SwitchListTile( + title: Text('Label:EnableNotificationTitle'.tr), + subtitle: Text('Label:EnableNotificationSubTitle'.tr), + value: bloc.state.isEnabled, + onChanged: bloc.onNotificationEnabled, + )), + ExpansionTile( + title: Text('Label:NotificationsTitle'.tr), + subtitle: Text('Label:NotificationsSubTitle'.tr), + children: [ + Obx(() => NotifierCard( + groups: bloc.state.groups, + onChange: bloc.onSubscribed, + )), + ], + ), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/notifier/widget/notifier_card.dart b/apps/flutter/notifications/lib/pages/notifier/widget/notifier_card.dart new file mode 100644 index 000000000..e0dfa991b --- /dev/null +++ b/apps/flutter/notifications/lib/pages/notifier/widget/notifier_card.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart' hide Notification; + +import '../state.dart'; + +class NotifierCard extends StatelessWidget { + const NotifierCard({ + super.key, + required this.groups, + this.onChange, + }); + + final List groups; + final void Function(Notification notification, bool checked)? onChange; + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Card( + margin: const EdgeInsets.all(10), + child: Column( + children: _notifierList(), + ), + ), + ); + } + + List _notifierList() { + if (groups.isEmpty == true) return []; + List notifierItems = []; + for (var group in groups) { + if (group.notifications.isEmpty == true) continue; + notifierItems.add(ExpansionTile( + title: Text(group.displayName), + children: _buildNotifierItems(group), + )); + } + return notifierItems; + } + + List _buildNotifierItems(NotificationGroup group) { + List children = []; + for (var item in group.notifications) { + children.add(SwitchListTile( + title: Text(item.displayName), + subtitle: Text(item.description ?? ''), + value: item.isSubscribed, + onChanged: (checked) { + if (onChange != null) { + onChange!(item, checked); + } + }, + )); + } + return children; + } +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/route.name.dart b/apps/flutter/notifications/lib/pages/route.name.dart new file mode 100644 index 000000000..0db27b302 --- /dev/null +++ b/apps/flutter/notifications/lib/pages/route.name.dart @@ -0,0 +1,4 @@ +class NotificationRoutes { + static String manageNotifier = '/notification/manage'; + static String notifies = '/notification/notifies'; +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/pages/route.notification.dart b/apps/flutter/notifications/lib/pages/route.notification.dart new file mode 100644 index 000000000..415281e50 --- /dev/null +++ b/apps/flutter/notifications/lib/pages/route.notification.dart @@ -0,0 +1,14 @@ +import 'package:get/get.dart'; + +import 'index.dart'; +import 'route.name.dart'; + +class NotificationRoute { + static List routes = [ + GetPage( + name: NotificationRoutes.manageNotifier, + page: () => const NotifierManagePage(), + binding: NotifierManageBinding(), + ), + ]; +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/services/index.dart b/apps/flutter/notifications/lib/services/index.dart new file mode 100644 index 000000000..beef5d17b --- /dev/null +++ b/apps/flutter/notifications/lib/services/index.dart @@ -0,0 +1 @@ +export 'notification.service.dart'; \ No newline at end of file diff --git a/apps/flutter/notifications/lib/services/notification.service.dart b/apps/flutter/notifications/lib/services/notification.service.dart new file mode 100644 index 000000000..6b913023e --- /dev/null +++ b/apps/flutter/notifications/lib/services/notification.service.dart @@ -0,0 +1,54 @@ +import 'package:core/models/abp.dto.dart'; +import 'package:core/services/rest.service.dart'; +import 'package:core/services/service.base.dart'; + +import '../models/notification.dart'; + +class NotificationService extends ServiceBase { + RestService get _restService => find(); + + Future sendAsyncByInput(NotificationSendDto input) { + return _restService.post('/api/notifications', + data: input, + ); + } + + Future subscribe(String name) { + return _restService.post('/api/notifications/my-subscribes', + data: { + 'name': name, + }, + ); + } + + Future unSubscribe(String name) { + return _restService.delete('/api/notifications/my-subscribes?name=$name'); + } + + Future> getMySubscribedListAsync() { + return _restService.get('/api/notifications/my-subscribes/all', + ).then((res) { + return ListResultDto( + items: (res.data['items'] as List).map((e) => UserSubscreNotificationDto.fromJson(e)).toList(), + ); + }); + } + + Future> getAssignableNotifiersAsync() { + return _restService.get('/api/notifications/assignables', + ).then((res) { + return ListResultDto( + items: (res.data['items'] as List).map((e) => NotificationGroupDto.fromJson(e)).toList(), + ); + }); + } + + Future> getAssignableTemplatesAsync() { + return _restService.get('/api/notifications/assignable-templates', + ).then((res) => ListResultDto( + items: (res.data['items'] as List) + .map((e) => NotificationTemplateDto.fromJson(e)).toList() + ), + ); + } +} \ No newline at end of file diff --git a/apps/flutter/notifications/lib/tokens/index.dart b/apps/flutter/notifications/lib/tokens/index.dart new file mode 100644 index 000000000..e568ffb78 --- /dev/null +++ b/apps/flutter/notifications/lib/tokens/index.dart @@ -0,0 +1 @@ +export 'notifications.token.dart'; \ No newline at end of file diff --git a/apps/flutter/notifications/lib/tokens/notifications.token.dart b/apps/flutter/notifications/lib/tokens/notifications.token.dart new file mode 100644 index 000000000..dbfa4cc24 --- /dev/null +++ b/apps/flutter/notifications/lib/tokens/notifications.token.dart @@ -0,0 +1,8 @@ +class NotificationTokens { + /// 通知生产者 + static const String producer = "producer"; + /// 通知消费者 + static const String consumer = "consumer"; + /// 通知订阅者(接收通知数据名称, 与Hub方法同名), 定义便于订阅/取消 + static const String receiver = "get-notification"; +} \ No newline at end of file diff --git a/apps/flutter/notifications/linux/flutter/generated_plugin_registrant.cc b/apps/flutter/notifications/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..e71a16d23 --- /dev/null +++ b/apps/flutter/notifications/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/apps/flutter/notifications/linux/flutter/generated_plugin_registrant.h b/apps/flutter/notifications/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..e0f0a47bc --- /dev/null +++ b/apps/flutter/notifications/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/notifications/linux/flutter/generated_plugins.cmake b/apps/flutter/notifications/linux/flutter/generated_plugins.cmake new file mode 100644 index 000000000..2e1de87a7 --- /dev/null +++ b/apps/flutter/notifications/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/apps/flutter/notifications/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/apps/flutter/notifications/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 000000000..3f4a84956 --- /dev/null +++ b/apps/flutter/notifications/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=D:\Sdk\Flutter +FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\notifications +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=0.0.1 +FLUTTER_BUILD_NUMBER=0.0.1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/apps/flutter/notifications/macos/Flutter/ephemeral/flutter_export_environment.sh b/apps/flutter/notifications/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100644 index 000000000..cdd3fa9f9 --- /dev/null +++ b/apps/flutter/notifications/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=D:\Sdk\Flutter" +export "FLUTTER_APPLICATION_PATH=D:\Projects\Flutter\packages\notifications" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=0.0.1" +export "FLUTTER_BUILD_NUMBER=0.0.1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/apps/flutter/notifications/pubspec.yaml b/apps/flutter/notifications/pubspec.yaml new file mode 100644 index 000000000..e43afb750 --- /dev/null +++ b/apps/flutter/notifications/pubspec.yaml @@ -0,0 +1,64 @@ +name: notifications +description: A new Flutter package project. +version: 0.0.1 +homepage: +publish_to: none + +environment: + sdk: '>=3.0.5 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + core: + path: '../core' + components: + path: '../components' + get: + json_annotation: ^4.8.1 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + + build_runner: ^2.4.5 + json_serializable: ^6.7.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/apps/flutter/notifications/windows/flutter/generated_plugin_registrant.cc b/apps/flutter/notifications/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 000000000..8b6d4680a --- /dev/null +++ b/apps/flutter/notifications/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/apps/flutter/notifications/windows/flutter/generated_plugin_registrant.h b/apps/flutter/notifications/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 000000000..dc139d85a --- /dev/null +++ b/apps/flutter/notifications/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/flutter/notifications/windows/flutter/generated_plugins.cmake b/apps/flutter/notifications/windows/flutter/generated_plugins.cmake new file mode 100644 index 000000000..b93c4c30c --- /dev/null +++ b/apps/flutter/notifications/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json index 3d97ea281..3fd0ccee1 100644 --- a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json +++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json @@ -3,7 +3,7 @@ "LINGYUN.Abp.Cli": { "commandName": "Project", //"commandLineArgs": "generate-view -t vben-view -m auditing -o D:\\Projects\\Development\\view-script -url http://127.0.0.1:30000/" - "commandLineArgs": "generate-proxy -t flutter -asp rest-service -u http://127.0.0.1:30000 -m platform -o D:\\Projects\\Development\\flutter-script -skip-cli-version-check" + "commandLineArgs": "generate-proxy -t flutter -asp rest-service -u http://127.0.0.1:30000 -m notifications -o D:\\Projects\\Development\\flutter-script -skip-cli-version-check" } } } \ No newline at end of file