Commit a680c565 authored by 林生雨's avatar 林生雨

Initial commit

parents
File added
.atom/
.dart_tool/
.idea
.vscode/
.packages
.pub/
android/
build/
ios/
packages
.flutter-plugins
# Since the current expectation is that clients are using Flutter head,
# and Dart SDK changes unlock dependencies, pubspec.lock isn't useful.
# Ignore it since it just creates noise. When there's a system in place
# for versioning this project relative to Flutter, remove this.
pubspec.lock
# 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: eaa9b47a4ac278a9439468911d2c361a472b114b
channel: master
# Application Customization
Because `example` is still in the process of being converted to
`flutter create` templates, support for customizing the application
is a work in progres. This page describes the current process for
making common modification to the native application on each platform.
It will be updated as `example` evolves. Keep in mind that as with
everything in this repository, forward-compatibility is not guaranteed;
the process for any customization may change in the future without
warning.
Please file issues for any basic application-level customizations that you would
like to be able to make that aren't listed here.
## macOS
- **Application Name**: Change `PRODUCT_NAME` in
`macos/Runner/Configs/AppInfo.xcconfig`.
- **Bundle Identifier**: Change `PRODUCT_BUNDLE_IDENTIFIER` in
`macos/Runner/Configs/AppInfo.xcconfig`.
- **Application Icon**: Replace `macos/Assets.xcassets/app_icon_*` with your
icon in the appropriate sizes.
## Windows
**Remember that Windows builds are currently debug-only, and should not be
distributed. These instructions are intended for experimentation and feedback
only.**
- **Application Name**: Change `TargetName` in
`windows\AppConfiguration.props`.
- You will likely want to change `kFlutterWindowTitle` in
`windows\window_configuration.cpp` to match. In the future this
will use the application name automatically by default.
- **Application Icon**: Replace `windows\resources\app_icon.ico` with your
icon.
- This will also change the Window icon.
## Linux
**Remember that Linux builds are currently debug-only, and should not be
distributed. These instructions are intended for experimentation and feedback
only.**
Linux has not yet had any customization support added. The fact that these steps
are non-trivial is a known issue.
- **Executable Name**: Change `BINARY_NAME` in `linux/Makefile`.
- You will likely want to change `window_properties.title` in
`linux/main.cc` to match. In the future this
will use the application name automatically by default.
- **Application Icon**: Prepare image data using the method of your choice
(e.g., by loading from a file in a set location; this may require the use
of a third-party library depending on the image format) and call `SetIcon`
on `flutter_controller.window()`. See the `SetIcon` comment in
`flutter_window.h` for the required format.
# Desktop Flutter Example
This is the standard Flutter template application, modified to run on desktop.
The `linux` and `windows` directories serve as early prototypes of
what will eventually become the `flutter create` templates for desktop, and will
be evolving over time to better reflect that goal. The `macos` directory has
now become a `flutter create` template, so is largely identical to what that
command creates.
## Building and Running
See [the main project README](../README.md).
To build without running, use `flutter build macos`/`windows`/`linux` rather than `flutter run`, as with
a standard Flutter project.
## Dart Differences from Flutter Template
The `main.dart` and `pubspec.yaml` have minor changes to support desktop:
* `debugDefaultTargetPlatformOverride` is set to avoid 'Unknown platform'
exceptions.
* The font is explicitly set to Roboto, and Roboto is bundled via
`pubspec.yaml`, to ensure that text displays on all platforms.
See the [Flutter Application Requirements section of the Flutter page on
desktop support](https://github.com/flutter/flutter/wiki/Desktop-shells#flutter-application-requirements)
for more information.
## Adapting for Another Project
Since `flutter create` is not yet supported for Windows and Linux, the easiest
way to try out desktop support with an existing Flutter application on those
platforms is to copy the platform directories from this example; see below for
details. For macOS, just run `flutter create --macos .` in your project.
Be sure to read the [Flutter page on desktop
support](https://github.com/flutter/flutter/wiki/Desktop-shells) before trying to
run an existing project on desktop, especially the [Flutter Application Requirements
section](https://github.com/flutter/flutter/wiki/Desktop-shells#flutter-application-requirements).
### Copying the Desktop Runners
The 'linux' and 'windows' directories are self-contained, and can be copied to
an existing Flutter project, enabling `flutter run` for those platforms.
**Be aware that neither the API surface of the Flutter desktop libraries nor the
interaction between the `flutter` tool and the platform directories is stable,
and no attempt will be made to provide supported migration paths as things
change.** You should expect that every time you update Flutter you may have
to delete your copies of the platform directories and re-copy them from an
updated version of flutter-desktop-embedding.
### Customizing the Runners
See [Application Customization](App-Customization.md) for premilinary
documenation on modifying basic application information like name and icon.
If you are building for macOS, you should also read about [managing macOS
security configurations](../macOS-Security.md).
flutter packages pub run build_runner clean
flutter packages pub run build_runner build --delete-conflicting-outputs
\ No newline at end of file
targets:
$default:
builders:
code_gen_demo|mark_builder:
enabled: true
builders:
user:
import: "package:example_flutter/Annotations/ServiceGenerator.dart"
builder_factories: ["userBuilder"]
build_extensions: {'.dart': ['.user.dart'] }
auto_apply: root_package
build_to: source
Router:
import: "package:example_flutter/Annotations/ServiceGenerator.dart"
builder_factories: ["routerBuilder"]
build_extensions: {'.dart': ['.rout.dart'] }
auto_apply: root_package
runs_before: ['routerCenter']
build_to: source
routerCenter:
import: "package:example_flutter/Annotations/ServiceGenerator.dart"
builder_factories: ["routerCenterBuilder"]
build_extensions: {'.dart': ['.mark.dart'] }
auto_apply: root_package
build_to: source
api_generator:
import: "package:example_flutter/Annotations/ServiceGenerator.dart"
builder_factories: ["apiBuilder"]
build_extensions: {".dart": [".serv.dart"]}
auto_apply: all_packages
build_to: source
applies_builders: ["source_gen|combining_builder"]
#
# json:
# import: "package:gmalpha_flutter/Annotations/ServiceGenerator.dart"
# builder_factories: ["jsonBuilder"]
# build_extensions: {".dart": [".json.dart"]}
# auto_apply: all_packages
# build_to: source
# applies_builders: ["source_gen|combining_builder"]
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
<svg width="135" height="158" viewBox="0 0 135 158" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="2" width="131" height="154" rx="65.5" stroke="#323232" stroke-width="4"/>
<path d="M43.7324 120.012C50.4299 124.752 58.6355 127.542 67.5 127.542C76.3646 127.542 84.5701 124.752 91.2677 120.012" stroke="#323232" stroke-width="4"/>
<path d="M40.8804 65.6747V85.6626" stroke="#323232" stroke-width="4"/>
<path d="M94.1198 65.6747V85.6626" stroke="#323232" stroke-width="4"/>
<path d="M70.3522 68.5301V98.9879C70.3522 102.142 67.7984 104.699 64.648 104.699C63.9813 104.699 63.3413 104.584 62.7466 104.374" stroke="#323232" stroke-width="4"/>
</svg>
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.75" y="0.75" width="98.5" height="98.5" stroke="#E4E4E4" stroke-width="1.5"/>
<path d="M40 50H60" stroke="#E4E4E4" stroke-width="2"/>
<path d="M50 60L50 40" stroke="#E4E4E4" stroke-width="2"/>
</svg>
<svg width="14" height="7" viewBox="0 0 14 7" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 1L7 6L13 1" stroke="#323232" stroke-width="1.5"/>
</svg>
<svg width="13" height="22" viewBox="0 0 13 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 1L2 11L12 21" stroke="#323232" stroke-width="1.5"/>
</svg>
<svg width="400" height="400" viewBox="0 0 400 400" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="400" height="400" fill="url(#pattern0)"/>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0" transform="scale(0.0025)"/>
</pattern>
<image id="image0" width="400" height="400" xlink:href="data:image/png;base64,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"/>
</defs>
</svg>
/*
* @author lsy
* @date 2019-09-02
**/
import 'package:analyzer/dart/element/element.dart';
import 'package:build/src/builder/build_step.dart';
import 'package:example_flutter/Annotations/anno/RouterCenter.dart';
import 'package:source_gen/source_gen.dart';
import '../RouterCenterRestore.dart';
class RouterCenterGenerator extends GeneratorForAnnotation<RouterCenter> {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
StringBuffer buffer = new StringBuffer();
StringBuffer importBuffer = new StringBuffer();
StringBuffer annoBuffer = new StringBuffer();
StringBuffer funBuffer = new StringBuffer();
RouterCenterRestore().buildMap.forEach((f, s) {
if (s.four) {
buffer.write("map.putIfAbsent(\"${f}\", ()=>${s.second}());\n");
}
annoBuffer.write("//${s.second} is resign : ${s.four} \n");
importBuffer.write("${s.first}${s.second}.dart\";\n");
importBuffer.write("${s.first}${s.third}.dart\";\n");
funBuffer.write("""
${s.third} find${s.third}(){
if(map[\"${f}\"]==null){
return null;
}
return map[\"${f}\"] as ${s.third};
}
""");
});
var pathSegments = buildStep.inputId.pathSegments;
StringBuffer pathBuffer = new StringBuffer();
for (int i = 0; i < pathSegments.length; i++) {
if (pathSegments[i] != "lib" && i != pathSegments.length - 1) {
pathBuffer.write(pathSegments[i] + "/");
}
}
String sufPath = pathBuffer.toString();
return """
${annoBuffer.toString()}
${importBuffer.toString()}
import "${"package:${buildStep.inputId.package}/${sufPath}RouterCenterRestore.dart"}";
import "${"package:${buildStep.inputId.package}/${sufPath}RouterBaser.dart"}";
class RouterCenterImpl {
Map<String,RouterBaser> map;
factory RouterCenterImpl() => _sharedInstance();
static RouterCenterImpl _instance;
RouterCenterImpl._() {
if (map == null) {
map = new Map();
init();
} else {
throw Exception("too many RouterCenter instance!!! fix it ");
}
}
static RouterCenterImpl _sharedInstance(){
if (_instance == null) {
_instance = RouterCenterImpl._();
}
return _instance;
}
void init(){
${buffer.toString()}
}
RouterBaser getModel(String modelName){
return map[modelName];
}
${funBuffer.toString()}
}
""";
}
}
/*
* @author lsy
* @date 2019-09-02
**/
import 'dart:math';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/src/builder/build_step.dart';
import 'package:example_flutter/Annotations/anno/Router.dart';
import 'package:example_flutter/Annotations/base/RouterBuildItem.dart';
import 'package:source_gen/source_gen.dart';
import '../RouterCenterRestore.dart';
class RouterGenerator extends GeneratorForAnnotation<Router> {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
var modelName = annotation.peek("modelName").stringValue;
var typeValue = annotation.peek("impl").typeValue;
var resignThisModel = annotation.peek("resignThisModel").boolValue;
var pathSegments = buildStep.inputId.pathSegments;
StringBuffer buffer = new StringBuffer();
String interfaceName;
for (int i = 0; i < pathSegments.length; i++) {
if (pathSegments[i] != "lib" && i != pathSegments.length - 1) {
buffer.write(pathSegments[i] + "/");
} else if (i == pathSegments.length - 1) {
// buffer.write("${typeValue.name}.dart");
interfaceName = pathSegments[i].replaceAll(".dart", "");
}
}
String first =
"import \"package:${buildStep.inputId.package}/${buffer.toString()}";
String second = typeValue.name;
String third = interfaceName;
bool four = resignThisModel;
RouterBuildItem item = new RouterBuildItem(first, second, third, four);
if (RouterCenterRestore().buildMap[modelName] != null) {
throw Exception("router error have same model name !!! change it name ");
}
RouterCenterRestore().buildMap.putIfAbsent(modelName, () => item);
// return """
//// import ${"package:${buildStep.inputId.package}/${buildStep.inputId.path.replaceFirst('lib/', '')}"}
// class APT {
// Map<String,RouterBaser> map={};
// }
// """;
return null;
}
}
/*
* @author lsy
* @date 2019-09-03
**/
import 'dart:convert';
import 'dart:core';
import 'dart:math';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/src/builder/build_step.dart';
import 'package:example_flutter/Annotations/anno/ServiceCenter.dart';
import 'package:source_gen/source_gen.dart';
import '../RouterCenterRestore.dart';
class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
print("element is $element");
if (element is! ClassElement) {
throw InvalidGenerationSourceError(
"Request class is not ok for ${element.displayName}");
}
StringBuffer improtBuffer = new StringBuffer();
StringBuffer methodBuffer = StringBuffer("");
StringBuffer outBuffer = StringBuffer();
StringBuffer mapBuffer = new StringBuffer();
List<String> differentList = [];
for (var methodElement in (element as ClassElement).methods) {
for (var annometadata in methodElement.metadata) {
final metadata = annometadata.computeConstantValue();
if (metadata.type.name == "Post" ||
metadata.type.name == "Get" ||
metadata.type.name == "Put") {
if (!differentList.contains(methodElement.returnType.name)) {
if (methodElement.returnType.name == "SimpleResponce") {
improtBuffer.write(
"import 'package:gmalpha_flutter/commonModel/net/Responce/SimpleResponce.dart';\n");
} else {
var pathSegments = buildStep.inputId.pathSegments;
StringBuffer path = new StringBuffer();
for (int i = 0; i < pathSegments.length; i++) {
if (i < pathSegments.length - 2 && pathSegments[i] != "lib") {
path.write("${pathSegments[i]}/");
}
}
improtBuffer.write(
"import 'package:${buildStep.inputId.package}/${path.toString()}entity/${methodElement.returnType.name}.dart\';\n");
}
differentList.add(methodElement.returnType.name);
}
String tempParams;
String sendType = metadata.type.name == "Post" ? "post" : "get";
if (metadata.type.name == "Put") {
sendType = "put";
}
mapBuffer.write("""
return Observable.fromFuture(DioUtil().${sendType}(\'${metadata.getField("sufUrl").toStringValue()}\'
""");
bool needMap = false;
for (int i = 0; i < methodElement.parameters.length; i++) {
var paramsMeta = methodElement.parameters[i];
for (int j = 0; j < paramsMeta.metadata.length; j++) {
var parameter = paramsMeta.metadata[j];
final queryAnno = parameter.computeConstantValue();
if (queryAnno.type.name == "Query") {
needMap = true;
if (tempParams == null) {
tempParams = "${paramsMeta}";
} else {
tempParams = "${tempParams},${paramsMeta}";
}
if (i == 0) {
mapBuffer.write(
",data:{\'${queryAnno.getField("params").toStringValue()}\':${paramsMeta.name}");
if (methodElement.parameters.length > 1) {
mapBuffer.write(",");
} else {
mapBuffer.write("}");
}
} else if (i == methodElement.parameters.length - 1) {
mapBuffer.write(
"\'${queryAnno.getField("params").toStringValue()}\':${paramsMeta.name}}");
} else {
mapBuffer.write(
"\'${queryAnno.getField("params").toStringValue()}\':${paramsMeta.name},");
}
}
}
}
//else{
// throw HttpException("RESPONCE error :\${value}");
// }
// Map map = json.decode(value.toString());
// return ${methodElement.returnType.name}.fromJson(map);
mapBuffer.write("))");
outBuffer.write("""
${methodElement.returnType.name} pase${methodElement.returnType.name}(String value){
return ${methodElement.returnType.name}.fromJson(json.decode(value));
}\n
""");
mapBuffer.write("""
.flatMap((value){
if(value!=null&&(value.statusCode>=200&&value.statusCode<300)){
return Observable.fromFuture(compute(pase${methodElement.returnType.name}, value.toString()));
}else {
return Observable.fromFuture(null);
}
});
""");
// mapBuffer.write("""
// .map((value){
// if(value!=null&&value.statusCode==200){
// Map map = json.decode(value.toString());
// return ${methodElement.returnType.name}.fromJson(map);
// }
// });
// """);
methodBuffer.write("""
Observable<${methodElement.returnType.name}> ${methodElement.name}(${tempParams == null ? "" : tempParams}){
${mapBuffer.toString()}
}
""");
mapBuffer.clear();
}
}
}
return """
import 'dart:convert';\n
import 'dart:io';\n
import 'package:rxdart/rxdart.dart';\n
import 'package:dio/dio.dart';\n
import 'package:flutter/foundation.dart';\n
${improtBuffer.toString()}
import 'package:example_flutter/commonModel/net/DioUtil.dart';\n
class ${element.displayName}Impl{
factory ${element.displayName}Impl() => _sharedInstance();
static ${element.displayName}Impl _instance;
${element.displayName}Impl._() {
}
static ${element.displayName}Impl _sharedInstance() {
if (_instance == null) {
_instance = ${element.displayName}Impl._();
}
return _instance;
}
${methodBuffer.toString()}
}
${outBuffer.toString()}
""";
}
}
/*
* @author lsy
* @date 2019-09-02
**/
import 'dart:math';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/src/builder/build_step.dart';
import 'package:example_flutter/Annotations/anno/UserCenter.dart';
import 'package:source_gen/source_gen.dart';
import '../RouterCenterRestore.dart';
Map<String, String> map = {};
class UserGenerator extends GeneratorForAnnotation<UserCenter> {
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
StringBuffer buffer = new StringBuffer();
for (var fieldData in (element as ClassElement).fields) {
for (var annometadata in fieldData.metadata) {
final metadata = annometadata.computeConstantValue();
// final metadatatype = annometadata.runtimeType;
// print("metadatatype is $metadatatype");
// print("metadataNAME is ${metadata.type.name}");
// print("element is $element");
if (element is! ClassElement) {
throw InvalidGenerationSourceError(
"Request class is not ok for ${element.displayName}");
}
if (metadata.type.name == "User") {
String key = metadata.getField("key").toStringValue();
var field = metadata.getField("type");
var type = field.type.name;
if (type == "String") {
buffer.write("""
String _${fieldData.name};
Observable<bool> save${fieldData.name}(String ${fieldData.name}){
return Observable.fromFuture(spUtil.saveStringKv("${key}",${fieldData.name}))
.map((value){
if(value){
this._${fieldData.name}=${fieldData.name};
}
return value;
});
}
Observable<String> get${fieldData.name}(){
if(_${fieldData.name}!=null){
return Observable.fromFuture(Future.value(_${fieldData.name}));
}
return Observable.fromFuture(spUtil.getStringKv("${key}")).map((value){
if(value==""){
return null;
}
return value;
});
}
""");
} else if (type == "int") {
buffer.write("""
int _${fieldData.name};
Observable<bool> save${fieldData.name}(int ${fieldData.name}){
return Observable.fromFuture(spUtil.saveIntKv("${key}",${fieldData.name}))
.map((value){
if(value){
this._${fieldData.name}=${fieldData.name};
}
return value;
});
}
Observable<int> get${fieldData.name}(){
if(_${fieldData.name}!=null){
return Observable.fromFuture(Future.value(_${fieldData.name}));
}
return Observable.fromFuture(spUtil.getIntKv("${key}"));
}
""");
} else if (type == "double") {
buffer.write("""
double _${fieldData.name};
Observable<bool> save${fieldData.name}(double ${fieldData.name}){
return Observable.fromFuture(spUtil.saveDoubleKv("${key}",${fieldData.name}))
.map((value){
if(value){
this._${fieldData.name}=${fieldData.name};
}
return value;
});
}
Observable<double> get${fieldData.name}(){
if(_${fieldData.name}!=null){
return Observable.fromFuture(Future.value(_${fieldData.name}));
}
return Observable.fromFuture(spUtil.getDoubleKv("${key}"));
}
""");
} else if (type == "bool") {
buffer.write("""
bool _${fieldData.name};
Observable<bool> save${fieldData.name}(bool ${fieldData.name}){
return Observable.fromFuture(spUtil.saveBoolKv("${key}",${fieldData.name}))
.map((value){
if(value){
this._${fieldData.name}=${fieldData.name};
}
return value;
});
}
Observable<bool> get${fieldData.name}(){
if(_${fieldData.name}!=null){
return Observable.fromFuture(Future.value(_${fieldData.name}));
}
return Observable.fromFuture(spUtil.getBoolKv("${key}"));
}
""");
}
}
}
}
return """
import 'package:rxdart/rxdart.dart';
import 'package:gmalpha_flutter/commonModel/sp/SpUtil.dart';
class ${element.displayName}Impl{
factory ${element.displayName}Impl() => _sharedInstance();
static ${element.displayName}Impl _instance;
${element.displayName}Impl._() {
}
static ${element.displayName}Impl _sharedInstance() {
if (_instance == null) {
_instance = ${element.displayName}Impl._();
}
return _instance;
}
SpUtil spUtil=SpUtil.getInstance();
${buffer.toString()}
}
""";
}
}
/*
* @author lsy
* @date 2019-09-02
**/
abstract class RouterBaser{
//TODO
}
/*
* @author lsy
* @date 2019-09-02
**/
import 'anno/RouterCenter.dart';
import 'base/RouterBuildItem.dart';
@RouterCenter()
class RouterCenterRestore {
Map<String, RouterBuildItem> buildMap;
factory RouterCenterRestore() => _sharedInstance();
static RouterCenterRestore _instance;
RouterCenterRestore._() {
print("INITTT ");
if (buildMap == null) {
buildMap = new Map();
} else {
throw Exception("too many RouterCenter instance!!! fix it ");
}
}
static RouterCenterRestore _sharedInstance() {
if (_instance == null) {
_instance = RouterCenterRestore._();
}
return _instance;
}
}
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// RouterCenterGenerator
// **************************************************************************
//HomeRouterImpl is resign : true
//UserRouterImpl is resign : true
import "package:example_flutter/HomeModel/HomeRouterImpl.dart";
import "package:example_flutter/HomeModel/HomeRouter.dart";
import "package:example_flutter/UserModel/UserRouterImpl.dart";
import "package:example_flutter/UserModel/UserRouter.dart";
import "package:example_flutter/Annotations/RouterCenterRestore.dart";
import "package:example_flutter/Annotations/RouterBaser.dart";
class RouterCenterImpl {
Map<String, RouterBaser> map;
factory RouterCenterImpl() => _sharedInstance();
static RouterCenterImpl _instance;
RouterCenterImpl._() {
if (map == null) {
map = new Map();
init();
} else {
throw Exception("too many RouterCenter instance!!! fix it ");
}
}
static RouterCenterImpl _sharedInstance() {
if (_instance == null) {
_instance = RouterCenterImpl._();
}
return _instance;
}
void init() {
map.putIfAbsent("HomeRouter", () => HomeRouterImpl());
map.putIfAbsent("UserRouter", () => UserRouterImpl());
}
RouterBaser getModel(String modelName) {
return map[modelName];
}
HomeRouter findHomeRouter() {
if (map["HomeRouter"] == null) {
return null;
}
return map["HomeRouter"] as HomeRouter;
}
UserRouter findUserRouter() {
if (map["UserRouter"] == null) {
return null;
}
return map["UserRouter"] as UserRouter;
}
}
import 'package:example_flutter/Annotations/Generator/ServiceGenerator.dart';
import 'package:example_flutter/Annotations/Generator/UserGenerator.dart';
import 'package:source_gen/source_gen.dart';
import 'package:build/src/builder/builder.dart';
import 'Generator/RouterCenterGenerator.dart';
import 'Generator/RouterGenerator.dart';
Builder routerBuilder(BuilderOptions options) =>
LibraryBuilder(RouterGenerator(), generatedExtension: ".rout.dart");
Builder routerCenterBuilder(BuilderOptions options) =>
LibraryBuilder(RouterCenterGenerator(), generatedExtension: ".mark.dart");
Builder userBuilder(BuilderOptions options)=>
LibraryBuilder(UserGenerator(),generatedExtension: ".user.dart");
Builder apiBuilder(BuilderOptions options)=>
LibraryBuilder(ServiceGenerator(),generatedExtension: ".serv.dart");
//Builder jsonBuilder(BuilderOptions options)=>
// LibraryBuilder(JsonSerializableGenerator(),generatedExtension: ".json.dart");
\ No newline at end of file
/*
* @author lsy
* @date 2019-09-04
**/
library Get;
class Get {
final String sufUrl;
const Get(this.sufUrl);
}
/*
* @author lsy
* @date 2019-09-04
**/
library Post;
class Post {
final String sufUrl;
const Post(this.sufUrl);
}
/*
* @author lsy
* @date 2019-11-15
**/
library Put;
class Put {
final String sufUrl;
const Put(this.sufUrl);
}
/*
* @author lsy
* @date 2019-09-04
**/
library Query;
class Query {
final String params;
const Query(this.params);
}
/*
* @author lsy
* @date 2019-09-02
**/
library Router;
class Router {
final String modelName;
final Type impl;
final bool resignThisModel;
const Router(this.modelName, this.impl, this.resignThisModel);
}
/*
* @author lsy
* @date 2019-09-02
**/
library RouterCenter;
class RouterCenter {
const RouterCenter();
}
/*
* @author lsy
* @date 2019-09-04
**/
library ServiceCenter;
class ServiceCenter{
const ServiceCenter();
}
\ No newline at end of file
/*
* @author lsy
* @date 2019-09-03
**/
library User;
class User {
final String key;
final Object type;
const User(this.key, this.type);
}
/*
* @author lsy
* @date 2019-09-03
**/
library UserCenter;
class UserCenter {
const UserCenter();
}
/*
* @author lsy
* @date 2019-09-02
**/
class RouterBuildItem<S, T, Z, W> {
S first;
T second;
Z third;
W four;
RouterBuildItem(this.first, this.second, this.third, this.four);
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/Annotations/RouterBaser.dart';
import 'package:example_flutter/Annotations/anno/Router.dart';
import 'package:example_flutter/HomeModel/HomeRouterImpl.dart';
import 'package:flutter/cupertino.dart';
@Router("HomeRouter", HomeRouterImpl, true)
abstract class HomeRouter extends RouterBaser {
Widget getHomePage();
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/HomeModel/HomeRouter.dart';
import 'package:example_flutter/HomeModel/page/home/HomePage.dart';
import 'package:flutter/src/widgets/framework.dart';
class HomeRouterImpl extends HomeRouter{
@override
Widget getHomePage() {
return HomePage();
}
}
\ No newline at end of file
/*
* @author lsy
* @date 2019-11-13
**/
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/cache/CacheManager.dart';
import 'package:example_flutter/res/value/ALColors.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
getBaseTitle(BuildContext context) {
String userName =
CacheManager.getInstance().get(MEMORY_CACHE).get("userName");
return baseAppBar(
backgroundColor: ALColors.Color5276F4,
backClick: () {
Navigator.pop(context);
},
action: <Widget>[
Expanded(
child: Container(),
),
Container(
margin: EdgeInsets.only(right: ScreenUtil.instance.setWidth(10)),
alignment: Alignment.center,
child: baseText(userName, 30, ALColors.ColorF8F8F8),
),
Container(
width: kToolbarHeight,
height: kToolbarHeight,
margin: EdgeInsets.only(
left: ScreenUtil.instance.setWidth(5),
right: ScreenUtil.instance.setWidth(50),
top: 5,
bottom: 5),
child: SvgPicture.asset("image/Face.svg"),
),
]);
}
/*
* @author lsy
* @date 2019-11-22
**/
import 'dart:ui' as ui;
class PointItem {
List<ui.Offset> list = new List();
ui.Image image;
double x = -1;
double y = -1;
double scareSize = 1;
double tranX = 0;
double tranY = 0;
bool drawPath = false;
void reset() {
list.clear();
x = -1;
y = -1;
scareSize = 1;
tranY = 0;
tranX = 0;
drawPath = false;
}
PointItem();
setScareSize(double scareSize) {
if (scareSize < 1) {
scareSize = 1;
}
this.scareSize = scareSize;
}
double getScareSize() {
return scareSize;
}
setTranX(double tranX) {
if (tranX < 0) {
tranX = 0;
}
this.tranX = tranX;
}
double getTranX() {
return tranX;
}
setTranY(double tranY) {
if (tranY < 0) {
tranY = 0;
}
this.tranY = tranY;
}
double getTranY() {
return tranY;
}
List<ui.Offset> getPoints() {
return list;
}
addPoint(double x, double y) {
double realX = (x + getTranX()) / scareSize;
double realY = (y + getTranY()) / scareSize;
list.add(new ui.Offset(realX, realY));
}
removePoint() {
if (list.isNotEmpty) {
list.removeAt(list.length - 1);
drawPath = false;
}
}
setImage(ui.Image image) {
this.image = image;
}
ui.Image getImage() {
return image;
}
setX(double x) {
this.x = x;
}
setY(double y) {
this.y = y;
}
double getX() {
return x;
}
double getY() {
return y;
}
void close() {
if (list.isNotEmpty && list.length > 2) {
list.add(list[0]);
drawPath = true;
}
}
}
/*
* @author lsy
* @date 2019-11-22
**/
import 'dart:async';
import 'dart:ui';
import 'package:example_flutter/HomeModel/base/bean/PointItem.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
//
//class WorkViewController extends StatefulWidget {
// @override
// State<StatefulWidget> createState() => WorkViewState();
//}
//
//class WorkViewState extends State<WorkViewController> {
// ui.Image img;
//
// @override
// void initState() {
// super.initState();
// String testImg =
// "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574413347096&di=44b91b322281ad449b4d93cf79df3d0c&imgtype=0&src=http%3A%2F%2Fpic27.nipic.com%2F20130324%2F9252150_152129329000_2.jpg";
// loadImage(testImg).then((value) {
// setState(() {
// img = value;
// });
// });
// }
//
// @override
// Widget build(BuildContext context) {
// return CustomPaint(painter: WorkView(img));
// }
//
// Future<ui.Image> loadImage(var path) async {
// ImageStream stream = NetworkImage(
// path,
// ).resolve(ImageConfiguration.empty);
// Completer<ui.Image> completer = Completer<ui.Image>();
// void listener(ImageInfo frame, bool synchronousCall) {
// final ui.Image image = frame.image as ui.Image;
// completer.complete(image);
// stream.removeListener(ImageStreamListener(listener));
// }
//
// stream.addListener(ImageStreamListener(listener));
// return completer.future;
// }
//}
class WorkView extends CustomPainter {
PointItem item;
WorkView(this.item) {}
Paint ImagePaint = new Paint()..isAntiAlias = true;
Paint linePaint = new Paint()
..isAntiAlias = true
..color = Colors.black
..strokeWidth = 1;
Paint pointPaint = new Paint()
..isAntiAlias = true
..color = Colors.red
..strokeWidth = 1;
Paint pathPaint = new Paint()
..isAntiAlias = true
..color = Colors.black38
..style = PaintingStyle.fill;
@override
void paint(Canvas canvas, Size size) {
if (item.tranX != 0 || item.tranY != 0) {
if (item.tranX / item.scareSize > size.width) {
item.tranX = size.width * item.scareSize;
}
if (item.tranY / item.scareSize > size.height) {
item.tranY = size.height * item.scareSize;
}
canvas.translate(-item.tranX, -item.tranY);
}
if (item.scareSize != 1) {
canvas.scale(item.scareSize, item.scareSize);
}
if (item.getImage() != null) {
double scareSize = item.getImage().width / size.width;
double showWidth = size.width;
double showheight = item.getImage().height / scareSize;
if (showheight > size.height) {
showheight = size.height;
}
double top = (size.height - showheight) / 2;
canvas.drawImageRect(
item.getImage(),
Rect.fromLTWH(0.0, 0.0, item.getImage().width.toDouble(),
item.getImage().height.toDouble()),
Rect.fromLTWH(0, top, showWidth, showheight),
ImagePaint);
}
double newX = (item.getX() + item.getTranX()) / item.scareSize;
double newY = (item.getY() + item.getTranY()) / item.scareSize;
if (item.getX() != null &&
item.getY() != null &&
item.getX() >= 0 &&
item.getY() >= 0) {
canvas.drawLine(Offset(newX, 0), Offset(newX, size.height), linePaint);
canvas.drawLine(Offset(0, newY), Offset(size.width, newY), linePaint);
TextPainter(
text: TextSpan(
text: "${newX.toInt()},${newY.toInt()}",
style: TextStyle(
fontSize: 15,
color: Colors.yellow,
fontWeight: FontWeight.w300)),
textDirection: TextDirection.ltr,
textAlign: TextAlign.center)
..layout(maxWidth: 150, minWidth: 30)
..paint(canvas, Offset(newX + 5, newY - 20));
}
if (item.getPoints().isNotEmpty) {
// if(item.getPoints().length==1){
// canvas.drawPoints(pointMode, points, paint)
// }else if(item.getPoints().length==2){
//
// } else{
// for(int i=0;i<item.getPoints().length;i++){
// if(i==item.getPoints().length-1){
//
// }else{
//
// }
// }
// }
canvas.drawPoints(PointMode.polygon, item.getPoints(), pointPaint);
}
print("OK?? ${item.drawPath}");
if (item.drawPath) {
if (item.getPoints().length < 2) {
return;
}
Path path = new Path();
path.moveTo(item.getPoints()[0].dx, item.getPoints()[0].dy);
for (int i = 0; i < item.getPoints().length; i++) {
path.lineTo(item.getPoints()[i].dx, item.getPoints()[i].dy);
}
path.close();
canvas.drawPath(path, pathPaint);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:example_flutter/HomeModel/page/picture/PicPage.dart';
import 'package:example_flutter/HomeModel/page/work/WorkPage.dart';
import 'package:example_flutter/HomeModel/service/HomeRepo.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/UploadResultBean.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/picker/base/BasePickerComponent.dart';
import 'package:example_flutter/commonModel/toast/toast.dart';
import 'package:example_flutter/res/anim/Anim.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:file_chooser/file_chooser.dart';
class HomeModel extends BaseModel {
HomeRepo repo = HomeRepo.getInstance();
List<UploadResultBean> scanList = new List();
int allSize;
int nowSize;
List<String> uploadFile = new List();
@override
void dispose() {}
void scanImages(BuildContext context) async {
await showOpenPanel((result, files) {
if (result != FileChooserResult.ok || files.isEmpty) {
Toast.show(context, "没有选择文件 批量上传 可以按住shift 或者拖拽鼠标!");
return;
}
BaseCenterPicker()
..setPicker(BaseLoadingItem("上传中..."))
..show(context);
allSize = files.length ;
nowSize = 0;
scanList.clear();
uploadFile.clear();
uploadFile.addAll(files);
uploadImage(context, uploadFile[nowSize]);
}, allowsMultipleSelection: true);
}
void uploadImage(
BuildContext context,
String path,
) {
netUpload(path).then((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
nowSize++;
if (allSize == nowSize) {
Toast.show(context, "上传成功");
// repo.updateScanList(scanList);
success(context);
} else {
uploadImage(context,uploadFile[nowSize]);
}
} else {
Toast.show(context, "上传图片返回接口有空值 暂停上传");
print("上传图片返回接口有空值 暂停上传");
Navigator.pop(context);
}
}).catchError((erro) {
Toast.show(context, erro.toString());
print(erro.toString());
Navigator.pop(context);
});
}
void success(BuildContext buildContext) {
Navigator.pop(buildContext);
Navigator.push(buildContext, CustomRoute(PicPage()));
}
}
Future<Response> netUpload(String path) async {
return DioUtil.getInstance().uploadFile("image-upload/", path);
}
UploadResultBean uploadImg(String value) {
return UploadResultBean.fromJson(json.decode(value));
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/HomeModel/page/home/HomeModel.dart';
import 'package:example_flutter/HomeModel/page/picture/PicPage.dart';
import 'package:example_flutter/commonModel/base/BaseComponent.dart';
import 'package:example_flutter/commonModel/cache/CacheManager.dart';
import 'package:example_flutter/res/GMRes.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() => HomeState();
}
class HomeState extends State<HomePage> {
HomeModel _model;
Size screenSize;
HomeState() {
_model = new HomeModel();
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
screenSize = MediaQuery.of(context).size;
String userName =
CacheManager.getInstance().get(MEMORY_CACHE).get("userName");
return Scaffold(
// appBar: AppBar(
// leading: Text(""),
// backgroundColor: ALColors.Color5276F4,
// actions: <Widget>[
// Expanded(
// child: Container(),
// ),
// Container(
// margin: EdgeInsets.only(right: ScreenUtil.instance.setWidth(10)),
// alignment: Alignment.center,
// child: baseText(userName, 30, ALColors.ColorF8F8F8),
// ),
// Container(
// width: kToolbarHeight,
// height: kToolbarHeight,
// margin: EdgeInsets.only(
// left: ScreenUtil.instance.setWidth(5),
// right: ScreenUtil.instance.setWidth(50),
// top: 5,
// bottom: 5),
// child: SvgPicture.asset("image/Face.svg"),
// ),
// ]),
body: uploadItem(),
);
}
uploadItem() {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573655792197&di=f9469fa087a082aedfd22514c1549e1f&imgtype=0&src=http%3A%2F%2Fimg8.zol.com.cn%2Fbbs%2Fupload%2F19571%2F19570481.jpg'))),
padding: EdgeInsets.only(
top: ScreenUtil.instance.setWidth(50),
bottom: ScreenUtil.instance.setWidth(80),
left: ScreenUtil.instance.setWidth(80),
right: ScreenUtil.instance.setWidth(80)),
alignment: Alignment.center,
width: screenSize.width,
height: double.maxFinite,
child: InkWell(
onTap: () {
_model.scanImages(context);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
//圆角
Radius.circular(20.0),
),
border: Border.all(width: 1.0),
),
alignment: Alignment.center,
width: double.maxFinite,
height: double.maxFinite,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: 25,
width: 100,
color: Colors.blueAccent,
child: FlatButton(
onPressed: () {
Navigator.push(context, CustomRoute(PicPage()));
},
child: baseText("跳过", 15, Colors.white),
)),
Expanded(
child: Container(
),
),
SvgPicture.asset("image/add.svg"),
Container(
margin: EdgeInsets.only(top: 30),
child: baseText("点击上传照片", 20, ALColors.ColorE4E4E4),
),
Expanded(
child: Container(),
),
],
),
)));
}
}
/*
* @author lsy
* @date 2019-11-13
**/
import 'dart:io';
import 'package:example_flutter/HomeModel/page/work/WorkModel.dart';
import 'package:example_flutter/HomeModel/page/work/WorkPage.dart';
import 'package:example_flutter/HomeModel/service/HomeRepo.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/TotalImageBean.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/picker/base/BasePickerComponent.dart';
import 'package:example_flutter/commonModel/toast/toast.dart';
import 'package:example_flutter/res/anim/Anim.dart';
import 'package:flutter/cupertino.dart';
class PicModel extends BaseModel {
HomeRepo _repo;
LiveData<List<PicList>> imageLive = new LiveData();
LiveData<int> countLive = new LiveData();
LiveData<TotalImageBean> totalLive = new LiveData();
PicModel() {
_repo = HomeRepo.getInstance();
countLive.notifyView(_repo.currentPage);
}
void getImages(BuildContext context, bool showPop) {
if (showPop) {
BaseCenterPicker()
..setPicker(BaseLoadingItem("加载中。。。"))
..show(context);
}
_repo.getImageResult(_repo.currentPage, 9).listen((data) {
_repo.updateCurrentPageList(data.picList);
imageLive.notifyView(data.picList);
if (showPop) {
Navigator.pop(context);
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
if (showPop) {
Navigator.pop(context);
}
});
}
void getTotalImages(BuildContext context) {
_repo.getTotalImage().listen((value) {
totalLive.notifyView(value);
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
}
@override
void dispose() {
imageLive.dispost();
countLive.dispost();
totalLive.dispost();
}
void onItemClick(BuildContext context, int index) {
Navigator.push(
context,
new CustomRoute(WorkPage(_repo.getCurrentPageList()[index].picurl,
_repo.getCurrentPageList()[index].id, index)))
.then((value) {
if (value == -1) {
getImages(context, false);
} else {
imageLive.notifyView(_repo.getCurrentPageList());
}
countLive.notifyView(_repo.currentPage);
});
}
void after(BuildContext context) {
BaseCenterPicker()
..setPicker(BaseLoadingItem("加载中。。。"))
..show(context);
_repo.getImageResult(_repo.currentPage + 1, 9).listen((data) {
if (data == null || data.picList == null || data.picList.isEmpty) {
Toast.show(context, "已经是最后一页了哦~");
} else {
_repo.currentPage = _repo.currentPage + 1;
_repo.updateCurrentPageList(data.picList);
imageLive.notifyView(data.picList);
}
countLive.notifyView(_repo.currentPage);
Navigator.pop(context);
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
Navigator.pop(context);
});
}
void before(BuildContext context) {
if (_repo.currentPage == 1) {
Toast.show(context, "已经是第一页了哦");
return;
}
_repo.currentPage = _repo.currentPage - 1;
getImages(context, true);
countLive.notifyView(_repo.currentPage);
}
void onDeleteItem(BuildContext context, int index) {
//TODO
BaseCenterPicker()
..setPicker(SurePicker("确定删除这张照片吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
//DELETE
_repo.deleteItem(_repo.getCurrentPageList()[index].id).listen((value) {
if (value != null && value.result == "DeleteSucceed") {
//OK
_repo.getImageResult(_repo.currentPage, 9).listen((data) {
if (data != null &&
data.picList != null &&
data.picList.isNotEmpty) {
_repo.updateCurrentPageList(data.picList);
imageLive.notifyView(data.picList);
} else {
if (_repo.currentPage == 1) {
Toast.show(context, "没有数据了");
} else {
_repo
.getImageResult(_repo.currentPage - 1, 9)
.listen((value) {
_repo.currentPage = _repo.currentPage - 1;
_repo.updateCurrentPageList(data.picList);
imageLive.notifyView(data.picList);
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
}
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
}))
..show(context);
}
}
/*
* @author lsy
* @date 2019-11-13
**/
import 'package:example_flutter/HomeModel/base/BaseTitle.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/TotalImageBean.dart';
import 'package:example_flutter/commonModel/base/BaseComponent.dart';
import 'package:example_flutter/res/GMRes.dart';
import 'package:flutter/material.dart';
import 'PicModel.dart';
class PicPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => PicState();
}
class PicState extends State<PicPage> {
PicModel _model;
Size screenSize;
PicState() {
_model = PicModel();
}
@override
void initState() {
super.initState();
_model.getImages(context, false);
_model.getTotalImages(context);
}
@override
void dispose() {
_model.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
screenSize = MediaQuery.of(context).size;
return Scaffold(
appBar: getBaseTitle(context),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
sync(context),
Expanded(
child: imageList(context),
),
nextBefor(context)
],
),
);
}
imageList(BuildContext context) {
for (int i = 0; i < 9; i++) {}
return StreamBuilder<List<PicList>>(
stream: _model.imageLive.stream,
initialData: _model.imageLive.data,
builder: (con, data) {
if (data.data == null) {
return loadingItem();
}
List<Widget> gridList = new List();
for (int i = 0; i < data.data.length; i++) {
String showText;
Color color;
if (data.data[i].status == "0") {
showText = "未分配";
color = Colors.blueGrey;
} else if (data.data[i].status == "1") {
showText = "已分配未标记";
color = Colors.red;
} else if (data.data[i].status == "2") {
showText = "已分配已标记";
color = Colors.green;
}
gridList.add(gridItem(data.data[i].picurl, showText, i, color));
}
return Container(
width: double.maxFinite,
height: double.maxFinite,
alignment: Alignment.center,
child: Container(
width: screenSize.height - 80-58,
height: screenSize.height - 80-58,
child: GridView.count(
crossAxisCount: 3,
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0,
children: gridList,
)));
},
);
}
gridItem(String url, String showText, int index, Color color) {
return GestureDetector(
onTap: () {
_model.onItemClick(context, index);
},
onLongPress: () {
_model.onDeleteItem(context, index);
},
child: Container(
alignment: Alignment.bottomRight,
decoration: BoxDecoration(
image:
DecorationImage(fit: BoxFit.cover, image: NetworkImage(url))),
child: Container(
color: Colors.yellow,
alignment: Alignment.center,
width: 150,
height: 30,
child: baseText(showText, 15, color),
),
));
}
sync(BuildContext context) {
return Container(
width: double.maxFinite,
height: 30,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 16,
),
baseText("刷新", 15, ALColors.Color323232),
GestureDetector(
onTap: () {
_model.getImages(context, true);
_model.getTotalImages(context);
},
child: Container(
padding: EdgeInsets.only(left: 20),
child: Icon(
Icons.sync,
color: Colors.black,
),
)),
Container(
margin: EdgeInsets.only(left: 50),
child: baseText("长按删除图片", 15, Colors.red),
),
Expanded(
child: StreamBuilder<TotalImageBean>(
stream: _model.totalLive.stream,
initialData: _model.totalLive.data,
builder: (con, data) {
if (data.data == null) {
return loadingItem();
}
return Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 20),
child: baseText(
"已标注图片的数量:${data.data.totalTag} 未标注图片的数量${data.data.total}",
15,
Colors.black),
);
},
))
],
),
);
}
nextBefor(BuildContext context) {
return Container(
width: double.maxFinite,
height: 50,
child: Row(
children: <Widget>[
FlatButton(
onPressed: () {
_model.before(context);
},
child: Container(
width: 100,
height: double.maxFinite,
alignment: Alignment.center,
child: baseText("上一页", 15, Colors.black),
),
),
Expanded(
child: StreamBuilder<int>(
stream: _model.countLive.stream,
initialData: _model.countLive.data,
builder: (con, data) {
if (data.data == null) {
return loadingItem();
}
return Container(
alignment: Alignment.center,
child: baseText("第${data.data}页", 15, Colors.black),
);
},
)),
FlatButton(
onPressed: () {
_model.after(context);
},
child: Container(
width: 100,
height: double.maxFinite,
alignment: Alignment.center,
child: baseText("下一页", 15, Colors.black),
),
)
],
),
);
}
}
/*
* @author lsy
* @date 2019-11-08
**/
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;
import 'package:example_flutter/HomeModel/base/bean/PointItem.dart';
import 'package:example_flutter/HomeModel/page/work/temp.dart';
import 'package:example_flutter/HomeModel/service/HomeRepo.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/AllTabBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/UploadResultBean.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/picker/base/BasePickerComponent.dart';
import 'package:example_flutter/commonModel/toast/toast.dart';
import 'package:example_flutter/commonModel/util/ImageUtil.dart';
import 'package:example_flutter/res/GMRes.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animation_set/animator.dart';
class WorkModel extends BaseModel {
LiveData<PointItem> pointLive = new LiveData();
LiveData<List<int>> nowIndexLive = new LiveData();
LiveData<Map<String, List<List<String>>>> selectLive = new LiveData();
LiveData<Map<String, List<List<String>>>> tabLive = new LiveData();
Map<String, List<List<String>>> selectMap = new Map();
Map<String, List<List<String>>> fixDataMap = new Map();
HomeRepo _repo = HomeRepo.getInstance();
PointItem pointItem = new PointItem();
AllTabBean allTabBean;
int imageId;
int currentIndex;
WorkModel(this.imageId, this.currentIndex);
getImageResutl(BuildContext context, bool showPicker) {
if (showPicker) {
BaseCenterPicker()
..setPicker(BaseLoadingItem("加载中..."))
..show(context);
}
_repo.imageAi(imageId).listen((value) {
selectMap.clear();
List<List<String>> browList = new List();
if (value.anno.browsStyle != null && value.anno.browsStyle != "无结果") {
browList.add([EXPLAN["brows_style"], value.anno.browsStyle]);
}
if (value.anno.browsThickness != null &&
value.anno.browsThickness != "无结果") {
browList.add([EXPLAN["brows_thickness"], value.anno.browsThickness]);
}
if (value.anno.dense != null && value.anno.dense != "无结果") {
browList.add([EXPLAN["Dense"], value.anno.dense]);
}
if (value.anno.browDensity != null && value.anno.browDensity != "无结果") {
browList.add([EXPLAN["brow_density"], value.anno.browDensity]);
}
if (value.anno.browsSpacing != null && value.anno.browsSpacing != "无结果") {
browList.add([EXPLAN["brows_spacing"], value.anno.browsSpacing]);
}
if (value.anno.browShape != null && value.anno.browShape != "无结果") {
browList.add([EXPLAN["brow_shape"], value.anno.browShape]);
}
if (browList.isNotEmpty) {
selectMap.putIfAbsent("眉毛部分", () => browList);
}
List<List<String>> eyeList = new List();
if (value.anno.eyelidLeft != null && value.anno.eyelidLeft != "无结果") {
eyeList.add([EXPLAN["eyelid_left"], value.anno.eyelidLeft]);
}
if (value.anno.eyelidRight != null && value.anno.eyelidRight != "无结果") {
eyeList.add([EXPLAN["eyelid_right"], value.anno.eyelidRight]);
}
if (value.anno.eyeShapeRight != null &&
value.anno.eyeShapeRight != "无结果") {
eyeList.add([EXPLAN["eye_shape_right"], value.anno.eyeShapeRight]);
}
if (value.anno.eyeShapeLeft != null && value.anno.eyeShapeLeft != "无结果") {
eyeList.add([EXPLAN["eye_shape_left"], value.anno.eyeShapeLeft]);
}
if (value.anno.pouch != null && value.anno.pouch != "无结果") {
eyeList.add([EXPLAN["pouch"], value.anno.pouch]);
}
if (value.anno.eyeDistance != null && value.anno.eyeDistance != "无结果") {
eyeList.add([EXPLAN["eye_distance"], value.anno.eyeDistance]);
}
if (eyeList.isNotEmpty) {
selectMap.putIfAbsent("眼睛部分", () => eyeList);
}
List<List<String>> noseList = new List();
if (value.anno.nose != null && value.anno.nose != "无结果") {
noseList.add([EXPLAN["nose"], value.anno.nose]);
}
if (noseList.isNotEmpty) {
selectMap.putIfAbsent("鼻子部分", () => noseList);
}
List<List<String>> lipList = new List();
if (value.anno.lipThickness != null && value.anno.lipThickness != "无结果") {
lipList.add([EXPLAN["lip_thickness"], value.anno.lipThickness]);
}
if (value.anno.lipPeak != null && value.anno.lipPeak != "无结果") {
lipList.add([EXPLAN["lip_peak"], value.anno.lipPeak]);
}
if (value.anno.lipShape != null && value.anno.lipShape != "无结果") {
lipList.add([EXPLAN["lip_shape"], value.anno.lipShape]);
}
if (value.anno.lipRadian != null && value.anno.lipRadian != "无结果") {
lipList.add([EXPLAN["lip_radian"], value.anno.lipRadian]);
}
if (lipList.isNotEmpty) {
selectMap.putIfAbsent("嘴唇部分", () => lipList);
}
List<List<String>> wrinkList = new List();
if (value.anno.wrink != null && value.anno.wrink != "无结果") {
wrinkList.add([EXPLAN["wrink"], value.anno.wrink]);
}
if (wrinkList.isNotEmpty) {
selectMap.putIfAbsent("法令纹", () => wrinkList);
}
List<List<String>> cheekboneList = new List();
if (value.anno.cheekbone != null && value.anno.cheekbone != "无结果") {
cheekboneList.add([EXPLAN["cheekbone"], value.anno.cheekbone]);
}
if (cheekboneList.isNotEmpty) {
selectMap.putIfAbsent("颧骨部分", () => cheekboneList);
}
List<List<String>> chinList = new List();
if (value.anno.chinShape != null && value.anno.chinShape != "无结果") {
chinList.add([EXPLAN["chin_shape"], value.anno.chinShape]);
}
if (chinList.isNotEmpty) {
selectMap.putIfAbsent("下巴部分", () => chinList);
}
List<List<String>> faceList = new List();
if (value.anno.face != null && value.anno.face != "无结果") {
faceList.add([EXPLAN["face"], value.anno.face]);
}
if (faceList.isNotEmpty) {
selectMap.putIfAbsent("脸型相关", () => faceList);
}
selectLive.notifyView(selectMap);
if (showPicker) {
Navigator.pop(context);
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
Toast.show(context, "这个照片估计识别不出来 导致出错");
if (showPicker) {
Navigator.pop(context);
}
});
}
selectChangeToMap() {}
allTab(BuildContext context, bool showPicker) {
if (showPicker) {
BaseCenterPicker()
..setPicker(BaseLoadingItem("加载中"))
..show(context);
}
nowIndexLive.notifyView([_repo.currentPage, currentIndex + 1]);
HomeRepo.getInstance().getAllTab().listen((value) {
allTabBean = value;
fixDataMap.clear();
//=====眉毛
List<List<String>> browList = new List();
List<String> eyebrowStyle = new List();
eyebrowStyle.add(allTabBean.eyebrowstyle.name);
eyebrowStyle.add(allTabBean.eyebrowstyle.eyebrowstyleData.willow);
eyebrowStyle.add(allTabBean.eyebrowstyle.eyebrowstyleData.wild);
List<String> eyebrowthickStyle = new List();
eyebrowthickStyle.add(allTabBean.eyebrowthickness.name);
eyebrowthickStyle
.add(allTabBean.eyebrowthickness.eyebrowthicknessData.cumei);
eyebrowthickStyle
.add(allTabBean.eyebrowthickness.eyebrowthicknessData.biaozhunmei);
eyebrowthickStyle
.add(allTabBean.eyebrowthickness.eyebrowthicknessData.xiemei);
List<String> concen = new List();
concen.add(allTabBean.eyebrowsconcentration.name);
concen.add(
allTabBean.eyebrowsconcentration.eyebrowsconcentrationData.piandan);
concen.add(allTabBean
.eyebrowsconcentration.eyebrowsconcentrationData.feichandan);
concen.add(allTabBean
.eyebrowsconcentration.eyebrowsconcentrationData.nongduzhenghao);
List<String> concenf = new List();
concenf.add(allTabBean.eyebrowsconcentrationF.name);
concenf.add(allTabBean
.eyebrowsconcentrationF.eyebrowsconcentrationFData.fenbujunyun);
concenf.add(allTabBean
.eyebrowsconcentrationF.eyebrowsconcentrationFData.qianshuhoumi);
concenf.add(allTabBean
.eyebrowsconcentrationF.eyebrowsconcentrationFData.qianmuhoushu);
concenf.add(allTabBean
.eyebrowsconcentrationF.eyebrowsconcentrationFData.lianjunyun);
List<String> brow = new List();
brow.add(allTabBean.brow.name);
brow.add(allTabBean.brow.browData.wide);
brow.add(allTabBean.brow.browData.narrow);
brow.add(allTabBean.brow.browData.appropriate);
List<String> eyebrow = new List();
eyebrow.add(allTabBean.eyebow.name);
eyebrow.add(allTabBean.eyebow.eyebowData.on);
eyebrow.add(allTabBean.eyebow.eyebowData.standard);
eyebrow.add(allTabBean.eyebow.eyebowData.one);
eyebrow.add(allTabBean.eyebow.eyebowData.sagging);
browList.add(eyebrowStyle);
browList.add(eyebrowthickStyle);
browList.add(concen);
browList.add(concenf);
browList.add(brow);
browList.add(eyebrow);
fixDataMap.putIfAbsent("眉毛部分", () => browList);
//=====眼睛👀
List<List<String>> eyeList = new List();
List<String> lefteye = new List();
lefteye.add(allTabBean.leftEye.name);
lefteye.add(allTabBean.leftEye.leftEyeData.seye);
lefteye.add(allTabBean.leftEye.leftEyeData.eyes);
lefteye.add(allTabBean.leftEye.leftEyeData.doubleIn);
List<String> righteye = new List();
righteye.add(allTabBean.rigthEye.name);
righteye.add(allTabBean.rigthEye.rigthEyeData.seye);
righteye.add(allTabBean.rigthEye.rigthEyeData.eyes);
righteye.add(allTabBean.rigthEye.rigthEyeData.doubleIn);
List<String> eyebag = new List();
eyebag.add(allTabBean.eyebag.name);
eyebag.add(allTabBean.eyebag.eyebagData.yes);
eyebag.add(allTabBean.eyebag.eyebagData.no);
List<String> eyeStyleleft = new List();
eyeStyleleft.add(allTabBean.eyestyleLeft.name);
eyeStyleleft.add(allTabBean.eyestyleLeft.eyestyleLeftData.almonEyes);
eyeStyleleft.add(allTabBean.eyestyleLeft.eyestyleLeftData.peach);
eyeStyleleft.add(allTabBean.eyestyleLeft.eyestyleLeftData.fineCheng);
eyeStyleleft.add(allTabBean.eyestyleLeft.eyestyleLeftData.deerEye);
eyeStyleleft.add(allTabBean.eyestyleLeft.eyestyleLeftData.dogEye);
List<String> eyeStyleright = new List();
eyeStyleright.add(allTabBean.eyestyleRight.name);
eyeStyleright.add(allTabBean.eyestyleRight.eyestyleRightData.almonEyes);
eyeStyleright.add(allTabBean.eyestyleRight.eyestyleRightData.peach);
eyeStyleright.add(allTabBean.eyestyleRight.eyestyleRightData.fineCheng);
eyeStyleright.add(allTabBean.eyestyleRight.eyestyleRightData.deerEye);
eyeStyleright.add(allTabBean.eyestyleRight.eyestyleRightData.dogEye);
List<String> eyeSpace = new List();
eyeSpace.add(allTabBean.eyespacing.name);
eyeSpace.add(allTabBean.eyespacing.eyespacingData.wide);
eyeSpace.add(allTabBean.eyespacing.eyespacingData.narrow);
eyeSpace.add(allTabBean.eyespacing.eyespacingData.appropriate);
eyeList.add(lefteye);
eyeList.add(righteye);
eyeList.add(eyeStyleleft);
eyeList.add(eyeStyleright);
eyeList.add(eyebag);
eyeList.add(eyeSpace);
fixDataMap.putIfAbsent("眼睛部分", () => eyeList);
//======== 鼻子👃
List<List<String>> noseList = new List();
List<String> nose = new List();
nose.add(allTabBean.nose.name);
nose.add(allTabBean.nose.noseData.narrowNose);
nose.add(allTabBean.nose.noseData.standardNose);
nose.add(allTabBean.nose.noseData.widepNose);
nose.add(allTabBean.nose.noseData.wideNose);
noseList.add(nose);
fixDataMap.putIfAbsent("鼻子部分", () => noseList);
//====== 嘴唇👄
List<List<String>> mouthList = new List();
List<String> mouth = new List();
mouth.add(allTabBean.mouth.name);
mouth.add(allTabBean.mouth.mouthData.standard);
mouth.add(allTabBean.mouth.mouthData.thick);
mouth.add(allTabBean.mouth.mouthData.thin);
List<String> lip = new List();
lip.add(allTabBean.lip.name);
lip.add(allTabBean.lip.lipData.yes);
lip.add(allTabBean.lip.lipData.no);
lip.add(allTabBean.lip.lipData.notObvious);
List<String> lipscurved = new List();
lipscurved.add(allTabBean.lipscurved.name);
lipscurved.add(allTabBean.lipscurved.lipscurvedData.smile);
lipscurved.add(allTabBean.lipscurved.lipscurvedData.moderate);
lipscurved.add(allTabBean.lipscurved.lipscurvedData.attitude);
List<String> Speciallip = new List();
Speciallip.add(allTabBean.speciallip.name);
Speciallip.add(allTabBean.speciallip.speciallipData.cherryLip);
Speciallip.add(allTabBean.speciallip.speciallipData.supermodelLip);
mouthList.add(mouth);
mouthList.add(lip);
mouthList.add(lipscurved);
mouthList.add(Speciallip);
fixDataMap.putIfAbsent("嘴唇部分", () => mouthList);
//=======其他
List<List<String>> wrinkList = new List();
List<String> wrink = new List();
wrink.add(allTabBean.wrink.name);
wrink.add(allTabBean.wrink.wrinkData.yes);
wrink.add(allTabBean.wrink.wrinkData.no);
wrinkList.add(wrink);
fixDataMap.putIfAbsent("法令纹", () => wrinkList);
List<List<String>> checkboneList = new List();
List<String> checkbone = new List();
checkbone.add(allTabBean.checkbone.name);
checkbone.add(allTabBean.checkbone.checkboneData.high);
checkbone.add(allTabBean.checkbone.checkboneData.flat);
checkboneList.add(checkbone);
fixDataMap.putIfAbsent("颧骨部分", () => checkboneList);
List<List<String>> chinList = new List();
List<String> chin = new List();
chin.add(allTabBean.chin.name);
chin.add(allTabBean.chin.chinData.tip);
chin.add(allTabBean.chin.chinData.party);
chin.add(allTabBean.chin.chinData.round);
chin.add(allTabBean.chin.chinData.ass);
chinList.add(chin);
fixDataMap.putIfAbsent("下巴部分", () => chinList);
List<List<String>> faceList = new List();
List<String> face = new List();
face.add(allTabBean.face.name);
face.add(allTabBean.face.faceData.babyFace);
face.add(allTabBean.face.faceData.guazilian);
face.add(allTabBean.face.faceData.fanglian);
face.add(allTabBean.face.faceData.edanlian);
face.add(allTabBean.face.faceData.changxinglian);
face.add(allTabBean.face.faceData.lixinglian);
face.add(allTabBean.face.faceData.jingzhuan);
faceList.add(face);
fixDataMap.putIfAbsent("脸型相关", () => faceList);
tabLive.notifyView(fixDataMap);
if (showPicker) {
Navigator.pop(context);
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
if (showPicker) {
Navigator.pop(context);
}
});
}
@override
void dispose() {
pointLive.dispost();
nowIndexLive.dispost();
tabLive.dispost();
selectLive.dispost();
}
void selectItem(String key, String title, String result) {
List<List<String>> innlist = selectMap[key];
if (innlist == null || innlist.isEmpty) {
selectMap[key] = [
[title, result]
];
} else {
int index = -1;
for (int i = 0; i < innlist.length; i++) {
if (innlist[i][0] == title) {
index = i;
break;
}
}
if (index != -1) {
innlist[index][1] = result;
} else {
List<String> list = [title, result];
innlist.add(list);
}
}
selectLive.notifyView(selectMap);
}
void deleteSelectItem(BuildContext context, String key, String title) {
BaseCenterPicker()
..setPicker(SurePicker("确定删除这个条目吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
var selectList = selectMap[key];
if (selectList != null && selectList.isNotEmpty) {
if (selectList.length == 1) {
selectMap.remove(key);
} else {
int index = -1;
for (int i = 0; i < selectList.length; i++) {
if (selectList[i][0] == title) {
index = i;
}
}
if (index != -1) {
selectList.removeAt(index);
}
}
}
selectLive.notifyView(selectMap);
}))
..show(context);
}
void imageNext(BuildContext context) {
if (currentIndex == 8) {
_repo.getImageResult(_repo.currentPage + 1, 9).listen((data) {
if (data == null || data.picList == null || data.picList.isEmpty) {
Toast.show(context, "已经是最后一张了哦~");
} else {
currentIndex = 0;
_repo.currentPage = _repo.currentPage + 1;
_repo.updateCurrentPageList(data.picList);
getNetWorkImg(context);
imageId = _repo.getCurrentPageList()[currentIndex].id;
nowIndexLive.notifyView([_repo.currentPage, currentIndex + 1]);
selectLive.notifyView(null);
getImageResutl(context, false);
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
} else {
if (currentIndex + 1 > _repo.getCurrentPageList().length - 1) {
Toast.show(context, "已经是最后一张了哦~");
return;
}
currentIndex = currentIndex + 1;
getNetWorkImg(context);
imageId = _repo.getCurrentPageList()[currentIndex].id;
selectLive.notifyView(null);
getImageResutl(context, false);
nowIndexLive.notifyView([_repo.currentPage, currentIndex + 1]);
}
}
void imageBefore(BuildContext context) {
if (currentIndex == 0) {
if (_repo.currentPage == 1) {
Toast.show(context, "已经是第一张了哦~");
return;
}
_repo.currentPage = _repo.currentPage - 1;
_repo.getImageResult(_repo.currentPage, 9).listen((data) {
currentIndex = 8;
_repo.updateCurrentPageList(data.picList);
getNetWorkImg(context);
imageId = _repo.getCurrentPageList()[currentIndex].id;
selectLive.notifyView(null);
getImageResutl(context, false);
nowIndexLive.notifyView([_repo.currentPage, currentIndex + 1]);
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
} else {
currentIndex = currentIndex - 1;
getNetWorkImg(context);
imageId = _repo.getCurrentPageList()[currentIndex].id;
selectLive.notifyView(null);
getImageResutl(context, false);
nowIndexLive.notifyView([_repo.currentPage, currentIndex + 1]);
}
}
void save(BuildContext context, bool param1) {
BaseCenterPicker()
..setPicker(BaseLoadingItem("保存中..."))
..show(context);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.write("""
{"face_details":{
""");
List<List<String>> finalResult = new List();
selectMap.forEach((key, value) {
for (int i = 0; i < value.length; i++) {
String before;
EXPLAN.forEach((k, v) {
if (v == value[i][0]) {
before = k;
}
});
finalResult.add([before, value[i][1]]);
}
});
for (int i = 0; i < finalResult.length; i++) {
stringBuffer.write("""
"${finalResult[i][0]}":"${finalResult[i][1]}"
""");
if (i != finalResult.length - 1) {
stringBuffer.write(",");
}
}
stringBuffer.write("}}");
print("====> ${stringBuffer.toString()}");
_repo.saveImageResult(imageId, stringBuffer.toString()).listen((value) {
if (value != null) {
Navigator.pop(context);
Navigator.pop(context, -1);
Toast.show(context, "保存成功");
}
}).onError((error) {
Toast.show(context, error.toString());
print(error.toString());
Navigator.pop(context);
});
}
void saveImage(BuildContext context) {
Toast.show(context, "开始保存图片");
getTempDir().then((value) {
if (value != null) {
print(value);
DioUtil().getDio().download(_repo.getCurrentPageList()[currentIndex].picurl,
"${value}/${DateTime.now().millisecondsSinceEpoch}.jpeg",
onReceiveProgress: (int count, int total) {
//进度
// Toast.show(context, "进度!! $count $total");
print("进度!! $count $total");
}).then((value) {
Toast.show(context, "下载完成");
print("OKKK ");
openCachce();
}).catchError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
}
});
}
void syncPos(double dx, double dy) {
pointItem.setX(dx);
pointItem.setY(dy);
pointLive.notifyView(pointItem);
}
void getNetWorkImg(BuildContext context) {
loadNetWorkImage(_repo.getCurrentPageList()[currentIndex].picurl).then((value) {
pointItem.reset();
pointItem.setImage(value);
pointLive.notifyView(pointItem);
}).catchError((error) {
Toast.show(context, error.toString());
print(error.toString());
});
}
void syncPoint() {
pointLive.notifyView(pointItem);
}
}
class SurePicker implements ICenterPicker {
VoidCallback cancel;
VoidCallback sure;
final String showText;
SurePicker(this.showText, this.cancel, this.sure);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(20))),
width: 350,
height: 260,
child: Column(
children: <Widget>[
Expanded(
child: Container(
alignment: Alignment.center,
child: baseText(showText, 15, Colors.black),
),
),
Container(
height: 1,
width: double.maxFinite,
color: Colors.black54,
),
Container(
width: double.maxFinite,
height: 50,
child: Row(
children: <Widget>[
Expanded(
child: GestureDetector(
onTap: cancel,
child: Container(
color: Colors.transparent,
alignment: Alignment.center,
child: baseText("取消", 12, Colors.black38),
)),
),
Container(
width: 1,
height: double.maxFinite,
color: Colors.black54,
),
Expanded(
child: GestureDetector(
onTap: sure,
child: Container(
color: Colors.transparent,
alignment: Alignment.center,
child: baseText("确定", 12, Colors.red),
),
),
)
],
),
)
],
),
);
}
}
/*
* @author lsy
* @date 2019-11-08
**/
import 'dart:ui' as ui;
import 'package:example_flutter/HomeModel/base/bean/PointItem.dart';
import 'package:example_flutter/HomeModel/base/view/WorkView.dart';
import 'package:example_flutter/HomeModel/page/work/WorkModel.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/AllTabBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/UploadResultBean.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/base/MySeparator.dart';
import 'package:example_flutter/commonModel/cache/CacheManager.dart';
import 'package:example_flutter/commonModel/dragScare/flutter_drag_scale.dart';
import 'package:example_flutter/commonModel/toast/toast.dart';
import 'package:example_flutter/res/GMRes.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/svg.dart';
class WorkPage extends StatefulWidget {
final String url;
final int id;
final int currentIndex;
WorkPage(this.url, this.id, this.currentIndex);
@override
State<StatefulWidget> createState() => WorkState(url, id, currentIndex);
}
class WorkState extends State<WorkPage> {
WorkModel _model;
Size screenSize;
double tabItemHeight;
double tabHeadHeight;
double rightAllWidth;
double rightTitleHeight;
final String url;
double dragStartX, dragStartY, startTranX, startTranY;
double tapStartX, tapStartY;
WorkState(this.url, int id, int currentIndex) {
_model = new WorkModel(id, currentIndex);
}
@override
void initState() {
super.initState();
_model.allTab(context, false);
_model.getImageResutl(context, false);
_model.getNetWorkImg(context);
}
@override
void dispose() {
_model.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
screenSize = MediaQuery.of(context).size;
tabItemHeight = 30;
rightAllWidth = 280;
rightTitleHeight = 15;
String userName =
CacheManager.getInstance().get(MEMORY_CACHE).get("userName");
return Scaffold(
appBar: baseAppBar(
backgroundColor: ALColors.Color5276F4,
backClick: () {
BaseCenterPicker()
..setPicker(SurePicker("确定返回吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
Navigator.pop(context);
}))
..show(context);
},
action: <Widget>[
Expanded(
child: Container(),
),
Container(
margin: EdgeInsets.only(right: ScreenUtil.instance.setWidth(10)),
alignment: Alignment.center,
child: baseText(userName, 30, ALColors.ColorF8F8F8),
),
Container(
width: kToolbarHeight,
height: kToolbarHeight,
margin: EdgeInsets.only(
left: ScreenUtil.instance.setWidth(5),
right: ScreenUtil.instance.setWidth(50),
top: 5,
bottom: 5),
child: SvgPicture.asset("image/Face.svg"),
),
]),
body: Row(
children: <Widget>[
Expanded(
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
Container(
width: double.maxFinite,
height: double.maxFinite,
color: Colors.black54,
child: Listener(
onPointerDown: (down) {
print("onPointerDownEvent");
},
onPointerMove: (move) {
print("onPointerMove");
},
onPointerUp: (up) {
print("onPointerUp");
},
onPointerHover: (hover) {
_model.syncPos(hover.position.dx,
hover.position.dy - kToolbarHeight);
// Toast.show(context,
// "onPointerHover ${hover.position.dx} ${hover.position.dy}");
},
onPointerExit: (exit) {
print("onPointerExit");
},
onPointerCancel: (cancle) {
print("onPointerCancel");
},
onPointerEnter: (enter) {
print("onPointerEnter");
},
)),
StreamBuilder<PointItem>(
stream: _model.pointLive.stream,
initialData: _model.pointLive.data,
builder: (con, data) {
if (data.data == null) {
return Container();
}
return GestureDetector(
onVerticalDragDown: (details) {
startTranX = _model.pointItem.tranX;
startTranY = _model.pointItem.tranY;
dragStartX = details.localPosition.dx;
dragStartY = details.localPosition.dy;
},
onVerticalDragUpdate: (details) {
if (_model.pointItem.scareSize == 1) {
return;
}
_model.pointItem.setTranX(startTranX -
(details.localPosition.dx - dragStartX));
_model.pointItem.setTranY(startTranY -
(details.localPosition.dy - dragStartY));
_model.syncPoint();
},
onTap: () {
_model.pointItem.addPoint(tapStartX, tapStartY);
_model.syncPoint();
},
onTapDown: (details) {
tapStartX = details.localPosition.dx;
tapStartY = details.localPosition.dy;
print("gesture onTap down");
},
// onDoubleTap: () {
// if (_model.pointItem.scareSize == 1) {
// _model.pointItem.setScareSize(3);
// _model.pointItem.setTranX(_model.pointItem.getX());
// _model.pointItem.setTranY(_model.pointItem.getY());
// _model.syncPoint();
// } else {
// _model.pointItem.setScareSize(1);
// _model.pointItem.setTranX(0);
// _model.pointItem.setTranY(0);
// _model.syncPoint();
// }
// },
child: ClipRect(
child: Container(
width: double.maxFinite,
height: double.maxFinite,
child: CustomPaint(painter: WorkView(_model.pointItem)),
)));
},
),
Container(
width: double.maxFinite,
height: double.maxFinite,
alignment: Alignment.topCenter,
child: Container(
width: double.maxFinite,
height: 80,
color: Colors.black54,
child: Row(
children: <Widget>[
Expanded(
child: FlatButton(
onPressed: () {
_model.saveImage(context);
},
child: Container(
color: Colors.pink,
alignment: Alignment.center,
child: baseText("保存图片", 15, Colors.white),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
_model.pointItem.close();
_model.syncPoint();
},
child: Container(
width: double.maxFinite,
height: double.maxFinite,
color: Colors.lightBlueAccent,
alignment: Alignment.center,
child: baseText("闭合标记", 15, Colors.white),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
_model.pointItem.removePoint();
_model.syncPoint();
},
child: Container(
color: Colors.green,
width: double.maxFinite,
height: double.maxFinite,
alignment: Alignment.center,
child: baseText("撤销标记", 15, Colors.white),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
if (_model.pointItem.scareSize == 1) {
_model.pointItem.setScareSize(3);
_model.pointItem
.setTranX(_model.pointItem.getX());
_model.pointItem
.setTranY(_model.pointItem.getY());
_model.syncPoint();
} else {
_model.pointItem.setScareSize(1);
_model.pointItem.setTranX(0);
_model.pointItem.setTranY(0);
_model.syncPoint();
}
},
child: Container(
width: double.maxFinite,
height: double.maxFinite,
color: Colors.yellow,
alignment: Alignment.center,
child: baseText("放大&缩小", 15, Colors.white),
),
),
),
Expanded(
child: FlatButton(
onPressed: () {
_model.saveImage(context);
},
child: Container(
color: Colors.pink,
alignment: Alignment.center,
child: baseText("保存标记结果", 15, Colors.white),
),
),
),
],
)),
),
Container(
width: double.maxFinite,
height: 50,
color: Colors.black54,
),
StreamBuilder<List<int>>(
stream: _model.nowIndexLive.stream,
initialData: _model.nowIndexLive.data,
builder: (con, data) {
if (data.data == null) {
return loadingItem();
}
return Container(
height: 50,
alignment: Alignment.center,
child: baseText("第${data.data[0]}页 第${data.data[1]}张", 15,
Colors.white),
);
},
),
Positioned(
left: 0,
bottom: 0,
child: FlatButton(
onPressed: () {
BaseCenterPicker()
..setPicker(SurePicker("还没有保存哦 确定上一张吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
_model.imageBefore(context);
}))
..show(context);
},
child: Container(
width: 50,
height: 30,
alignment: Alignment.centerLeft,
child: baseText("上一张", 15, Colors.white),
),
),
),
Positioned(
right: 0,
bottom: 0,
child: FlatButton(
onPressed: () {
BaseCenterPicker()
..setPicker(SurePicker("还没有保存哦 确定下一张吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
_model.imageNext(context);
}))
..show(context);
},
child: Container(
width: 50,
height: 30,
alignment: Alignment.center,
child: baseText("下一张", 15, Colors.white),
),
),
),
],
)),
Container(
margin: EdgeInsets.only(left: 2, right: 2),
color: Colors.black38,
width: 1,
height: double.maxFinite,
),
centerItem(),
Container(
margin: EdgeInsets.only(left: 2, right: 2),
color: Colors.black38,
width: 1,
height: double.maxFinite,
),
rightItem()
],
),
);
}
rightItem() {
return Container(
height: double.maxFinite,
width: rightAllWidth,
child: StreamBuilder<Map<String, List<List<String>>>>(
stream: _model.tabLive.stream,
initialData: _model.tabLive.data,
builder: (con, data) {
if (data.data == null || data.data.isEmpty) {
// return Container(
// alignment: Alignment.center,
// child: OutlineButton(
// onPressed: () {
// _model.allTab(context);
// },
// child: baseText("重试", 20, ALColors.Color323232),
// ),
// );
return Center(child: CircularProgressIndicator());
}
tabHeadHeight = 30 + kToolbarHeight;
double center1 = screenSize.width - rightAllWidth;
double center2 = screenSize.width - rightAllWidth / 2;
List<Widget> allList = new List();
allList.add(tabHead());
double startHeight = tabHeadHeight;
data.data.forEach((k, value) {
startHeight = startHeight + (rightTitleHeight + tabItemHeight);
allList.add(divideItem(k));
List<Widget> grids = new List();
for (int i = 0; i < value.length; i++) {
if (i == 0) {
grids.add(glidItem(k, value[i], startHeight, center1));
} else if (i == 1) {
grids.add(glidItem(k, value[i], startHeight, center2));
} else if (i == 2) {
startHeight = startHeight + (tabItemHeight);
grids.add(glidItem(k, value[i], startHeight, center1));
} else if (i == 3) {
grids.add(glidItem(k, value[i], startHeight, center2));
} else if (i == 4) {
startHeight = startHeight + (tabItemHeight);
grids.add(glidItem(k, value[i], startHeight, center1));
} else if (i == 5) {
grids.add(glidItem(k, value[i], startHeight, center2));
} else if (i == 6) {
startHeight = startHeight + (tabItemHeight);
grids.add(glidItem(k, value[i], startHeight, center1));
}
}
int count = (value.length / 2).ceil();
allList.add(tabItem(tabItemHeight * count, grids));
});
return ListView(
physics: BouncingScrollPhysics(),
children: allList,
);
},
));
}
tabItem(double height, List<Widget> items) {
return Container(
width: rightAllWidth / 2,
height: height,
child: GridView.count(
crossAxisCount: 2,
childAspectRatio: rightAllWidth / 2 / tabItemHeight,
children: items,
),
);
}
divideItem(String text) {
return Container(
alignment: Alignment.center,
width: double.maxFinite,
height: rightTitleHeight,
child: baseText(text, 10, Colors.black54),
);
}
glidItem(String key, List<String> dataList, double top, double left) {
String title = dataList[0];
List<PopupMenuItem<String>> list = new List();
for (int i = 1; i < dataList.length; i++) {
list.add(PopupMenuItem(
value: dataList[i],
child: Container(
width: rightAllWidth / 2,
alignment: Alignment.center,
child: baseText(dataList[i], 12, ALColors.Color666666),
)));
}
return Container(
padding: EdgeInsets.all(5),
child: FlatButton(
color: Colors.lightBlueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5))),
onPressed: () async {
final result = await showMenu(
context: context,
position: RelativeRect.fromLTRB(
left, top, left + rightAllWidth / 2, 0),
items: list);
print(result);
if (result != null) {
_model.selectItem(key, title, result);
}
},
child: Container(
// width: double.maxFinite,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Container(),
),
Container(
padding: EdgeInsets.only(right: 5),
child: baseText(title, 15, ALColors.ColorFFFFFF),
),
SvgPicture.asset("image/bottom_arrow.svg"),
Expanded(
child: Container(),
),
],
))));
}
tabHead() {
return GestureDetector(
onTap: () => _model.allTab(context, true),
child: Container(
padding: EdgeInsets.only(top: 5, left: 16),
height: 30,
alignment: Alignment.centerLeft,
child: Icon(Icons.sync),
));
}
centerItem() {
return Container(
width: 200,
height: double.maxFinite,
child: StreamBuilder<Map<String, List<List<String>>>>(
stream: _model.selectLive.stream,
initialData: _model.selectLive.data,
builder: (con, data) {
if (data.data == null) {
return Column(
children: <Widget>[
centerTitle(context),
Expanded(
child: Center(child: CircularProgressIndicator()),
)
],
);
}
List<Widget> list = new List();
list.add(centerTitle(context));
data.data.forEach((k, v) {
list.add(divideItem(k));
for (int i = 0; i < v.length; i++) {
list.add(centerListItem(k, "${v[i][0]}:${v[i][1]}", v[i][0]));
}
});
return ListView(
physics: BouncingScrollPhysics(),
children: list,
);
},
));
}
centerListItem(String key, String showText, String title) {
return Container(
margin: EdgeInsets.all(5),
color: Colors.lightBlue,
width: double.maxFinite,
height: 30,
child: Stack(
alignment: AlignmentDirectional.center,
children: <Widget>[
Positioned(
right: 5,
top: 3,
child: GestureDetector(
onTap: () {
_model.deleteSelectItem(context, key, title);
},
child: Icon(
Icons.delete,
color: Colors.red,
),
)),
baseText(showText, 16, Colors.white)
],
),
);
}
Widget centerTitle(BuildContext context) {
return Container(
width: double.maxFinite,
height: 30,
padding: EdgeInsets.only(top: 5, left: 5),
alignment: Alignment.centerLeft,
child: Row(
children: <Widget>[
GestureDetector(
onTap: () {
BaseCenterPicker()
..setPicker(SurePicker("清除已经选好的数据 重新识别图片吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
_model.getImageResutl(context, true);
}))
..show(context);
},
child: Icon(Icons.sync)),
Expanded(
child: Container(),
),
GestureDetector(
onTap: () {
BaseCenterPicker()
..setPicker(SurePicker("确定保存吗?", () {
Navigator.pop(context);
}, () {
Navigator.pop(context);
_model.save(context, true);
}))
..show(context);
},
child: Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.all(Radius.circular(2))),
alignment: Alignment.center,
height: double.maxFinite,
width: 50,
margin: EdgeInsets.only(right: 5),
child: baseText("保存", 15, Colors.white),
),
)
],
),
);
}
}
/*
* @author lsy
* @date 2019-11-14
**/
const String TEST_IMAGES = """
{
"pic_list": [
{
"picurl": "https://anno-1258538551.cos.ap-chengdu.myqcloud.com/f540275d1e6d2fbad9273a8f17924e94.png",
"id": 11,
"status": "2"
},
{
"picurl": "https://anno-1258538551.cos.ap-chengdu.myqcloud.com/f540275d1e6d2fbad9273a8f17924e94",
"id": 12,
"status": "2"
}
]
}
""";
const String CACHE_JSON = """
{
"left_eye": {
"name": "左眼",
"leftEyeData": {
"seye": "单眼皮",
"eyes": "双眼皮",
"doubleIn": "内双"
}
},
"rigth_eye": {
"name": "右眼",
"rigthEyeData": {
"seye": "单眼皮",
"eyes": "双眼皮",
"doubleIn": "内双"
}
},
"eyebag": {
"name": "眼袋",
"eyebagData": {
"yes": "有",
"no": "无"
}
},
"eyestyle_left": {
"name": "左眼风格",
"eyestyleLeftData": {
"Almon_eyes": "杏眼",
"Peach": "桃花眼",
"Fine_cheng": "细凤眼",
"deer_eye": "小鹿眼",
"dog_eye": "小狗眼"
}
},
"eyestyle_right": {
"name": "右眼眼风格",
"eyestyleRightData": {
"Almon_eyes": "杏眼",
"Peach": "桃花眼",
"Fine_cheng": "细凤眼",
"deer_eye": "小鹿眼",
"dog_eye": "小狗眼"
}
},
"nose": {
"name": "鼻翼",
"noseData": {
"Narrow_nose": "窄鼻翼",
"Standard_nose": "标准鼻翼",
"widep_nose": "偏宽鼻翼",
"wide_nose": "宽鼻翼"
}
},
"mouth": {
"name": "嘴唇厚度",
"mouthData": {
"Standard": "标准唇",
"Thick": "厚唇",
"thin": "薄唇"
}
},
"lip": {
"name": "唇峰",
"lipData": {
"yes": "有",
"no": "无",
"not_obvious": "有唇峰,但不明显"
}
},
"wrink": {
"name": "法令纹",
"wrinkData": {
"yes": "有",
"no": "无"
}
},
"checkbone": {
"name": "颧骨",
"checkboneData": {
"high": "高颧骨",
"flat": "平颧骨"
}
},
"eyebow": {
"name": "眉毛挑度",
"eyebowData": {
"On": "上挑眉",
"Standard": "标准眉",
"one": "一字眉",
"sagging": "下垂眉"
}
},
"chin": {
"name": "下巴",
"chinData": {
"tip": "尖",
"party": "方",
"round": "圆",
"Ass": "屁股下巴"
}
},
"Eyebrowstyle": {
"name": "眉毛风格",
"eyebrowstyleData": {
"willow": "柳叶眉",
"wild": "野生眉"
}
},
"eyebrowthickness": {
"name": "眉毛粗细",
"eyebrowthicknessData": {
"cumei": "粗眉",
"biaozhunmei": "标准眉",
"xiemei": "细眉"
}
},
"Eyebrowsconcentration": {
"name": "眉毛浓度",
"eyebrowsconcentrationData": {
"piandan": "偏淡",
"feichandan": "非常淡",
"nongduzhenghao": "浓密正好"
}
},
"Eyebrowsconcentration_f": {
"name": "浓度分布",
"eyebrowsconcentration_fData": {
"fenbujunyun": "分布均匀",
"qianshuhoumi": "前疏后密",
"qianmuhoushu": "前密后疏",
"lianjunyun": "分布偏均匀"
}
},
"eyespacing": {
"name": "两眼间距",
"eyespacingData": {
"wide": "宽",
"narrow": "窄",
"appropriate": "适当"
}
},
"brow": {
"name": "两眉间距",
"browData": {
"wide": "宽",
"narrow": "窄",
"appropriate": "适当"
}
},
"lipscurved": {
"name": "嘴唇弧度",
"lipscurvedData": {
"smile": "微笑唇",
"moderate": "温和唇",
"attitude": "态度唇"
}
},
"Speciallip": {
"name": "嘴唇形态",
"speciallipData": {
"Cherry_lip": "樱桃唇",
"Supermodel_lip": "超模唇"
}
},
"face": {
"name": "脸型",
"faceData": {
"baby_face": "娃娃脸",
"guazilian": "瓜子脸",
"fanglian": "方脸",
"edanlian": "鹅蛋脸",
"changxinglian": "长型脸",
"lixinglian": "梨形脸",
"jingzhuan": "晶钻脸"
}
}
}
""";
const Map<String, String> EXPLAN = {
"eyelid_right": "右眼",
"eyelid_left": "左眼",
"nose": "鼻翼",
"eye_shape_right": "右眼风格",
"eye_shape_left": "左眼风格",
"wrink": "法令纹",
"lip_thickness": "嘴唇厚度",
"lip_peak": "唇峰",
"cheekbone": "颧骨",
"brow_shape": "眉毛挑度",
"brow_density": "浓度分布",
"pouch": "眼袋",
"chin_shape": "下巴",
"eye_distance": "两眼间距",
"lip_shape": "嘴唇形态",
"lip_radian": "嘴唇弧度",
"brows_style": "眉毛风格",
"brows_thickness": "眉毛粗细",
"Dense": "眉毛浓度",
"brows_spacing": "两眉间距",
"face": "脸型",
};
/*
* @author lsy
* @date 2019-11-07
**/
import 'dart:convert';
import 'package:example_flutter/HomeModel/page/work/temp.dart';
import 'package:example_flutter/HomeModel/service/remote/api/HomeApi.serv.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/AllTabBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/DeleteResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageAiBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/PutImageDataBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/TotalImageBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/UploadResultBean.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';
ImageResultBean paseImageResult(String value) {
return ImageResultBean.fromJson(json.decode(value));
}
class HomeRepo {
static HomeRepo _repo;
HomeRepo._();
static HomeRepo getInstance() {
if (_repo == null) {
_repo = new HomeRepo._();
}
return _repo;
}
int currentPage = 1;
Observable<AllTabBean> getAllTab() {
return HomeApiImpl().getAllTab();
}
List<UploadResultBean> scanList = new List();
void updateScanList(List<UploadResultBean> newList) {
this.scanList = newList;
}
Observable<ImageResultBean> getImageResult(
int currentPage, int onePageCount) {
return HomeApiImpl().getImageList(currentPage, 9);
// return Observable.fromFuture(compute(paseImageResult, TEST_IMAGES));
}
Observable<UploadResultBean> upload() {
// DioUtil().downloadFile(urlPath, savePath)
}
List<PicList> currentList = new List();
void updateCurrentPageList(List<PicList> picList) {
if (picList != null && picList.isNotEmpty) {
currentList.clear();
currentList.addAll(picList);
}
}
List<PicList> getCurrentPageList() {
return currentList;
}
Observable<ImageAiBean> imageAi(int id) {
return Observable.fromFuture(DioUtil().get('images/${id}/'))
.flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(compute(paseImageAi, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<PutImageDataBean> saveImageResult(int id, String jsonResult) {
return Observable.fromFuture(DioUtil.getInstance()
.getDio()
.put('images/${id}/', data: jsonResult))
.flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(compute(parsePutImageBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<DeleteResultBean> deleteItem(int id) {
return Observable.fromFuture(
DioUtil.getInstance().getDio().delete("images/${id}/"))
.flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(compute(parseDeleteResult, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<TotalImageBean> getTotalImage() {
return HomeApiImpl().getTotalImages();
}
// Observable<>
}
ImageAiBean paseImageAi(String value) {
return ImageAiBean.fromJson(json.decode(value));
}
DeleteResultBean parseDeleteResult(String value) {
return DeleteResultBean.fromJson(json.decode(value));
}
PutImageDataBean parsePutImageBean(String value){
return PutImageDataBean.fromJson(json.decode(value));
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/Annotations/anno/Get.dart';
import 'package:example_flutter/Annotations/anno/Post.dart';
import 'package:example_flutter/Annotations/anno/Query.dart';
import 'package:example_flutter/Annotations/anno/ServiceCenter.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/AllTabBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/TotalImageBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/UploadResultBean.dart';
@ServiceCenter()
abstract class HomeApi{
@Get("anno-meta/")
AllTabBean getAllTab();
@Post("image-upload/")
UploadResultBean upload(Map upload);
@Get("imagelist/")
ImageResultBean getImageList(@Query("page")int page,@Query("pageSize")int pageSize);
@Get("countimage/")
TotalImageBean getTotalImages();
}
\ No newline at end of file
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// ServiceGenerator
// **************************************************************************
import 'dart:convert';
import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/AllTabBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/UploadResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/ImageResultBean.dart';
import 'package:example_flutter/HomeModel/service/remote/entity/TotalImageBean.dart';
import 'package:example_flutter/commonModel/net/DioUtil.dart';
class HomeApiImpl {
factory HomeApiImpl() => _sharedInstance();
static HomeApiImpl _instance;
HomeApiImpl._() {}
static HomeApiImpl _sharedInstance() {
if (_instance == null) {
_instance = HomeApiImpl._();
}
return _instance;
}
Observable<AllTabBean> getAllTab() {
return Observable.fromFuture(DioUtil().get('anno-meta/')).flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(compute(paseAllTabBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<UploadResultBean> upload() {
return Observable.fromFuture(DioUtil().post('image-upload/'))
.flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(
compute(paseUploadResultBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<ImageResultBean> getImageList(int page, int pageSize) {
return Observable.fromFuture(DioUtil().get('imagelist/',
data: {'page': page, 'pageSize': pageSize})).flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(
compute(paseImageResultBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<TotalImageBean> getTotalImages() {
return Observable.fromFuture(DioUtil().get('countimage/')).flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(
compute(paseTotalImageBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
}
AllTabBean paseAllTabBean(String value) {
return AllTabBean.fromJson(json.decode(value));
}
UploadResultBean paseUploadResultBean(String value) {
return UploadResultBean.fromJson(json.decode(value));
}
ImageResultBean paseImageResultBean(String value) {
return ImageResultBean.fromJson(json.decode(value));
}
TotalImageBean paseTotalImageBean(String value) {
return TotalImageBean.fromJson(json.decode(value));
}
class AllTabBean {
LeftEye leftEye;
RigthEye rigthEye;
Eyebag eyebag;
EyestyleLeft eyestyleLeft;
EyestyleRight eyestyleRight;
Nose nose;
Mouth mouth;
Lip lip;
Wrink wrink;
Checkbone checkbone;
Eyebow eyebow;
Chin chin;
Eyebrowstyle eyebrowstyle;
Eyebrowthickness eyebrowthickness;
Eyebrowsconcentration eyebrowsconcentration;
EyebrowsconcentrationF eyebrowsconcentrationF;
Eyespacing eyespacing;
Brow brow;
Lipscurved lipscurved;
Speciallip speciallip;
Face face;
AllTabBean(
{this.leftEye,
this.rigthEye,
this.eyebag,
this.eyestyleLeft,
this.eyestyleRight,
this.nose,
this.mouth,
this.lip,
this.wrink,
this.checkbone,
this.eyebow,
this.chin,
this.eyebrowstyle,
this.eyebrowthickness,
this.eyebrowsconcentration,
this.eyebrowsconcentrationF,
this.eyespacing,
this.brow,
this.lipscurved,
this.speciallip,
this.face});
AllTabBean.fromJson(Map<String, dynamic> json) {
leftEye = json['left_eye'] != null
? new LeftEye.fromJson(json['left_eye'])
: null;
rigthEye = json['rigth_eye'] != null
? new RigthEye.fromJson(json['rigth_eye'])
: null;
eyebag =
json['eyebag'] != null ? new Eyebag.fromJson(json['eyebag']) : null;
eyestyleLeft = json['eyestyle_left'] != null
? new EyestyleLeft.fromJson(json['eyestyle_left'])
: null;
eyestyleRight = json['eyestyle_right'] != null
? new EyestyleRight.fromJson(json['eyestyle_right'])
: null;
nose = json['nose'] != null ? new Nose.fromJson(json['nose']) : null;
mouth = json['mouth'] != null ? new Mouth.fromJson(json['mouth']) : null;
lip = json['lip'] != null ? new Lip.fromJson(json['lip']) : null;
wrink = json['wrink'] != null ? new Wrink.fromJson(json['wrink']) : null;
checkbone = json['checkbone'] != null
? new Checkbone.fromJson(json['checkbone'])
: null;
eyebow =
json['eyebow'] != null ? new Eyebow.fromJson(json['eyebow']) : null;
chin = json['chin'] != null ? new Chin.fromJson(json['chin']) : null;
eyebrowstyle = json['Eyebrowstyle'] != null
? new Eyebrowstyle.fromJson(json['Eyebrowstyle'])
: null;
eyebrowthickness = json['eyebrowthickness'] != null
? new Eyebrowthickness.fromJson(json['eyebrowthickness'])
: null;
eyebrowsconcentration = json['Eyebrowsconcentration'] != null
? new Eyebrowsconcentration.fromJson(json['Eyebrowsconcentration'])
: null;
eyebrowsconcentrationF = json['Eyebrowsconcentration_f'] != null
? new EyebrowsconcentrationF.fromJson(json['Eyebrowsconcentration_f'])
: null;
eyespacing = json['eyespacing'] != null
? new Eyespacing.fromJson(json['eyespacing'])
: null;
brow = json['brow'] != null ? new Brow.fromJson(json['brow']) : null;
lipscurved = json['lipscurved'] != null
? new Lipscurved.fromJson(json['lipscurved'])
: null;
speciallip = json['Speciallip'] != null
? new Speciallip.fromJson(json['Speciallip'])
: null;
face = json['face'] != null ? new Face.fromJson(json['face']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.leftEye != null) {
data['left_eye'] = this.leftEye.toJson();
}
if (this.rigthEye != null) {
data['rigth_eye'] = this.rigthEye.toJson();
}
if (this.eyebag != null) {
data['eyebag'] = this.eyebag.toJson();
}
if (this.eyestyleLeft != null) {
data['eyestyle_left'] = this.eyestyleLeft.toJson();
}
if (this.eyestyleRight != null) {
data['eyestyle_right'] = this.eyestyleRight.toJson();
}
if (this.nose != null) {
data['nose'] = this.nose.toJson();
}
if (this.mouth != null) {
data['mouth'] = this.mouth.toJson();
}
if (this.lip != null) {
data['lip'] = this.lip.toJson();
}
if (this.wrink != null) {
data['wrink'] = this.wrink.toJson();
}
if (this.checkbone != null) {
data['checkbone'] = this.checkbone.toJson();
}
if (this.eyebow != null) {
data['eyebow'] = this.eyebow.toJson();
}
if (this.chin != null) {
data['chin'] = this.chin.toJson();
}
if (this.eyebrowstyle != null) {
data['Eyebrowstyle'] = this.eyebrowstyle.toJson();
}
if (this.eyebrowthickness != null) {
data['eyebrowthickness'] = this.eyebrowthickness.toJson();
}
if (this.eyebrowsconcentration != null) {
data['Eyebrowsconcentration'] = this.eyebrowsconcentration.toJson();
}
if (this.eyebrowsconcentrationF != null) {
data['Eyebrowsconcentration_f'] = this.eyebrowsconcentrationF.toJson();
}
if (this.eyespacing != null) {
data['eyespacing'] = this.eyespacing.toJson();
}
if (this.brow != null) {
data['brow'] = this.brow.toJson();
}
if (this.lipscurved != null) {
data['lipscurved'] = this.lipscurved.toJson();
}
if (this.speciallip != null) {
data['Speciallip'] = this.speciallip.toJson();
}
if (this.face != null) {
data['face'] = this.face.toJson();
}
return data;
}
}
class LeftEye {
String name;
LeftEyeData leftEyeData;
LeftEye({this.name, this.leftEyeData});
LeftEye.fromJson(Map<String, dynamic> json) {
name = json['name'];
leftEyeData = json['leftEyeData'] != null
? new LeftEyeData.fromJson(json['leftEyeData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.leftEyeData != null) {
data['leftEyeData'] = this.leftEyeData.toJson();
}
return data;
}
}
class LeftEyeData {
String seye;
String eyes;
String doubleIn;
LeftEyeData({this.seye, this.eyes, this.doubleIn});
LeftEyeData.fromJson(Map<String, dynamic> json) {
seye = json['seye'];
eyes = json['eyes'];
doubleIn = json['doubleIn'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['seye'] = this.seye;
data['eyes'] = this.eyes;
data['doubleIn'] = this.doubleIn;
return data;
}
}
class RigthEye {
String name;
RigthEyeData rigthEyeData;
RigthEye({this.name, this.rigthEyeData});
RigthEye.fromJson(Map<String, dynamic> json) {
name = json['name'];
rigthEyeData = json['rigthEyeData'] != null
? new RigthEyeData.fromJson(json['rigthEyeData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.rigthEyeData != null) {
data['rigthEyeData'] = this.rigthEyeData.toJson();
}
return data;
}
}
class RigthEyeData {
String seye;
String eyes;
String doubleIn;
RigthEyeData({this.seye, this.eyes, this.doubleIn});
RigthEyeData.fromJson(Map<String, dynamic> json) {
seye = json['seye'];
eyes = json['eyes'];
doubleIn = json['doubleIn'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['seye'] = this.seye;
data['eyes'] = this.eyes;
data['doubleIn'] = this.doubleIn;
return data;
}
}
class Eyebag {
String name;
EyebagData eyebagData;
Eyebag({this.name, this.eyebagData});
Eyebag.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyebagData = json['eyebagData'] != null
? new EyebagData.fromJson(json['eyebagData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyebagData != null) {
data['eyebagData'] = this.eyebagData.toJson();
}
return data;
}
}
class EyebagData {
String yes;
String no;
EyebagData({this.yes, this.no});
EyebagData.fromJson(Map<String, dynamic> json) {
yes = json['yes'];
no = json['no'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['yes'] = this.yes;
data['no'] = this.no;
return data;
}
}
class EyestyleLeft {
String name;
EyestyleLeftData eyestyleLeftData;
EyestyleLeft({this.name, this.eyestyleLeftData});
EyestyleLeft.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyestyleLeftData = json['eyestyleLeftData'] != null
? new EyestyleLeftData.fromJson(json['eyestyleLeftData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyestyleLeftData != null) {
data['eyestyleLeftData'] = this.eyestyleLeftData.toJson();
}
return data;
}
}
class EyestyleLeftData {
String almonEyes;
String peach;
String fineCheng;
String deerEye;
String dogEye;
EyestyleLeftData(
{this.almonEyes, this.peach, this.fineCheng, this.deerEye, this.dogEye});
EyestyleLeftData.fromJson(Map<String, dynamic> json) {
almonEyes = json['Almon_eyes'];
peach = json['Peach'];
fineCheng = json['Fine_cheng'];
deerEye = json['deer_eye'];
dogEye = json['dog_eye'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Almon_eyes'] = this.almonEyes;
data['Peach'] = this.peach;
data['Fine_cheng'] = this.fineCheng;
data['deer_eye'] = this.deerEye;
data['dog_eye'] = this.dogEye;
return data;
}
}
class EyestyleRight {
String name;
EyestyleRightData eyestyleRightData;
EyestyleRight({this.name, this.eyestyleRightData});
EyestyleRight.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyestyleRightData = json['eyestyleRightData'] != null
? new EyestyleRightData.fromJson(json['eyestyleRightData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyestyleRightData != null) {
data['eyestyleRightData'] = this.eyestyleRightData.toJson();
}
return data;
}
}
class EyestyleRightData {
String almonEyes;
String peach;
String fineCheng;
String deerEye;
String dogEye;
EyestyleRightData(
{this.almonEyes, this.peach, this.fineCheng, this.deerEye, this.dogEye});
EyestyleRightData.fromJson(Map<String, dynamic> json) {
almonEyes = json['Almon_eyes'];
peach = json['Peach'];
fineCheng = json['Fine_cheng'];
deerEye = json['deer_eye'];
dogEye = json['dog_eye'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Almon_eyes'] = this.almonEyes;
data['Peach'] = this.peach;
data['Fine_cheng'] = this.fineCheng;
data['deer_eye'] = this.deerEye;
data['dog_eye'] = this.dogEye;
return data;
}
}
class Nose {
String name;
NoseData noseData;
Nose({this.name, this.noseData});
Nose.fromJson(Map<String, dynamic> json) {
name = json['name'];
noseData = json['noseData'] != null
? new NoseData.fromJson(json['noseData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.noseData != null) {
data['noseData'] = this.noseData.toJson();
}
return data;
}
}
class NoseData {
String narrowNose;
String standardNose;
String widepNose;
String wideNose;
NoseData({this.narrowNose, this.standardNose, this.widepNose, this.wideNose});
NoseData.fromJson(Map<String, dynamic> json) {
narrowNose = json['Narrow_nose'];
standardNose = json['Standard_nose'];
widepNose = json['widep_nose'];
wideNose = json['wide_nose'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Narrow_nose'] = this.narrowNose;
data['Standard_nose'] = this.standardNose;
data['widep_nose'] = this.widepNose;
data['wide_nose'] = this.wideNose;
return data;
}
}
class Mouth {
String name;
MouthData mouthData;
Mouth({this.name, this.mouthData});
Mouth.fromJson(Map<String, dynamic> json) {
name = json['name'];
mouthData = json['mouthData'] != null
? new MouthData.fromJson(json['mouthData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.mouthData != null) {
data['mouthData'] = this.mouthData.toJson();
}
return data;
}
}
class MouthData {
String standard;
String thick;
String thin;
MouthData({this.standard, this.thick, this.thin});
MouthData.fromJson(Map<String, dynamic> json) {
standard = json['Standard'];
thick = json['Thick'];
thin = json['thin'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Standard'] = this.standard;
data['Thick'] = this.thick;
data['thin'] = this.thin;
return data;
}
}
class Lip {
String name;
LipData lipData;
Lip({this.name, this.lipData});
Lip.fromJson(Map<String, dynamic> json) {
name = json['name'];
lipData =
json['lipData'] != null ? new LipData.fromJson(json['lipData']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.lipData != null) {
data['lipData'] = this.lipData.toJson();
}
return data;
}
}
class LipData {
String yes;
String no;
String notObvious;
LipData({this.yes, this.no, this.notObvious});
LipData.fromJson(Map<String, dynamic> json) {
yes = json['yes'];
no = json['no'];
notObvious = json['not_obvious'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['yes'] = this.yes;
data['no'] = this.no;
data['not_obvious'] = this.notObvious;
return data;
}
}
class Wrink {
String name;
WrinkData wrinkData;
Wrink({this.name, this.wrinkData});
Wrink.fromJson(Map<String, dynamic> json) {
name = json['name'];
wrinkData = json['wrinkData'] != null
? new WrinkData.fromJson(json['wrinkData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.wrinkData != null) {
data['wrinkData'] = this.wrinkData.toJson();
}
return data;
}
}
class WrinkData {
String yes;
String no;
WrinkData({this.yes, this.no});
WrinkData.fromJson(Map<String, dynamic> json) {
yes = json['yes'];
no = json['no'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['yes'] = this.yes;
data['no'] = this.no;
return data;
}
}
class Checkbone {
String name;
CheckboneData checkboneData;
Checkbone({this.name, this.checkboneData});
Checkbone.fromJson(Map<String, dynamic> json) {
name = json['name'];
checkboneData = json['checkboneData'] != null
? new CheckboneData.fromJson(json['checkboneData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.checkboneData != null) {
data['checkboneData'] = this.checkboneData.toJson();
}
return data;
}
}
class CheckboneData {
String high;
String flat;
CheckboneData({this.high, this.flat});
CheckboneData.fromJson(Map<String, dynamic> json) {
high = json['high'];
flat = json['flat'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['high'] = this.high;
data['flat'] = this.flat;
return data;
}
}
class Eyebow {
String name;
EyebowData eyebowData;
Eyebow({this.name, this.eyebowData});
Eyebow.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyebowData = json['eyebowData'] != null
? new EyebowData.fromJson(json['eyebowData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyebowData != null) {
data['eyebowData'] = this.eyebowData.toJson();
}
return data;
}
}
class EyebowData {
String on;
String standard;
String one;
String sagging;
EyebowData({this.on, this.standard, this.one, this.sagging});
EyebowData.fromJson(Map<String, dynamic> json) {
on = json['On'];
standard = json['Standard'];
one = json['one'];
sagging = json['sagging'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['On'] = this.on;
data['Standard'] = this.standard;
data['one'] = this.one;
data['sagging'] = this.sagging;
return data;
}
}
class Chin {
String name;
ChinData chinData;
Chin({this.name, this.chinData});
Chin.fromJson(Map<String, dynamic> json) {
name = json['name'];
chinData = json['chinData'] != null
? new ChinData.fromJson(json['chinData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.chinData != null) {
data['chinData'] = this.chinData.toJson();
}
return data;
}
}
class ChinData {
String tip;
String party;
String round;
String ass;
ChinData({this.tip, this.party, this.round, this.ass});
ChinData.fromJson(Map<String, dynamic> json) {
tip = json['tip'];
party = json['party'];
round = json['round'];
ass = json['Ass'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['tip'] = this.tip;
data['party'] = this.party;
data['round'] = this.round;
data['Ass'] = this.ass;
return data;
}
}
class Eyebrowstyle {
String name;
EyebrowstyleData eyebrowstyleData;
Eyebrowstyle({this.name, this.eyebrowstyleData});
Eyebrowstyle.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyebrowstyleData = json['eyebrowstyleData'] != null
? new EyebrowstyleData.fromJson(json['eyebrowstyleData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyebrowstyleData != null) {
data['eyebrowstyleData'] = this.eyebrowstyleData.toJson();
}
return data;
}
}
class EyebrowstyleData {
String willow;
String wild;
EyebrowstyleData({this.willow, this.wild});
EyebrowstyleData.fromJson(Map<String, dynamic> json) {
willow = json['willow'];
wild = json['wild'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['willow'] = this.willow;
data['wild'] = this.wild;
return data;
}
}
class Eyebrowthickness {
String name;
EyebrowthicknessData eyebrowthicknessData;
Eyebrowthickness({this.name, this.eyebrowthicknessData});
Eyebrowthickness.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyebrowthicknessData = json['eyebrowthicknessData'] != null
? new EyebrowthicknessData.fromJson(json['eyebrowthicknessData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyebrowthicknessData != null) {
data['eyebrowthicknessData'] = this.eyebrowthicknessData.toJson();
}
return data;
}
}
class EyebrowthicknessData {
String cumei;
String biaozhunmei;
String xiemei;
EyebrowthicknessData({this.cumei, this.biaozhunmei, this.xiemei});
EyebrowthicknessData.fromJson(Map<String, dynamic> json) {
cumei = json['cumei'];
biaozhunmei = json['biaozhunmei'];
xiemei = json['xiemei'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['cumei'] = this.cumei;
data['biaozhunmei'] = this.biaozhunmei;
data['xiemei'] = this.xiemei;
return data;
}
}
class Eyebrowsconcentration {
String name;
EyebrowsconcentrationData eyebrowsconcentrationData;
Eyebrowsconcentration({this.name, this.eyebrowsconcentrationData});
Eyebrowsconcentration.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyebrowsconcentrationData = json['eyebrowsconcentrationData'] != null
? new EyebrowsconcentrationData.fromJson(
json['eyebrowsconcentrationData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyebrowsconcentrationData != null) {
data['eyebrowsconcentrationData'] =
this.eyebrowsconcentrationData.toJson();
}
return data;
}
}
class EyebrowsconcentrationData {
String piandan;
String feichandan;
String nongduzhenghao;
EyebrowsconcentrationData(
{this.piandan, this.feichandan, this.nongduzhenghao});
EyebrowsconcentrationData.fromJson(Map<String, dynamic> json) {
piandan = json['piandan'];
feichandan = json['feichandan'];
nongduzhenghao = json['nongduzhenghao'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['piandan'] = this.piandan;
data['feichandan'] = this.feichandan;
data['nongduzhenghao'] = this.nongduzhenghao;
return data;
}
}
class EyebrowsconcentrationF {
String name;
EyebrowsconcentrationFData eyebrowsconcentrationFData;
EyebrowsconcentrationF({this.name, this.eyebrowsconcentrationFData});
EyebrowsconcentrationF.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyebrowsconcentrationFData = json['eyebrowsconcentration_fData'] != null
? new EyebrowsconcentrationFData.fromJson(
json['eyebrowsconcentration_fData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyebrowsconcentrationFData != null) {
data['eyebrowsconcentration_fData'] =
this.eyebrowsconcentrationFData.toJson();
}
return data;
}
}
class EyebrowsconcentrationFData {
String fenbujunyun;
String qianshuhoumi;
String qianmuhoushu;
String lianjunyun;
EyebrowsconcentrationFData(
{this.fenbujunyun,
this.qianshuhoumi,
this.qianmuhoushu,
this.lianjunyun});
EyebrowsconcentrationFData.fromJson(Map<String, dynamic> json) {
fenbujunyun = json['fenbujunyun'];
qianshuhoumi = json['qianshuhoumi'];
qianmuhoushu = json['qianmuhoushu'];
lianjunyun = json['lianjunyun'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['fenbujunyun'] = this.fenbujunyun;
data['qianshuhoumi'] = this.qianshuhoumi;
data['qianmuhoushu'] = this.qianmuhoushu;
data['lianjunyun'] = this.lianjunyun;
return data;
}
}
class Eyespacing {
String name;
EyespacingData eyespacingData;
Eyespacing({this.name, this.eyespacingData});
Eyespacing.fromJson(Map<String, dynamic> json) {
name = json['name'];
eyespacingData = json['eyespacingData'] != null
? new EyespacingData.fromJson(json['eyespacingData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.eyespacingData != null) {
data['eyespacingData'] = this.eyespacingData.toJson();
}
return data;
}
}
class EyespacingData {
String wide;
String narrow;
String appropriate;
EyespacingData({this.wide, this.narrow, this.appropriate});
EyespacingData.fromJson(Map<String, dynamic> json) {
wide = json['wide'];
narrow = json['narrow'];
appropriate = json['appropriate'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['wide'] = this.wide;
data['narrow'] = this.narrow;
data['appropriate'] = this.appropriate;
return data;
}
}
class Brow {
String name;
BrowData browData;
Brow({this.name, this.browData});
Brow.fromJson(Map<String, dynamic> json) {
name = json['name'];
browData = json['browData'] != null
? new BrowData.fromJson(json['browData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.browData != null) {
data['browData'] = this.browData.toJson();
}
return data;
}
}
class BrowData {
String wide;
String narrow;
String appropriate;
BrowData({this.wide, this.narrow, this.appropriate});
BrowData.fromJson(Map<String, dynamic> json) {
wide = json['wide'];
narrow = json['narrow'];
appropriate = json['appropriate'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['wide'] = this.wide;
data['narrow'] = this.narrow;
data['appropriate'] = this.appropriate;
return data;
}
}
class Lipscurved {
String name;
LipscurvedData lipscurvedData;
Lipscurved({this.name, this.lipscurvedData});
Lipscurved.fromJson(Map<String, dynamic> json) {
name = json['name'];
lipscurvedData = json['lipscurvedData'] != null
? new LipscurvedData.fromJson(json['lipscurvedData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.lipscurvedData != null) {
data['lipscurvedData'] = this.lipscurvedData.toJson();
}
return data;
}
}
class LipscurvedData {
String smile;
String moderate;
String attitude;
LipscurvedData({this.smile, this.moderate, this.attitude});
LipscurvedData.fromJson(Map<String, dynamic> json) {
smile = json['smile'];
moderate = json['moderate'];
attitude = json['attitude'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['smile'] = this.smile;
data['moderate'] = this.moderate;
data['attitude'] = this.attitude;
return data;
}
}
class Speciallip {
String name;
SpeciallipData speciallipData;
Speciallip({this.name, this.speciallipData});
Speciallip.fromJson(Map<String, dynamic> json) {
name = json['name'];
speciallipData = json['speciallipData'] != null
? new SpeciallipData.fromJson(json['speciallipData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.speciallipData != null) {
data['speciallipData'] = this.speciallipData.toJson();
}
return data;
}
}
class SpeciallipData {
String cherryLip;
String supermodelLip;
SpeciallipData({this.cherryLip, this.supermodelLip});
SpeciallipData.fromJson(Map<String, dynamic> json) {
cherryLip = json['Cherry_lip'];
supermodelLip = json['Supermodel_lip'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['Cherry_lip'] = this.cherryLip;
data['Supermodel_lip'] = this.supermodelLip;
return data;
}
}
class Face {
String name;
FaceData faceData;
Face({this.name, this.faceData});
Face.fromJson(Map<String, dynamic> json) {
name = json['name'];
faceData = json['faceData'] != null
? new FaceData.fromJson(json['faceData'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
if (this.faceData != null) {
data['faceData'] = this.faceData.toJson();
}
return data;
}
}
class FaceData {
String babyFace;
String guazilian;
String fanglian;
String edanlian;
String changxinglian;
String lixinglian;
String jingzhuan;
FaceData(
{this.babyFace,
this.guazilian,
this.fanglian,
this.edanlian,
this.changxinglian,
this.lixinglian,
this.jingzhuan});
FaceData.fromJson(Map<String, dynamic> json) {
babyFace = json['baby_face'];
guazilian = json['guazilian'];
fanglian = json['fanglian'];
edanlian = json['edanlian'];
changxinglian = json['changxinglian'];
lixinglian = json['lixinglian'];
jingzhuan = json['jingzhuan'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['baby_face'] = this.babyFace;
data['guazilian'] = this.guazilian;
data['fanglian'] = this.fanglian;
data['edanlian'] = this.edanlian;
data['changxinglian'] = this.changxinglian;
data['lixinglian'] = this.lixinglian;
data['jingzhuan'] = this.jingzhuan;
return data;
}
}
/*
* @author lsy
* @date 2019-11-18
**/
class DeleteResultBean {
String result;
DeleteResultBean({this.result});
DeleteResultBean.fromJson(Map<String, dynamic> json) {
result = json['result'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['result'] = this.result;
return data;
}
}
/*
* @author lsy
* @date 2019-11-15
**/
class ImageAiBean {
String url;
Anno anno;
ImageAiBean({this.url, this.anno});
ImageAiBean.fromJson(Map<String, dynamic> json) {
url = json['url'];
anno = json['anno'] != null ? new Anno.fromJson(json['anno']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['url'] = this.url;
if (this.anno != null) {
data['anno'] = this.anno.toJson();
}
return data;
}
}
class Anno {
String browShape;
String browsStyle;
String browsSpacing;
String browsThickness;
String dense;
String browDensity;
String face;
String pouch;
String eyelidLeft;
String eyelidRight;
String eyeShapeLeft;
String eyeShapeRight;
String eyeDistance;
String cheekbone;
String chinShape;
String wrink;
String nose;
String lipThickness;
String lipRadian;
String lipShape;
String lipPeak;
Anno(
{this.browShape,
this.browsStyle,
this.browsSpacing,
this.browsThickness,
this.dense,
this.browDensity,
this.face,
this.pouch,
this.eyelidLeft,
this.eyelidRight,
this.eyeShapeLeft,
this.eyeShapeRight,
this.eyeDistance,
this.cheekbone,
this.chinShape,
this.wrink,
this.nose,
this.lipThickness,
this.lipRadian,
this.lipShape,
this.lipPeak});
Anno.fromJson(Map<String, dynamic> json) {
browShape = json['brow_shape'];
browsStyle = json['brows_style'];
browsSpacing = json['brows_spacing'];
browsThickness = json['brows_thickness'];
dense = json['Dense'];
browDensity = json['brow_density'];
face = json['face'];
pouch = json['pouch'];
eyelidLeft = json['eyelid_left'];
eyelidRight = json['eyelid_right'];
eyeShapeLeft = json['eye_shape_left'];
eyeShapeRight = json['eye_shape_right'];
eyeDistance = json['eye_distance'];
cheekbone = json['cheekbone'];
chinShape = json['chin_shape'];
wrink = json['wrink'];
nose = json['nose'];
lipThickness = json['lip_thickness'];
lipRadian = json['lip_radian'];
lipShape = json['lip_shape'];
lipPeak = json['lip_peak'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['brow_shape'] = this.browShape;
data['brows_style'] = this.browsStyle;
data['brows_spacing'] = this.browsSpacing;
data['brows_thickness'] = this.browsThickness;
data['Dense'] = this.dense;
data['brow_density'] = this.browDensity;
data['face'] = this.face;
data['pouch'] = this.pouch;
data['eyelid_left'] = this.eyelidLeft;
data['eyelid_right'] = this.eyelidRight;
data['eye_shape_left'] = this.eyeShapeLeft;
data['eye_shape_right'] = this.eyeShapeRight;
data['eye_distance'] = this.eyeDistance;
data['cheekbone'] = this.cheekbone;
data['chin_shape'] = this.chinShape;
data['wrink'] = this.wrink;
data['nose'] = this.nose;
data['lip_thickness'] = this.lipThickness;
data['lip_radian'] = this.lipRadian;
data['lip_shape'] = this.lipShape;
data['lip_peak'] = this.lipPeak;
return data;
}
}
/*
* @author lsy
* @date 2019-11-14
**/
class ImageResultBean {
List<PicList> picList;
ImageResultBean({this.picList});
ImageResultBean.fromJson(Map<String, dynamic> json) {
if (json['pic_list'] != null) {
picList = new List<PicList>();
json['pic_list'].forEach((v) {
picList.add(new PicList.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.picList != null) {
data['pic_list'] = this.picList.map((v) => v.toJson()).toList();
}
return data;
}
}
class PicList {
String picurl;
int id;
String status;
PicList({this.picurl, this.id, this.status});
PicList.fromJson(Map<String, dynamic> json) {
picurl = json['picurl'];
id = json['id'];
status = json['status'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['picurl'] = this.picurl;
data['id'] = this.id;
data['status'] = this.status;
return data;
}
}
/*
* @author lsy
* @date 2019-11-18
**/
class PutImageDataBean {
Result result;
PutImageDataBean({this.result});
PutImageDataBean.fromJson(Map<String, dynamic> json) {
result =
json['result'] != null ? new Result.fromJson(json['result']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.result != null) {
data['result'] = this.result.toJson();
}
return data;
}
}
class Result {
String url;
FaceDetails faceDetails;
Result({this.url, this.faceDetails});
Result.fromJson(Map<String, dynamic> json) {
url = json['url'];
faceDetails = json['face_details'] != null
? new FaceDetails.fromJson(json['face_details'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['url'] = this.url;
if (this.faceDetails != null) {
data['face_details'] = this.faceDetails.toJson();
}
return data;
}
}
class FaceDetails {
String eyelidRight;
String eyelidLeft;
String nose;
String wrink;
String lipThickness;
String lipPeak;
String pouch;
String cheekbone;
String browShape;
String browDensity;
String chinShape;
String lipShape;
String lipRadian;
String eyeShapeRight;
String eyeShapeLeft;
String eyebrowstyle;
String eyebrowthickness;
String eyebrowsconcentration;
String brow;
String eyeDistance;
String face;
FaceDetails(
{this.eyelidRight,
this.eyelidLeft,
this.nose,
this.wrink,
this.lipThickness,
this.lipPeak,
this.pouch,
this.cheekbone,
this.browShape,
this.browDensity,
this.chinShape,
this.lipShape,
this.lipRadian,
this.eyeShapeRight,
this.eyeShapeLeft,
this.eyebrowstyle,
this.eyebrowthickness,
this.eyebrowsconcentration,
this.brow,
this.eyeDistance,
this.face});
FaceDetails.fromJson(Map<String, dynamic> json) {
eyelidRight = json['eyelid_right'];
eyelidLeft = json['eyelid_left'];
nose = json['nose'];
wrink = json['wrink'];
lipThickness = json['lip_thickness'];
lipPeak = json['lip_peak'];
pouch = json['pouch'];
cheekbone = json['cheekbone'];
browShape = json['brow_shape'];
browDensity = json['brow_density'];
chinShape = json['chin_shape'];
lipShape = json['lip_shape'];
lipRadian = json['lip_radian'];
eyeShapeRight = json['eye_shape_right'];
eyeShapeLeft = json['eye_shape_left'];
eyebrowstyle = json['Eyebrowstyle'];
eyebrowthickness = json['eyebrowthickness'];
eyebrowsconcentration = json['Eyebrowsconcentration'];
brow = json['brow'];
eyeDistance = json['eye_distance'];
face = json['face'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['eyelid_right'] = this.eyelidRight;
data['eyelid_left'] = this.eyelidLeft;
data['nose'] = this.nose;
data['wrink'] = this.wrink;
data['lip_thickness'] = this.lipThickness;
data['lip_peak'] = this.lipPeak;
data['pouch'] = this.pouch;
data['cheekbone'] = this.cheekbone;
data['brow_shape'] = this.browShape;
data['brow_density'] = this.browDensity;
data['chin_shape'] = this.chinShape;
data['lip_shape'] = this.lipShape;
data['lip_radian'] = this.lipRadian;
data['eye_shape_right'] = this.eyeShapeRight;
data['eye_shape_left'] = this.eyeShapeLeft;
data['Eyebrowstyle'] = this.eyebrowstyle;
data['eyebrowthickness'] = this.eyebrowthickness;
data['Eyebrowsconcentration'] = this.eyebrowsconcentration;
data['brow'] = this.brow;
data['eye_distance'] = this.eyeDistance;
data['face'] = this.face;
return data;
}
}
/*
* @author lsy
* @date 2019-11-18
**/
class TotalImageBean {
int totalTag;
int total;
TotalImageBean({this.totalTag, this.total});
TotalImageBean.fromJson(Map<String, dynamic> json) {
totalTag = json['total_tag'];
total = json['total'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['total_tag'] = this.totalTag;
data['total'] = this.total;
return data;
}
}
/*
* @author lsy
* @date 2019-11-07
**/
class UploadResultBean {
String url;
int id;
UploadResultBean({this.url, this.id});
UploadResultBean.fromJson(Map<String, dynamic> json) {
url = json['url'];
id = json['id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['url'] = this.url;
data['id'] = this.id;
return data;
}
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/Annotations/RouterBaser.dart';
import 'package:example_flutter/Annotations/anno/Router.dart';
import 'package:example_flutter/UserModel/UserRouterImpl.dart';
import 'package:flutter/cupertino.dart';
@Router("UserRouter",UserRouterImpl,true)
abstract class UserRouter extends RouterBaser{
Widget getLoginPage();
}
\ No newline at end of file
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/UserModel/UserRouter.dart';
import 'package:example_flutter/UserModel/page/login/LoginPage.dart';
import 'package:flutter/src/widgets/framework.dart';
class UserRouterImpl implements UserRouter {
@override
Widget getLoginPage() {
return LoginPage();
}
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'dart:io';
import 'package:example_flutter/Annotations/RouterCenterRestore.mark.dart';
import 'package:example_flutter/UserModel/service/Resp.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/cache/CacheManager.dart';
import 'package:example_flutter/commonModel/toast/toast.dart';
import 'package:example_flutter/res/anim/Anim.dart';
import 'package:flutter/cupertino.dart';
class LoginModel extends BaseModel {
resign(BuildContext context, String text, String text2) {
Resp.getInstance().resign(text, text2).listen((value) {
Navigator.pop(context);
if (value != null && value.username != null) {
login(context, text, text2);
} else {
Toast.show(context, "网络接口错误 ==> resign");
}
}).onError((error) {
Navigator.pop(context);
Toast.show(context, "该用户名已经被注册");
print(error.toString());
});
}
login(BuildContext context, String text, String text2) async {
Resp.getInstance().login(text, text2).listen((value) {
Navigator.pop(context);
if (value != null && value.token != null) {
CacheManager.getInstance().get(MEMORY_CACHE).save("token", value.token);
CacheManager.getInstance().get(MEMORY_CACHE).save("userName", text);
CacheManager.getInstance().get(MEMORY_CACHE).save("userWorld", text2);
Toast.show(context, "登入成功");
Navigator.push(context, CustomRoute(
RouterCenterImpl().findHomeRouter()?.getHomePage()
));
} else {
Toast.show(context, "接口请求错误 ==> login");
}
}).onError((error) {
Navigator.pop(context);
Toast.show(context, error.toString());
print(error.toString());
});
}
@override
void dispose() {}
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'dart:ui';
import 'package:example_flutter/UserModel/page/login/LoginModel.dart';
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:example_flutter/commonModel/base/BaseComponent.dart';
import 'package:example_flutter/commonModel/picker/base/BasePickerComponent.dart';
import 'package:example_flutter/commonModel/toast/toast.dart';
import 'package:example_flutter/res/GMRes.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class LoginPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => LoginState();
}
class LoginState extends State<LoginPage> {
LoginModel _model;
TextEditingController _nameCon;
TextEditingController _wordCon;
LoginState() {
_model = LoginModel();
}
@override
void initState() {
super.initState();
_nameCon = TextEditingController();
_wordCon = TextEditingController();
}
@override
void dispose() {
super.dispose();
_nameCon.dispose();
_wordCon.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints.expand(),
child: BackdropFilter(
filter: new ImageFilter.blur(sigmaX: 100, sigmaY: 100),
child: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573655792197&di=f9469fa087a082aedfd22514c1549e1f&imgtype=0&src=http%3A%2F%2Fimg8.zol.com.cn%2Fbbs%2Fupload%2F19571%2F19570481.jpg",
fit: BoxFit.cover,
)),
),
main()
],
));
}
main() {
return Container(
width: double.maxFinite,
height: double.maxFinite,
alignment: Alignment.center,
child: Container(
width: 600,
height: 350,
color: Colors.black38,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Container(),
),
baseText("更美AI标注平台", 30, ALColors.ColorF8F8F8),
Container(
margin: EdgeInsets.only(
top: ScreenUtil.instance.setHeight(20),
left: ScreenUtil.instance.setWidth(100),
right: ScreenUtil.instance.setWidth(100)),
child: TextField(
controller: _nameCon,
keyboardType: TextInputType.number,
cursorColor: Colors.white,
decoration: InputDecoration(
hoverColor: Colors.white,
fillColor: Colors.white,
focusColor: Colors.white,
contentPadding: EdgeInsets.all(10.0),
icon: Icon(
Icons.person,
size: ScreenUtil.instance.setSp(30),
),
labelText: '请输入你的用户名',
// helperText: '请输入你的用户名',
labelStyle: TextStyle(color: Colors.white),
helperStyle: TextStyle(color: Colors.white)),
autofocus: false,
),
),
Container(
margin: EdgeInsets.only(
top: ScreenUtil.instance.setHeight(20),
left: ScreenUtil.instance.setWidth(100),
right: ScreenUtil.instance.setWidth(100)),
child: TextField(
controller: _wordCon,
keyboardType: TextInputType.number,
cursorColor: Colors.white,
decoration: InputDecoration(
hoverColor: Colors.white,
fillColor: Colors.white,
focusColor: Colors.white,
contentPadding: EdgeInsets.all(10.0),
icon: Icon(
Icons.wb_cloudy,
size: ScreenUtil.instance.setSp(30),
),
labelText: '请输入你的密码',
// helperText: '请输入你的用户名',
labelStyle: TextStyle(color: Colors.white),
helperStyle: TextStyle(color: Colors.white)),
autofocus: false,
),
),
Container(
width: double.maxFinite,
height: ScreenUtil.instance.setHeight(130),
margin: EdgeInsets.only(
top: ScreenUtil.instance.setHeight(80),
left: ScreenUtil.instance.setWidth(100),
right: ScreenUtil.instance.setWidth(100)),
child: RaisedButton(
onPressed: () {
if (_nameCon.text.length == 0 ||
_wordCon.text.length == 0) {
Toast.show(context, "账号或者密码为空");
return;
}
BaseCenterPicker()
..setPicker(BaseLoadingItem("加载中..."))
..show(context);
_model.login(context, _nameCon.text, _wordCon.text);
},
color: Colors.deepOrange,
child: baseText("登入", ScreenUtil.instance.setSp(15),
ALColors.ColorFFFFFF),
)),
Container(
width: double.maxFinite,
height: ScreenUtil.instance.setHeight(130),
margin: EdgeInsets.only(
top: ScreenUtil.instance.setHeight(20),
left: ScreenUtil.instance.setWidth(100),
right: ScreenUtil.instance.setWidth(100)),
child: RaisedButton(
color: Colors.deepPurpleAccent,
onPressed: () {
BaseCenterPicker()
..setPicker(BaseLoadingItem("加载中..."))
..show(context);
_model.resign(context, _nameCon.text, _wordCon.text);
},
child: baseText("注册", ScreenUtil.instance.setSp(15),
ALColors.ColorFFFFFF),
)),
Expanded(
child: Container(),
),
],
),
));
}
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'dart:convert';
import 'dart:io';
import 'package:example_flutter/UserModel/service/remote/api/UserApi.serv.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserBean.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserToken.dart';
import 'package:rxdart/rxdart.dart';
class Resp {
static Resp _resp;
Resp._();
static Resp getInstance() {
if (_resp == null) {
_resp = Resp._();
}
return _resp;
}
Observable<UserToken> login(String userName, String userWord) {
return UserApiImpl().login(userName, userWord);
}
Observable<UserBean> resign(String userName, String userWord) {
return UserApiImpl().resign(userName, userWord);
}
}
/*
* @author lsy
* @date 2019-11-07
**/
import 'package:example_flutter/Annotations/anno/Get.dart';
import 'package:example_flutter/Annotations/anno/Post.dart';
import 'package:example_flutter/Annotations/anno/Query.dart';
import 'package:example_flutter/Annotations/anno/ServiceCenter.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserBean.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserInfoBean.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserToken.dart';
@ServiceCenter()
abstract class UserApi {
@Post("api-token-auth/")
UserToken login(
@Query("username") String userName, @Query("password") String password);
@Post("users/")
UserBean resign(
@Query("username") String userName, @Query("password") String password);
@Get("userinfo/")
UserInfoBean getUserInfo();
}
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// ServiceGenerator
// **************************************************************************
import 'dart:convert';
import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserToken.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserBean.dart';
import 'package:example_flutter/UserModel/service/remote/entity/UserInfoBean.dart';
import 'package:example_flutter/commonModel/net/DioUtil.dart';
class UserApiImpl {
factory UserApiImpl() => _sharedInstance();
static UserApiImpl _instance;
UserApiImpl._() {}
static UserApiImpl _sharedInstance() {
if (_instance == null) {
_instance = UserApiImpl._();
}
return _instance;
}
Observable<UserToken> login(String userName, String password) {
return Observable.fromFuture(DioUtil().post('api-token-auth/',
data: {'username': userName, 'password': password})).flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(compute(paseUserToken, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<UserBean> resign(String userName, String password) {
return Observable.fromFuture(DioUtil().post('users/',
data: {'username': userName, 'password': password})).flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(compute(paseUserBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<UserInfoBean> getUserInfo() {
return Observable.fromFuture(DioUtil().get('userinfo/')).flatMap((value) {
if (value != null &&
(value.statusCode >= 200 && value.statusCode < 300)) {
return Observable.fromFuture(
compute(paseUserInfoBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
}
UserToken paseUserToken(String value) {
return UserToken.fromJson(json.decode(value));
}
UserBean paseUserBean(String value) {
return UserBean.fromJson(json.decode(value));
}
UserInfoBean paseUserInfoBean(String value) {
return UserInfoBean.fromJson(json.decode(value));
}
/*
* @author lsy
* @date 2019-11-07
**/
class UserBean {
String username;
UserBean({this.username});
UserBean.fromJson(Map<String, dynamic> json) {
username = json['username'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['username'] = this.username;
return data;
}
}
/*
* @author lsy
* @date 2019-11-15
**/
class UserInfoBean {
int uid;
String username;
UserInfoBean({this.uid, this.username});
UserInfoBean.fromJson(Map<String, dynamic> json) {
uid = json['uid'];
username = json['username'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['uid'] = this.uid;
data['username'] = this.username;
return data;
}
}
/*
* @author lsy
* @date 2019-11-07
**/
class UserToken {
String token;
UserToken({this.token});
UserToken.fromJson(Map<String, dynamic> json) {
token = json['token'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['token'] = this.token;
return data;
}
}
/*
* @author lsy
* @date 2019-10-15
**/
library GMBase;
export 'base/BaseComponent.dart';
export 'base/BaseUtil.dart';
export 'live/BaseModel.dart';
export 'live/LiveData.dart';
export 'net/Api.dart';
export 'net/DioUtil.dart';
export 'net/ALNetWork.dart';
export 'picker/loadingPicker.dart';
export 'picker/base/BaseCenterPicker.dart';
/*
* @author lsy
* @date 2019-10-13
**/
import 'package:example_flutter/res/value/ALColors.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/svg.dart';
MethodChannel channel=new MethodChannel("plugins.flutter.io/path_provider");
Future getTempDir(){
return channel.invokeMethod("getTemporaryDirectory");
}
Future openCachce(){
return channel.invokeMethod("openCache");
}
AppBar baseAppBar(
{String title,
List<Widget> action,
bool centerTitle,
VoidCallback backClick,
Color backgroundColor}) {
return baseAppBarChangeTitle(
title: title == null
? Container()
: baseText(title, 16, ALColors.Color323232),
action: action,
centerTitle: centerTitle,
backClick: backClick,
backgroundColor: backgroundColor);
}
AppBar baseAppBarChangeTitle(
{Widget title,
List<Widget> action,
bool centerTitle,
VoidCallback backClick,
Color backgroundColor}) {
return AppBar(
backgroundColor:
backgroundColor == null ? ALColors.ColorFFFFFF : backgroundColor,
title: title,
centerTitle: centerTitle,
elevation: 0.0,
leading: GestureDetector(
onTap: backClick,
child: Hero(
tag: "left_arrow",
child: Container(
color: backgroundColor == null
? ALColors.ColorFFFFFF
: backgroundColor,
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 22),
width: 30,
height: double.maxFinite,
child: SvgPicture.asset(
"image/left_arrow.svg",
color: Color(0xff323232),
))),
),
actions: action == null ? List<Widget>() : action,
);
}
Text baseText(String text, double fontSize, Color color) {
return Text(
text,
textScaleFactor: 1.0,
softWrap: true,
style: TextStyle(fontSize: fontSize, color: color),
);
}
/**
* 基础的liveView分割线
*/
Widget baseDivide(double height, double padding, Color color) {
return Container(
height: height,
margin: EdgeInsets.only(
right: ScreenUtil.instance.setWidth(padding),
left: ScreenUtil.instance.setWidth(padding)),
child: Container(
color: color,
));
}
Widget loadingItem() {
//TODO
return Center(child: CircularProgressIndicator());
}
Widget netErrorItem() {}
//TODO
/*
* @author lsy
* @date 2019-10-14
**/
import 'dart:ui';
import 'package:flutter/material.dart';
void jumpToPage(Widget page, BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: ((context) {
return page;
})));
}
/*
* @author lsy
* @date 2019-11-14
**/
import 'package:flutter/material.dart';
class MySeparator extends StatelessWidget {
final double height;
final Color color;
const MySeparator({this.height = 1, this.color = Colors.black});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final boxWidth = constraints.constrainWidth();
final dashWidth = 10.0;
final dashHeight = height;
final dashCount = (boxWidth / (2 * dashWidth)).floor();
return Flex(
children: List.generate(dashCount, (_) {
return SizedBox(
width: dashWidth,
height: dashHeight,
child: DecoratedBox(
decoration: BoxDecoration(color: color),
),
);
}),
mainAxisAlignment: MainAxisAlignment.spaceBetween,
direction: Axis.horizontal,
);
},
);
}
}
abstract class BlocBase {
void dispose();
}
import 'package:flutter/widgets.dart';
import 'bloc_base.dart';
Type _typeOf<T>() => T;
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
@required this.child,
@required this.blocs,
}) : super(key: key);
final Widget child;
final List<T> blocs;
@override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static List<T> of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<_BlocProviderInherited<T>>();
_BlocProviderInherited<T> provider =
context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
return provider?.blocs;
}
}
class _BlocProviderState<T extends BlocBase> extends State<BlocProvider<T>> {
@override
void dispose() {
widget.blocs.map((bloc) {
bloc.dispose();
});
super.dispose();
}
@override
Widget build(BuildContext context) {
return _BlocProviderInherited<T>(
blocs: widget.blocs,
child: widget.child,
);
}
}
class _BlocProviderInherited<T> extends InheritedWidget {
_BlocProviderInherited({
Key key,
@required Widget child,
@required this.blocs,
}) : super(key: key, child: child);
final List<T> blocs;
@override
bool updateShouldNotify(_BlocProviderInherited oldWidget) => false;
}
/*
* @author lsy
* @date 2019-10-08
**/
import 'MemoryCache.dart';
const MEMORY_CACHE = "MEMORY_CACHE";
const SHARE_CACHE = "SHARE_CACHE";
class CacheManager {
MemoryCache memoryCache;
static CacheManager _instance = CacheManager._();
CacheManager._() {
memoryCache = new MemoryCache();
}
static CacheManager getInstance() {
return _instance;
}
ICache get(String whichCache) {
if (whichCache == MEMORY_CACHE) {
return memoryCache;
}
}
}
class ICache {
dynamic get(String key) {}
void save(String key, dynamic value) {}
}
/*
* @author lsy
* @date 2019-10-08
**/
import 'CacheManager.dart';
class MemoryCache implements ICache {
Map<String, dynamic> _cacheMap = new Map();
@override
get(String key) {
return _cacheMap[key];
}
@override
void save(String key, value) {
_cacheMap.putIfAbsent(key, () => value);
}
}
/*
* @author lsy
* @date 2019-10-08
**/
import 'CacheManager.dart';
class ShareCache implements ICache{
@override
get(String key) {
return null;
}
@override
void save(String key, value) {
}
}
\ No newline at end of file
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'
show
GestureRecognizer,
GestureTapDownCallback,
GestureTapUpCallback,
GestureTapCallback,
GestureTapCancelCallback,
GestureLongPressUpCallback,
GestureLongPressCallback,
GestureDragStartCallback,
GestureDragUpdateCallback,
GestureDragEndCallback,
GestureDragCancelCallback,
GestureDragDownCallback,
GestureForcePressStartCallback,
GestureForcePressPeakCallback,
GestureForcePressUpdateCallback,
GestureForcePressEndCallback,
TapGestureRecognizer,
LongPressGestureRecognizer,
VerticalDragGestureRecognizer,
ForcePressGestureRecognizer,
HorizontalDragGestureRecognizer,
TapDownDetails,
PanGestureRecognizer,
TapUpDetails,
DragUpdateDetails,
DragDownDetails,
DragStartDetails,
DragEndDetails;
import 'package:flutter/rendering.dart';
import 'package:flutter/src/widgets/basic.dart' show Listener;
import 'package:flutter/src/widgets/framework.dart'
show
StatelessWidget,
StatefulWidget,
State,
Widget,
Element,
BuildContext,
SingleChildRenderObjectWidget;
import './scale.dart';
import './multitap.dart';
import './double_details.dart';
export 'package:flutter/gestures.dart'
show
DragDownDetails,
DragStartDetails,
DragUpdateDetails,
DragEndDetails,
GestureTapDownCallback,
GestureTapUpCallback,
GestureTapCallback,
GestureTapCancelCallback,
GestureLongPressCallback,
GestureDragDownCallback,
GestureDragStartCallback,
GestureDragUpdateCallback,
GestureDragEndCallback,
GestureDragCancelCallback,
// GestureScaleStartCallback,
// GestureScaleUpdateCallback,
// GestureScaleEndCallback,
GestureForcePressStartCallback,
GestureForcePressPeakCallback,
GestureForcePressEndCallback,
GestureForcePressUpdateCallback,
// ScaleStartDetails,
// ScaleUpdateDetails,
// ScaleEndDetails,
TapDownDetails,
TapUpDetails,
Velocity;
export './scale.dart'
show
GestureScaleStartCallback,
GestureScaleUpdateCallback,
GestureScaleEndCallback,
ScaleStartDetails,
ScaleUpdateDetails,
ScaleEndDetails;
export './double_details.dart' show DoubleDetails;
// Examples can assume:
// bool _lights;
// void setState(VoidCallback fn) { }
// String _last;
/// Factory for creating gesture recognizers.
///
/// `T` is the type of gesture recognizer this class manages.
///
/// Used by [RawGestureDetector.gestures].
@optionalTypeArgs
abstract class GestureRecognizerFactory<T extends GestureRecognizer> {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const GestureRecognizerFactory();
/// Must return an instance of T.
T constructor();
/// Must configure the given instance (which will have been created by
/// `constructor`).
///
/// This normally means setting the callbacks.
void initializer(T instance);
bool _debugAssertTypeMatches(Type type) {
assert(type == T,
'GestureRecognizerFactory of type $T was used where type $type was specified.');
return true;
}
}
/// Signature for closures that implement [GestureRecognizerFactory.constructor].
typedef GestureRecognizerFactoryConstructor<T extends GestureRecognizer> = T
Function();
/// Signature for closures that implement [GestureRecognizerFactory.initializer].
typedef GestureRecognizerFactoryInitializer<T extends GestureRecognizer> = void
Function(T instance);
/// Factory for creating gesture recognizers that delegates to callbacks.
///
/// Used by [RawGestureDetector.gestures].
class GestureRecognizerFactoryWithHandlers<T extends GestureRecognizer>
extends GestureRecognizerFactory<T> {
/// Creates a gesture recognizer factory with the given callbacks.
///
/// The arguments must not be null.
const GestureRecognizerFactoryWithHandlers(
this._constructor, this._initializer)
: assert(_constructor != null),
assert(_initializer != null);
final GestureRecognizerFactoryConstructor<T> _constructor;
final GestureRecognizerFactoryInitializer<T> _initializer;
@override
T constructor() => _constructor();
@override
void initializer(T instance) => _initializer(instance);
}
/// A widget that detects gestures.
///
/// Attempts to recognize gestures that correspond to its non-null callbacks.
///
/// If this widget has a child, it defers to that child for its sizing behavior.
/// If it does not have a child, it grows to fit the parent instead.
///
/// By default a GestureDetector with an invisible child ignores touches;
/// this behavior can be controlled with [behavior].
///
/// GestureDetector also listens for accessibility events and maps
/// them to the callbacks. To ignore accessibility events, set
/// [excludeFromSemantics] to true.
///
/// See <http://flutter.io/gestures/> for additional information.
///
/// Material design applications typically react to touches with ink splash
/// effects. The [InkWell] class implements this effect and can be used in place
/// of a [GestureDetector] for handling taps.
///
/// {@tool sample}
///
/// This example makes a rectangle react to being tapped by setting the
/// `_lights` field:
///
/// ```dart
/// GestureDetector(
/// onTap: () {
/// setState(() { _lights = true; });
/// },
/// child: Container(
/// color: Colors.yellow,
/// child: Text('TURN LIGHTS ON'),
/// ),
/// )
/// ```
/// {@end-tool}
///
/// ## Debugging
///
/// To see how large the hit test box of a [GestureDetector] is for debugging
/// purposes, set [debugPaintPointersEnabled] to true.
class GestureDetector extends StatelessWidget {
/// Creates a widget that detects gestures.
///
/// Pan and scale callbacks cannot be used simultaneously because scale is a
/// superset of pan. Simply use the scale callbacks instead.
///
/// Horizontal and vertical drag callbacks cannot be used simultaneously
/// because a combination of a horizontal and vertical drag is a pan. Simply
/// use the pan callbacks instead.
///
/// By default, gesture detectors contribute semantic information to the tree
/// that is used by assistive technology.
GestureDetector(
{Key key,
this.child,
this.onTapDown,
this.onTapUp,
this.onTap,
this.onTapCancel,
this.onDoubleTap,
this.onLongPress,
this.onLongPressUp,
this.onVerticalDragDown,
this.onVerticalDragStart,
this.onVerticalDragUpdate,
this.onVerticalDragEnd,
this.onVerticalDragCancel,
this.onHorizontalDragDown,
this.onHorizontalDragStart,
this.onHorizontalDragUpdate,
this.onHorizontalDragEnd,
this.onHorizontalDragCancel,
this.onForcePressStart,
this.onForcePressPeak,
this.onForcePressUpdate,
this.onForcePressEnd,
this.onPanDown,
this.onPanStart,
this.onPanUpdate,
this.onPanEnd,
this.onPanCancel,
this.onScaleStart,
this.onScaleUpdate,
this.onScaleEnd,
this.behavior,
this.excludeFromSemantics = false})
: assert(excludeFromSemantics != null),
assert(() {
final bool haveVerticalDrag = onVerticalDragStart != null ||
onVerticalDragUpdate != null ||
onVerticalDragEnd != null;
final bool haveHorizontalDrag = onHorizontalDragStart != null ||
onHorizontalDragUpdate != null ||
onHorizontalDragEnd != null;
final bool havePan =
onPanStart != null || onPanUpdate != null || onPanEnd != null;
final bool haveScale = onScaleStart != null ||
onScaleUpdate != null ||
onScaleEnd != null;
if (havePan || haveScale) {
if (havePan && haveScale) {
throw FlutterError('Incorrect GestureDetector arguments.\n'
'Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan. Just use the scale gesture recognizer.');
}
final String recognizer = havePan ? 'pan' : 'scale';
if (haveVerticalDrag && haveHorizontalDrag) {
throw FlutterError('Incorrect GestureDetector arguments.\n'
'Simultaneously having a vertical drag gesture recognizer, a horizontal drag gesture recognizer, and a $recognizer gesture recognizer '
'will result in the $recognizer gesture recognizer being ignored, since the other two will catch all drags.');
}
}
return true;
}()),
super(key: key);
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
final Widget child;
/// A pointer that might cause a tap has contacted the screen at a particular
/// location.
///
/// This is called after a short timeout, even if the winning gesture has not
/// yet been selected. If the tap gesture wins, [onTapUp] will be called,
/// otherwise [onTapCancel] will be called.
final GestureTapDownCallback onTapDown;
/// A pointer that will trigger a tap has stopped contacting the screen at a
/// particular location.
///
/// This triggers immediately before [onTap] in the case of the tap gesture
/// winning. If the tap gesture did not win, [onTapCancel] is called instead.
final GestureTapUpCallback onTapUp;
/// A tap has occurred.
///
/// This triggers when the tap gesture wins. If the tap gesture did not win,
/// [onTapCancel] is called instead.
///
/// See also:
///
/// * [onTapUp], which is called at the same time but includes details
/// regarding the pointer position.
final GestureTapCallback onTap;
/// The pointer that previously triggered [onTapDown] will not end up causing
/// a tap.
///
/// This is called after [onTapDown], and instead of [onTapUp] and [onTap], if
/// the tap gesture did not win.
final GestureTapCancelCallback onTapCancel;
/// The user has tapped the screen at the same location twice in quick
/// succession.
final GestureDoubleTapCallback onDoubleTap;
/// A pointer has remained in contact with the screen at the same location for
/// a long period of time.
final GestureLongPressCallback onLongPress;
/// A pointer that has triggered a long-press has stopped contacting the screen.
final GestureLongPressUpCallback onLongPressUp;
/// A pointer has contacted the screen and might begin to move vertically.
final GestureDragDownCallback onVerticalDragDown;
/// A pointer has contacted the screen and has begun to move vertically.
final GestureDragStartCallback onVerticalDragStart;
/// A pointer that is in contact with the screen and moving vertically has
/// moved in the vertical direction.
final GestureDragUpdateCallback onVerticalDragUpdate;
/// A pointer that was previously in contact with the screen and moving
/// vertically is no longer in contact with the screen and was moving at a
/// specific velocity when it stopped contacting the screen.
final GestureDragEndCallback onVerticalDragEnd;
/// The pointer that previously triggered [onVerticalDragDown] did not
/// complete.
final GestureDragCancelCallback onVerticalDragCancel;
/// A pointer has contacted the screen and might begin to move horizontally.
final GestureDragDownCallback onHorizontalDragDown;
/// A pointer has contacted the screen and has begun to move horizontally.
final GestureDragStartCallback onHorizontalDragStart;
/// A pointer that is in contact with the screen and moving horizontally has
/// moved in the horizontal direction.
final GestureDragUpdateCallback onHorizontalDragUpdate;
/// A pointer that was previously in contact with the screen and moving
/// horizontally is no longer in contact with the screen and was moving at a
/// specific velocity when it stopped contacting the screen.
final GestureDragEndCallback onHorizontalDragEnd;
/// The pointer that previously triggered [onHorizontalDragDown] did not
/// complete.
final GestureDragCancelCallback onHorizontalDragCancel;
/// A pointer has contacted the screen and might begin to move.
final GestureDragDownCallback onPanDown;
/// A pointer has contacted the screen and has begun to move.
final GestureDragStartCallback onPanStart;
/// A pointer that is in contact with the screen and moving has moved again.
final GestureDragUpdateCallback onPanUpdate;
/// A pointer that was previously in contact with the screen and moving
/// is no longer in contact with the screen and was moving at a specific
/// velocity when it stopped contacting the screen.
final GestureDragEndCallback onPanEnd;
/// The pointer that previously triggered [onPanDown] did not complete.
final GestureDragCancelCallback onPanCancel;
/// The pointers in contact with the screen have established a focal point and
/// initial scale of 1.0.
final GestureScaleStartCallback onScaleStart;
/// The pointers in contact with the screen have indicated a new focal point
/// and/or scale.
final GestureScaleUpdateCallback onScaleUpdate;
/// The pointers are no longer in contact with the screen.
final GestureScaleEndCallback onScaleEnd;
/// The pointer is in contact with the screen and has pressed with sufficient
/// force to initiate a force press. The amount of force is at least
/// [ForcePressGestureRecognizer.startPressure].
///
/// Note that this callback will only be fired on devices with pressure
/// detecting screens.
final GestureForcePressStartCallback onForcePressStart;
/// The pointer is in contact with the screen and has pressed with the maximum
/// force. The amount of force is at least
/// [ForcePressGestureRecognizer.peakPressure].
///
/// Note that this callback will only be fired on devices with pressure
/// detecting screens.
final GestureForcePressPeakCallback onForcePressPeak;
/// A pointer is in contact with the screen, has previously passed the
/// [ForcePressGestureRecognizer.startPressure] and is either moving on the
/// plane of the screen, pressing the screen with varying forces or both
/// simultaneously.
///
/// Note that this callback will only be fired on devices with pressure
/// detecting screens.
final GestureForcePressUpdateCallback onForcePressUpdate;
/// The pointer is no longer in contact with the screen.
///
/// Note that this callback will only be fired on devices with pressure
/// detecting screens.
final GestureForcePressEndCallback onForcePressEnd;
/// How this gesture detector should behave during hit testing.
///
/// This defaults to [HitTestBehavior.deferToChild] if [child] is not null and
/// [HitTestBehavior.translucent] if child is null.
final HitTestBehavior behavior;
/// Whether to exclude these gestures from the semantics tree. For
/// example, the long-press gesture for showing a tooltip is
/// excluded because the tooltip itself is included in the semantics
/// tree directly and so having a gesture to show it would result in
/// duplication of information.
final bool excludeFromSemantics;
@override
Widget build(BuildContext context) {
final Map<Type, GestureRecognizerFactory> gestures =
<Type, GestureRecognizerFactory>{};
if (onTapDown != null ||
onTapUp != null ||
onTap != null ||
onTapCancel != null) {
gestures[TapGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
() => TapGestureRecognizer(debugOwner: this),
(TapGestureRecognizer instance) {
instance
..onTapDown = onTapDown
..onTapUp = onTapUp
..onTap = onTap
..onTapCancel = onTapCancel;
},
);
}
if (onDoubleTap != null) {
gestures[DoubleTapGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<DoubleTapGestureRecognizer>(
() => DoubleTapGestureRecognizer(debugOwner: this),
(DoubleTapGestureRecognizer instance) {
instance..onDoubleTap = onDoubleTap;
},
);
}
if (onLongPress != null || onLongPressUp != null) {
gestures[LongPressGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
() => LongPressGestureRecognizer(debugOwner: this),
(LongPressGestureRecognizer instance) {
instance
..onLongPress = onLongPress
..onLongPressUp = onLongPressUp;
},
);
}
if (onVerticalDragDown != null ||
onVerticalDragStart != null ||
onVerticalDragUpdate != null ||
onVerticalDragEnd != null ||
onVerticalDragCancel != null) {
gestures[VerticalDragGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer(debugOwner: this),
(VerticalDragGestureRecognizer instance) {
instance
..onDown = onVerticalDragDown
..onStart = onVerticalDragStart
..onUpdate = onVerticalDragUpdate
..onEnd = onVerticalDragEnd
..onCancel = onVerticalDragCancel;
},
);
}
if (onHorizontalDragDown != null ||
onHorizontalDragStart != null ||
onHorizontalDragUpdate != null ||
onHorizontalDragEnd != null ||
onHorizontalDragCancel != null) {
gestures[HorizontalDragGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<HorizontalDragGestureRecognizer>(
() => HorizontalDragGestureRecognizer(debugOwner: this),
(HorizontalDragGestureRecognizer instance) {
instance
..onDown = onHorizontalDragDown
..onStart = onHorizontalDragStart
..onUpdate = onHorizontalDragUpdate
..onEnd = onHorizontalDragEnd
..onCancel = onHorizontalDragCancel;
},
);
}
if (onPanDown != null ||
onPanStart != null ||
onPanUpdate != null ||
onPanEnd != null ||
onPanCancel != null) {
gestures[PanGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
() => PanGestureRecognizer(debugOwner: this),
(PanGestureRecognizer instance) {
instance
..onDown = onPanDown
..onStart = onPanStart
..onUpdate = onPanUpdate
..onEnd = onPanEnd
..onCancel = onPanCancel;
},
);
}
if (onScaleStart != null || onScaleUpdate != null || onScaleEnd != null) {
gestures[ScaleGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<ScaleGestureRecognizer>(
() => ScaleGestureRecognizer(debugOwner: this),
(ScaleGestureRecognizer instance) {
instance
..onStart = onScaleStart
..onUpdate = onScaleUpdate
..onEnd = onScaleEnd;
},
);
}
if (onForcePressStart != null ||
onForcePressPeak != null ||
onForcePressUpdate != null ||
onForcePressEnd != null) {
gestures[ForcePressGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<ForcePressGestureRecognizer>(
() => ForcePressGestureRecognizer(debugOwner: this),
(ForcePressGestureRecognizer instance) {
instance
..onStart = onForcePressStart
..onPeak = onForcePressPeak
..onUpdate = onForcePressUpdate
..onEnd = onForcePressEnd;
},
);
}
return RawGestureDetector(
gestures: gestures,
behavior: behavior,
excludeFromSemantics: excludeFromSemantics,
child: child,
);
}
}
/// A widget that detects gestures described by the given gesture
/// factories.
///
/// For common gestures, use a [GestureRecognizer].
/// [RawGestureDetector] is useful primarily when developing your
/// own gesture recognizers.
///
/// Configuring the gesture recognizers requires a carefully constructed map, as
/// described in [gestures] and as shown in the example below.
///
/// {@tool sample}
///
/// This example shows how to hook up a [TapGestureRecognizer]. It assumes that
/// the code is being used inside a [State] object with a `_last` field that is
/// then displayed as the child of the gesture detector.
///
/// ```dart
/// RawGestureDetector(
/// gestures: <Type, GestureRecognizerFactory>{
/// TapGestureRecognizer: GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
/// () => TapGestureRecognizer(),
/// (TapGestureRecognizer instance) {
/// instance
/// ..onTapDown = (TapDownDetails details) { setState(() { _last = 'down'; }); }
/// ..onTapUp = (TapUpDetails details) { setState(() { _last = 'up'; }); }
/// ..onTap = () { setState(() { _last = 'tap'; }); }
/// ..onTapCancel = () { setState(() { _last = 'cancel'; }); };
/// },
/// ),
/// },
/// child: Container(width: 300.0, height: 300.0, color: Colors.yellow, child: Text(_last)),
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [GestureDetector], a less flexible but much simpler widget that does the same thing.
/// * [Listener], a widget that reports raw pointer events.
/// * [GestureRecognizer], the class that you extend to create a custom gesture recognizer.
class RawGestureDetector extends StatefulWidget {
/// Creates a widget that detects gestures.
///
/// By default, gesture detectors contribute semantic information to the tree
/// that is used by assistive technology. This can be controlled using
/// [excludeFromSemantics].
const RawGestureDetector(
{Key key,
this.child,
this.gestures = const <Type, GestureRecognizerFactory>{},
this.behavior,
this.excludeFromSemantics = false})
: assert(gestures != null),
assert(excludeFromSemantics != null),
super(key: key);
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
final Widget child;
/// The gestures that this widget will attempt to recognize.
///
/// This should be a map from [GestureRecognizer] subclasses to
/// [GestureRecognizerFactory] subclasses specialized with the same type.
///
/// This value can be late-bound at layout time using
/// [RawGestureDetectorState.replaceGestureRecognizers].
final Map<Type, GestureRecognizerFactory> gestures;
/// How this gesture detector should behave during hit testing.
///
/// This defaults to [HitTestBehavior.deferToChild] if [child] is not null and
/// [HitTestBehavior.translucent] if child is null.
final HitTestBehavior behavior;
/// Whether to exclude these gestures from the semantics tree. For
/// example, the long-press gesture for showing a tooltip is
/// excluded because the tooltip itself is included in the semantics
/// tree directly and so having a gesture to show it would result in
/// duplication of information.
final bool excludeFromSemantics;
@override
RawGestureDetectorState createState() => RawGestureDetectorState();
}
/// State for a [RawGestureDetector].
class RawGestureDetectorState extends State<RawGestureDetector> {
Map<Type, GestureRecognizer> _recognizers = const <Type, GestureRecognizer>{};
@override
void initState() {
super.initState();
_syncAll(widget.gestures);
}
@override
void didUpdateWidget(RawGestureDetector oldWidget) {
super.didUpdateWidget(oldWidget);
_syncAll(widget.gestures);
}
/// This method can be called after the build phase, during the
/// layout of the nearest descendant [RenderObjectWidget] of the
/// gesture detector, to update the list of active gesture
/// recognizers.
///
/// The typical use case is [Scrollable]s, which put their viewport
/// in their gesture detector, and then need to know the dimensions
/// of the viewport and the viewport's child to determine whether
/// the gesture detector should be enabled.
///
/// The argument should follow the same conventions as
/// [RawGestureDetector.gestures]. It acts like a temporary replacement for
/// that value until the next build.
void replaceGestureRecognizers(Map<Type, GestureRecognizerFactory> gestures) {
assert(() {
if (!context.findRenderObject().owner.debugDoingLayout) {
throw FlutterError(
'Unexpected call to replaceGestureRecognizers() method of RawGestureDetectorState.\n'
'The replaceGestureRecognizers() method can only be called during the layout phase. '
'To set the gesture recognizers at other times, trigger a new build using setState() '
'and provide the new gesture recognizers as constructor arguments to the corresponding '
'RawGestureDetector or GestureDetector object.');
}
return true;
}());
_syncAll(gestures);
if (!widget.excludeFromSemantics) {
final RenderSemanticsGestureHandler semanticsGestureHandler =
context.findRenderObject();
context.visitChildElements((Element element) {
final _GestureSemantics widget = element.widget;
widget._updateHandlers(semanticsGestureHandler);
});
}
}
/// This method can be called outside of the build phase to filter the list of
/// available semantic actions.
///
/// The actual filtering is happening in the next frame and a frame will be
/// scheduled if non is pending.
///
/// This is used by [Scrollable] to configure system accessibility tools so
/// that they know in which direction a particular list can be scrolled.
///
/// If this is never called, then the actions are not filtered. If the list of
/// actions to filter changes, it must be called again.
void replaceSemanticsActions(Set<SemanticsAction> actions) {
assert(() {
final Element element = context;
if (element.owner.debugBuilding) {
throw FlutterError(
'Unexpected call to replaceSemanticsActions() method of RawGestureDetectorState.\n'
'The replaceSemanticsActions() method can only be called outside of the build phase.');
}
return true;
}());
if (!widget.excludeFromSemantics) {
final RenderSemanticsGestureHandler semanticsGestureHandler =
context.findRenderObject();
semanticsGestureHandler.validActions =
actions; // will call _markNeedsSemanticsUpdate(), if required.
}
}
@override
void dispose() {
for (GestureRecognizer recognizer in _recognizers.values)
recognizer.dispose();
_recognizers = null;
super.dispose();
}
void _syncAll(Map<Type, GestureRecognizerFactory> gestures) {
assert(_recognizers != null);
final Map<Type, GestureRecognizer> oldRecognizers = _recognizers;
_recognizers = <Type, GestureRecognizer>{};
for (Type type in gestures.keys) {
assert(gestures[type] != null);
assert(gestures[type]._debugAssertTypeMatches(type));
assert(!_recognizers.containsKey(type));
_recognizers[type] = oldRecognizers[type] ?? gestures[type].constructor();
assert(_recognizers[type].runtimeType == type,
'GestureRecognizerFactory of type $type created a GestureRecognizer of type ${_recognizers[type].runtimeType}. The GestureRecognizerFactory must be specialized with the type of the class that it returns from its constructor method.');
gestures[type].initializer(_recognizers[type]);
}
for (Type type in oldRecognizers.keys) {
if (!_recognizers.containsKey(type)) oldRecognizers[type].dispose();
}
}
void _handlePointerDown(PointerDownEvent event) {
assert(_recognizers != null);
for (GestureRecognizer recognizer in _recognizers.values)
recognizer.addPointer(event);
}
HitTestBehavior get _defaultBehavior {
return widget.child == null
? HitTestBehavior.translucent
: HitTestBehavior.deferToChild;
}
void _handleSemanticsTap() {
final TapGestureRecognizer recognizer = _recognizers[TapGestureRecognizer];
assert(recognizer != null);
if (recognizer.onTapDown != null) recognizer.onTapDown(TapDownDetails());
if (recognizer.onTapUp != null) recognizer.onTapUp(TapUpDetails());
if (recognizer.onTap != null) recognizer.onTap();
}
void _handleSemanticsLongPress() {
final LongPressGestureRecognizer recognizer =
_recognizers[LongPressGestureRecognizer];
assert(recognizer != null);
if (recognizer.onLongPress != null) recognizer.onLongPress();
}
void _handleSemanticsHorizontalDragUpdate(DragUpdateDetails updateDetails) {
{
final HorizontalDragGestureRecognizer recognizer =
_recognizers[HorizontalDragGestureRecognizer];
if (recognizer != null) {
if (recognizer.onDown != null) recognizer.onDown(DragDownDetails());
if (recognizer.onStart != null) recognizer.onStart(DragStartDetails());
if (recognizer.onUpdate != null) recognizer.onUpdate(updateDetails);
if (recognizer.onEnd != null)
recognizer.onEnd(DragEndDetails(primaryVelocity: 0.0));
return;
}
}
{
final PanGestureRecognizer recognizer =
_recognizers[PanGestureRecognizer];
if (recognizer != null) {
if (recognizer.onDown != null) recognizer.onDown(DragDownDetails());
if (recognizer.onStart != null) recognizer.onStart(DragStartDetails());
if (recognizer.onUpdate != null) recognizer.onUpdate(updateDetails);
if (recognizer.onEnd != null) recognizer.onEnd(DragEndDetails());
return;
}
}
}
void _handleSemanticsVerticalDragUpdate(DragUpdateDetails updateDetails) {
{
final VerticalDragGestureRecognizer recognizer =
_recognizers[VerticalDragGestureRecognizer];
if (recognizer != null) {
if (recognizer.onDown != null) recognizer.onDown(DragDownDetails());
if (recognizer.onStart != null) recognizer.onStart(DragStartDetails());
if (recognizer.onUpdate != null) recognizer.onUpdate(updateDetails);
if (recognizer.onEnd != null)
recognizer.onEnd(DragEndDetails(primaryVelocity: 0.0));
return;
}
}
{
final PanGestureRecognizer recognizer =
_recognizers[PanGestureRecognizer];
if (recognizer != null) {
if (recognizer.onDown != null) recognizer.onDown(DragDownDetails());
if (recognizer.onStart != null) recognizer.onStart(DragStartDetails());
if (recognizer.onUpdate != null) recognizer.onUpdate(updateDetails);
if (recognizer.onEnd != null) recognizer.onEnd(DragEndDetails());
return;
}
}
}
@override
Widget build(BuildContext context) {
Widget result = Listener(
onPointerDown: _handlePointerDown,
behavior: widget.behavior ?? _defaultBehavior,
child: widget.child);
if (!widget.excludeFromSemantics)
result = _GestureSemantics(owner: this, child: result);
return result;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
if (_recognizers == null) {
properties.add(DiagnosticsNode.message('DISPOSED'));
} else {
final List<String> gestures = _recognizers.values
.map<String>(
(GestureRecognizer recognizer) => recognizer.debugDescription)
.toList();
properties.add(
IterableProperty<String>('gestures', gestures, ifEmpty: '<none>'));
properties.add(IterableProperty<GestureRecognizer>(
'recognizers', _recognizers.values,
level: DiagnosticLevel.fine));
}
properties.add(EnumProperty<HitTestBehavior>('behavior', widget.behavior,
defaultValue: null));
}
}
class _GestureSemantics extends SingleChildRenderObjectWidget {
const _GestureSemantics({Key key, Widget child, this.owner})
: super(key: key, child: child);
final RawGestureDetectorState owner;
@override
RenderSemanticsGestureHandler createRenderObject(BuildContext context) {
return RenderSemanticsGestureHandler(
onTap: _onTapHandler,
onLongPress: _onLongPressHandler,
onHorizontalDragUpdate: _onHorizontalDragUpdateHandler,
onVerticalDragUpdate: _onVerticalDragUpdateHandler,
);
}
void _updateHandlers(RenderSemanticsGestureHandler renderObject) {
renderObject
..onTap = _onTapHandler
..onLongPress = _onLongPressHandler
..onHorizontalDragUpdate = _onHorizontalDragUpdateHandler
..onVerticalDragUpdate = _onVerticalDragUpdateHandler;
}
@override
void updateRenderObject(
BuildContext context, RenderSemanticsGestureHandler renderObject) {
_updateHandlers(renderObject);
}
GestureTapCallback get _onTapHandler {
return owner._recognizers.containsKey(TapGestureRecognizer)
? owner._handleSemanticsTap
: null;
}
GestureTapCallback get _onLongPressHandler {
return owner._recognizers.containsKey(LongPressGestureRecognizer)
? owner._handleSemanticsLongPress
: null;
}
GestureDragUpdateCallback get _onHorizontalDragUpdateHandler {
return owner._recognizers.containsKey(HorizontalDragGestureRecognizer) ||
owner._recognizers.containsKey(PanGestureRecognizer)
? owner._handleSemanticsHorizontalDragUpdate
: null;
}
GestureDragUpdateCallback get _onVerticalDragUpdateHandler {
return owner._recognizers.containsKey(VerticalDragGestureRecognizer) ||
owner._recognizers.containsKey(PanGestureRecognizer)
? owner._handleSemanticsVerticalDragUpdate
: null;
}
}
import 'package:flutter/src/gestures/events.dart' show PointerEvent;
/// Signature for callback when the user has tapped the screen at the same
/// location twice in quick succession.
typedef GestureDoubleTapCallback = void Function(DoubleDetails details);
/// double tap callback details
/// 双击的回调信息
class DoubleDetails {
DoubleDetails({this.pointerEvent});
final PointerEvent pointerEvent;
@override
String toString() => 'DoubleDetails(pointerEvent: $pointerEvent)';
}
import 'package:flutter/material.dart';
import './touchable_container.dart';
@immutable
class DragScaleContainer extends StatefulWidget {
Widget child;
final Function(DragDownDetails details) _onPanDown;
/// 双击内容是否一致放大,默认是true,也就是一致放大
/// 如果为false,第一次双击放大两倍,再次双击恢复原本大小
bool doubleTapStillScale;
DragScaleContainer(this._onPanDown,{Widget child, bool doubleTapStillScale = true
})
: this.child = child,
this.doubleTapStillScale = doubleTapStillScale;
@override
State<StatefulWidget> createState() {
return _DragScaleContainerState();
}
}
class _DragScaleContainerState extends State<DragScaleContainer> {
@override
Widget build(BuildContext context) {
return ClipRect(
child: TouchableContainer(
widget._onPanDown,
child: widget.child, doubleTapStillScale: widget.doubleTapStillScale),
);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:ui' show Offset;
import 'package:flutter/src/gestures/binding.dart';
import 'package:flutter/src/gestures/pointer_router.dart';
import 'package:flutter/src/gestures/tap.dart';
import 'package:flutter/src/gestures/arena.dart';
import 'package:flutter/src/gestures/constants.dart';
import 'package:flutter/src/gestures/events.dart';
import 'package:flutter/src/gestures/recognizer.dart';
import 'package:flutter/src/gestures/velocity_tracker.dart';
import './double_details.dart';
/// Signature used by [MultiTapGestureRecognizer] for when a pointer that might
/// cause a tap has contacted the screen at a particular location.
typedef GestureMultiTapDownCallback = void Function(
int pointer, TapDownDetails details);
/// Signature used by [MultiTapGestureRecognizer] for when a pointer that will
/// trigger a tap has stopped contacting the screen at a particular location.
typedef GestureMultiTapUpCallback = void Function(
int pointer, TapUpDetails details);
/// Signature used by [MultiTapGestureRecognizer] for when a tap has occurred.
typedef GestureMultiTapCallback = void Function(int pointer);
/// Signature for when the pointer that previously triggered a
/// [GestureMultiTapDownCallback] will not end up causing a tap.
typedef GestureMultiTapCancelCallback = void Function(int pointer);
/// TapTracker helps track individual tap sequences as part of a
/// larger gesture.
class _TapTracker {
_TapTracker({PointerDownEvent event, this.entry})
: pointer = event.pointer,
_initialPosition = event.position;
final int pointer;
final GestureArenaEntry entry;
final Offset _initialPosition;
bool _isTrackingPointer = false;
void startTrackingPointer(PointerRoute route) {
if (!_isTrackingPointer) {
_isTrackingPointer = true;
GestureBinding.instance.pointerRouter.addRoute(pointer, route);
}
}
void stopTrackingPointer(PointerRoute route) {
if (_isTrackingPointer) {
_isTrackingPointer = false;
GestureBinding.instance.pointerRouter.removeRoute(pointer, route);
}
}
bool isWithinTolerance(PointerEvent event, double tolerance) {
final Offset offset = event.position - _initialPosition;
return offset.distance <= tolerance;
}
}
/// Recognizes when the user has tapped the screen at the same location twice in
/// quick succession.
class DoubleTapGestureRecognizer extends GestureRecognizer {
/// Create a gesture recognizer for double taps.
DoubleTapGestureRecognizer({Object debugOwner})
: super(debugOwner: debugOwner);
// Implementation notes:
// The double tap recognizer can be in one of four states. There's no
// explicit enum for the states, because they are already captured by
// the state of existing fields. Specifically:
// Waiting on first tap: In this state, the _trackers list is empty, and
// _firstTap is null.
// First tap in progress: In this state, the _trackers list contains all
// the states for taps that have begun but not completed. This list can
// have more than one entry if two pointers begin to tap.
// Waiting on second tap: In this state, one of the in-progress taps has
// completed successfully. The _trackers list is again empty, and
// _firstTap records the successful tap.
// Second tap in progress: Much like the "first tap in progress" state, but
// _firstTap is non-null. If a tap completes successfully while in this
// state, the callback is called and the state is reset.
// There are various other scenarios that cause the state to reset:
// - All in-progress taps are rejected (by time, distance, pointercancel, etc)
// - The long timer between taps expires
// - The gesture arena decides we have been rejected wholesale
/// Called when the user has tapped the screen at the same location twice in
/// quick succession.
GestureDoubleTapCallback onDoubleTap;
Timer _doubleTapTimer;
_TapTracker _firstTap;
final Map<int, _TapTracker> _trackers = <int, _TapTracker>{};
@override
void addPointer(PointerEvent event) {
// Ignore out-of-bounds second taps.
if (_firstTap != null &&
!_firstTap.isWithinTolerance(event, kDoubleTapSlop)) return;
_stopDoubleTapTimer();
final _TapTracker tracker = _TapTracker(
event: event,
entry: GestureBinding.instance.gestureArena.add(event.pointer, this));
_trackers[event.pointer] = tracker;
tracker.startTrackingPointer(_handleEvent);
}
void _handleEvent(PointerEvent event) {
final _TapTracker tracker = _trackers[event.pointer];
assert(tracker != null);
if (event is PointerUpEvent) {
if (_firstTap == null)
_registerFirstTap(tracker);
else
_registerSecondTap(tracker, event);
} else if (event is PointerMoveEvent) {
if (!tracker.isWithinTolerance(event, kDoubleTapTouchSlop))
_reject(tracker);
} else if (event is PointerCancelEvent) {
_reject(tracker);
}
}
@override
void acceptGesture(int pointer) {}
@override
void rejectGesture(int pointer) {
_TapTracker tracker = _trackers[pointer];
// If tracker isn't in the list, check if this is the first tap tracker
if (tracker == null && _firstTap != null && _firstTap.pointer == pointer)
tracker = _firstTap;
// If tracker is still null, we rejected ourselves already
if (tracker != null) _reject(tracker);
}
void _reject(_TapTracker tracker) {
_trackers.remove(tracker.pointer);
tracker.entry.resolve(GestureDisposition.rejected);
_freezeTracker(tracker);
// If the first tap is in progress, and we've run out of taps to track,
// reset won't have any work to do. But if we're in the second tap, we need
// to clear intermediate state.
if (_firstTap != null && (_trackers.isEmpty || tracker == _firstTap))
_reset();
}
@override
void dispose() {
_reset();
super.dispose();
}
void _reset() {
_stopDoubleTapTimer();
if (_firstTap != null) {
// Note, order is important below in order for the resolve -> reject logic
// to work properly.
final _TapTracker tracker = _firstTap;
_firstTap = null;
_reject(tracker);
GestureBinding.instance.gestureArena.release(tracker.pointer);
}
_clearTrackers();
}
void _registerFirstTap(_TapTracker tracker) {
_startDoubleTapTimer();
GestureBinding.instance.gestureArena.hold(tracker.pointer);
// Note, order is important below in order for the clear -> reject logic to
// work properly.
_freezeTracker(tracker);
_trackers.remove(tracker.pointer);
_clearTrackers();
_firstTap = tracker;
}
void _registerSecondTap(_TapTracker tracker, PointerEvent event) {
_firstTap.entry.resolve(GestureDisposition.accepted);
tracker.entry.resolve(GestureDisposition.accepted);
_freezeTracker(tracker);
_trackers.remove(tracker.pointer);
if (onDoubleTap != null)
invokeCallback<void>(
'onDoubleTap', () => onDoubleTap(DoubleDetails(pointerEvent: event)));
_reset();
}
void _clearTrackers() {
_trackers.values.toList().forEach(_reject);
assert(_trackers.isEmpty);
}
void _freezeTracker(_TapTracker tracker) {
tracker.stopTrackingPointer(_handleEvent);
}
void _startDoubleTapTimer() {
_doubleTapTimer ??= Timer(kDoubleTapTimeout, _reset);
}
void _stopDoubleTapTimer() {
if (_doubleTapTimer != null) {
_doubleTapTimer.cancel();
_doubleTapTimer = null;
}
}
@override
String get debugDescription => 'double tap';
}
/// TapGesture represents a full gesture resulting from a single tap sequence,
/// as part of a [MultiTapGestureRecognizer]. Tap gestures are passive, meaning
/// that they will not preempt any other arena member in play.
class _TapGesture extends _TapTracker {
_TapGesture(
{this.gestureRecognizer, PointerEvent event, Duration longTapDelay})
: _lastPosition = event.position,
super(
event: event,
entry: GestureBinding.instance.gestureArena
.add(event.pointer, gestureRecognizer)) {
startTrackingPointer(handleEvent);
if (longTapDelay > Duration.zero) {
_timer = Timer(longTapDelay, () {
_timer = null;
gestureRecognizer._dispatchLongTap(event.pointer, _lastPosition);
});
}
}
final MultiTapGestureRecognizer gestureRecognizer;
bool _wonArena = false;
Timer _timer;
Offset _lastPosition;
Offset _finalPosition;
void handleEvent(PointerEvent event) {
assert(event.pointer == pointer);
if (event is PointerMoveEvent) {
if (!isWithinTolerance(event, kTouchSlop))
cancel();
else
_lastPosition = event.position;
} else if (event is PointerCancelEvent) {
cancel();
} else if (event is PointerUpEvent) {
stopTrackingPointer(handleEvent);
_finalPosition = event.position;
_check();
}
}
@override
void stopTrackingPointer(PointerRoute route) {
_timer?.cancel();
_timer = null;
super.stopTrackingPointer(route);
}
void accept() {
_wonArena = true;
_check();
}
void reject() {
stopTrackingPointer(handleEvent);
gestureRecognizer._dispatchCancel(pointer);
}
void cancel() {
// If we won the arena already, then entry is resolved, so resolving
// again is a no-op. But we still need to clean up our own state.
if (_wonArena)
reject();
else
entry.resolve(GestureDisposition.rejected); // eventually calls reject()
}
void _check() {
if (_wonArena && _finalPosition != null)
gestureRecognizer._dispatchTap(pointer, _finalPosition);
}
}
/// Recognizes taps on a per-pointer basis.
///
/// [MultiTapGestureRecognizer] considers each sequence of pointer events that
/// could constitute a tap independently of other pointers: For example, down-1,
/// down-2, up-1, up-2 produces two taps, on up-1 and up-2.
///
/// See also:
///
/// * [TapGestureRecognizer]
class MultiTapGestureRecognizer extends GestureRecognizer {
/// Creates a multi-tap gesture recognizer.
///
/// The [longTapDelay] defaults to [Duration.zero], which means
/// [onLongTapDown] is called immediately after [onTapDown].
MultiTapGestureRecognizer({
this.longTapDelay = Duration.zero,
Object debugOwner,
}) : super(debugOwner: debugOwner);
/// A pointer that might cause a tap has contacted the screen at a particular
/// location.
GestureMultiTapDownCallback onTapDown;
/// A pointer that will trigger a tap has stopped contacting the screen at a
/// particular location.
GestureMultiTapUpCallback onTapUp;
/// A tap has occurred.
GestureMultiTapCallback onTap;
/// The pointer that previously triggered [onTapDown] will not end up causing
/// a tap.
GestureMultiTapCancelCallback onTapCancel;
/// The amount of time between [onTapDown] and [onLongTapDown].
Duration longTapDelay;
/// A pointer that might cause a tap is still in contact with the screen at a
/// particular location after [longTapDelay].
GestureMultiTapDownCallback onLongTapDown;
final Map<int, _TapGesture> _gestureMap = <int, _TapGesture>{};
@override
void addPointer(PointerEvent event) {
assert(!_gestureMap.containsKey(event.pointer));
_gestureMap[event.pointer] = _TapGesture(
gestureRecognizer: this, event: event, longTapDelay: longTapDelay);
if (onTapDown != null)
invokeCallback<void>(
'onTapDown',
() => onTapDown(
event.pointer, TapDownDetails(globalPosition: event.position)));
}
@override
void acceptGesture(int pointer) {
assert(_gestureMap.containsKey(pointer));
_gestureMap[pointer].accept();
}
@override
void rejectGesture(int pointer) {
assert(_gestureMap.containsKey(pointer));
_gestureMap[pointer].reject();
assert(!_gestureMap.containsKey(pointer));
}
void _dispatchCancel(int pointer) {
assert(_gestureMap.containsKey(pointer));
_gestureMap.remove(pointer);
if (onTapCancel != null)
invokeCallback<void>('onTapCancel', () => onTapCancel(pointer));
}
void _dispatchTap(int pointer, Offset globalPosition) {
assert(_gestureMap.containsKey(pointer));
_gestureMap.remove(pointer);
if (onTapUp != null)
invokeCallback<void>('onTapUp',
() => onTapUp(pointer, TapUpDetails(globalPosition: globalPosition)));
if (onTap != null) invokeCallback<void>('onTap', () => onTap(pointer));
}
void _dispatchLongTap(int pointer, Offset lastPosition) {
assert(_gestureMap.containsKey(pointer));
if (onLongTapDown != null)
invokeCallback<void>(
'onLongTapDown',
() => onLongTapDown(
pointer, TapDownDetails(globalPosition: lastPosition)));
}
@override
void dispose() {
final List<_TapGesture> localGestures =
List<_TapGesture>.from(_gestureMap.values);
for (_TapGesture gesture in localGestures) gesture.cancel();
// Rejection of each gesture should cause it to be removed from our map
assert(_gestureMap.isEmpty);
super.dispose();
}
@override
String get debugDescription => 'multitap';
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:async' show Timer;
import 'package:flutter/src/gestures/arena.dart';
import 'package:flutter/src/gestures/constants.dart';
import 'package:flutter/src/gestures/events.dart';
import 'package:flutter/src/gestures/recognizer.dart';
import 'package:flutter/src/gestures/velocity_tracker.dart';
import './double_details.dart';
/// The possible states of a [ScaleGestureRecognizer].
enum _ScaleState {
/// The recognizer is ready to start recognizing a gesture.
ready,
/// The sequence of pointer events seen thus far is consistent with a scale
/// gesture but the gesture has not been accepted definitively.
possible,
/// The sequence of pointer events seen thus far has been accepted
/// definitively as a scale gesture.
accepted,
/// The sequence of pointer events seen thus far has been accepted
/// definitively as a scale gesture and the pointers established a focal point
/// and initial scale.
started,
}
/// Details for [GestureScaleStartCallback].
class ScaleStartDetails {
/// Creates details for [GestureScaleStartCallback].
///
/// The [focalPoint] argument must not be null.
ScaleStartDetails({this.focalPoint = Offset.zero})
: assert(focalPoint != null);
/// The initial focal point of the pointers in contact with the screen.
/// Reported in global coordinates.
final Offset focalPoint;
@override
String toString() => 'ScaleStartDetails(focalPoint: $focalPoint)';
}
/// Details for [GestureScaleUpdateCallback].
class ScaleUpdateDetails {
/// Creates details for [GestureScaleUpdateCallback].
///
/// The [focalPoint], [scale], [rotation] arguments must not be null. The [scale]
/// argument must be greater than or equal to zero.
ScaleUpdateDetails({
this.focalPoint = Offset.zero,
this.scale = 1.0,
this.rotation = 0.0,
this.pointerEvent,
this.pointCount = 1,
}) : assert(scale != null && scale >= 0.0),
assert(rotation != null);
/// The focal point of the pointers in contact with the screen. Reported in
/// global coordinates.
final Offset focalPoint;
/// The scale implied by the pointers in contact with the screen. A value
/// greater than or equal to zero.
final double scale;
/// The angle implied by the first two pointers to enter in contact with
/// the screen. Expressed in radians.
final double rotation;
final PointerEvent pointerEvent;
final int pointCount;
@override
String toString() =>
'ScaleUpdateDetails(focalPoint: $focalPoint, scale: $scale, rotation: $rotation, pointerEvent: $pointerEvent, pointCount: $pointCount)';
}
/// Details for [GestureScaleEndCallback].
class ScaleEndDetails {
/// Creates details for [GestureScaleEndCallback].
///
/// The [velocity] argument must not be null.
ScaleEndDetails({this.velocity = Velocity.zero}) : assert(velocity != null);
/// The velocity of the last pointer to be lifted off of the screen.
final Velocity velocity;
@override
String toString() => 'ScaleEndDetails(velocity: $velocity)';
}
/// Signature for when the pointers in contact with the screen have established
/// a focal point and initial scale of 1.0.
typedef GestureScaleStartCallback = void Function(ScaleStartDetails details);
/// Signature for when the pointers in contact with the screen have indicated a
/// new focal point and/or scale.
typedef GestureScaleUpdateCallback = void Function(ScaleUpdateDetails details);
/// Signature for when the pointers are no longer in contact with the screen.
typedef GestureScaleEndCallback = void Function(ScaleEndDetails details);
bool _isFlingGesture(Velocity velocity) {
assert(velocity != null);
final double speedSquared = velocity.pixelsPerSecond.distanceSquared;
return speedSquared > kMinFlingVelocity * kMinFlingVelocity;
}
/// Defines a line between two pointers on screen.
///
/// [_LineBetweenPointers] is an abstraction of a line between two pointers in
/// contact with the screen. Used to track the rotation of a scale gesture.
class _LineBetweenPointers {
/// Creates a [_LineBetweenPointers]. None of the [pointerStartLocation], [pointerStartId]
/// [pointerEndLocation] and [pointerEndId] must be null. [pointerStartId] and [pointerEndId]
/// should be different.
_LineBetweenPointers(
{this.pointerStartLocation = Offset.zero,
this.pointerStartId = 0,
this.pointerEndLocation = Offset.zero,
this.pointerEndId = 1})
: assert(pointerStartLocation != null && pointerEndLocation != null),
assert(pointerStartId != null && pointerEndId != null),
assert(pointerStartId != pointerEndId);
// The location and the id of the pointer that marks the start of the line.
final Offset pointerStartLocation;
final int pointerStartId;
// The location and the id of the pointer that marks the end of the line.
final Offset pointerEndLocation;
final int pointerEndId;
}
/// Recognizes a scale gesture.
///
/// [ScaleGestureRecognizer] tracks the pointers in contact with the screen and
/// calculates their focal point, indicated scale, and rotation. When a focal
/// pointer is established, the recognizer calls [onStart]. As the focal point,
/// scale, rotation change, the recognizer calls [onUpdate]. When the pointers
/// are no longer in contact with the screen, the recognizer calls [onEnd].
class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
/// Create a gesture recognizer for interactions intended for scaling content.
ScaleGestureRecognizer({Object debugOwner}) : super(debugOwner: debugOwner);
/// The pointers in contact with the screen have established a focal point and
/// initial scale of 1.0.
GestureScaleStartCallback onStart;
/// The pointers in contact with the screen have indicated a new focal point
/// and/or scale.
GestureScaleUpdateCallback onUpdate;
/// The pointers are no longer in contact with the screen.
GestureScaleEndCallback onEnd;
_ScaleState _state = _ScaleState.ready;
Offset _initialFocalPoint;
Offset _currentFocalPoint;
double _initialSpan;
double _currentSpan;
_LineBetweenPointers _initialLine;
_LineBetweenPointers _currentLine;
Map<int, Offset> _pointerLocations;
List<int> _pointerQueue;
int pointCount = 0;
bool isOnlyOnePoint = true; // 表示
/// --------------------------DoubleTap-start--------------------------
/// Called when the user has tapped the screen at the same location twice in
/// quick succession.
GestureDoubleTapCallback onDoubleTap;
/// is track pointer
/// 是否追踪手指
bool _isTrackingPointer = false;
bool isFirstTap = true;
/// timer
Timer _doubleTapTimer;
/// start track pointer
/// 开始追踪双击手指
void startDoubleTracking() {
if (!_isTrackingPointer) {
_isTrackingPointer = true;
}
}
/// stop track pointer
/// 停止追踪双击手指
void stopDoubleTracking() {
if (_isTrackingPointer) {
_isTrackingPointer = false;
}
}
/// is two point within tolerance
/// 双击 是否两个点在一个范围内
bool isWithinTolerance(PointerEvent event, double tolerance) {
final Offset offset = event.position - _initialFocalPoint;
return offset.distance <= tolerance;
}
void _reset() {
_stopDoubleTapTimer();
if (!isFirstTap) {
// Note, order is important below in order for the resolve -> reject logic
// to work properly.
isFirstTap = true;
}
}
void _registerFirstTap() {
_startDoubleTapTimer();
// Note, order is important below in order for the clear -> reject logic to
// work properly.
isFirstTap = false;
}
void _registerSecondTap(PointerEvent event) {
if (onDoubleTap != null)
invokeCallback<void>(
'onDoubleTap', () => onDoubleTap(DoubleDetails(pointerEvent: event)));
_reset();
}
void _startDoubleTapTimer() {
_doubleTapTimer ??= Timer(kDoubleTapTimeout, _reset);
}
void _stopDoubleTapTimer() {
if (_doubleTapTimer != null) {
_doubleTapTimer.cancel();
_doubleTapTimer = null;
}
}
void _reject() {
if (!isFirstTap) _reset();
}
void _doubleTapAddPoniter(PointerEvent event) {
_stopDoubleTapTimer();
if (event is PointerUpEvent) {
if (isFirstTap) {
_registerFirstTap();
} else {
_registerSecondTap(event);
}
} else if (event is PointerMoveEvent) {
if (!isWithinTolerance(event, kDoubleTapTouchSlop)) _reject();
} else if (event is PointerCancelEvent) {
_reject();
}
}
/// --------------------------DoubleTap-end--------------------------
/// A queue to sort pointers in order of entrance
final Map<int, VelocityTracker> _velocityTrackers = <int, VelocityTracker>{};
double get _scaleFactor =>
_initialSpan > 0.0 ? _currentSpan / _initialSpan : 1.0;
double _computeRotationFactor() {
if (_initialLine == null || _currentLine == null) {
return 0.0;
}
final double fx = _initialLine.pointerStartLocation.dx;
final double fy = _initialLine.pointerStartLocation.dy;
final double sx = _initialLine.pointerEndLocation.dx;
final double sy = _initialLine.pointerEndLocation.dy;
final double nfx = _currentLine.pointerStartLocation.dx;
final double nfy = _currentLine.pointerStartLocation.dy;
final double nsx = _currentLine.pointerEndLocation.dx;
final double nsy = _currentLine.pointerEndLocation.dy;
final double angle1 = math.atan2(fy - sy, fx - sx);
final double angle2 = math.atan2(nfy - nsy, nfx - nsx);
return angle2 - angle1;
}
@override
void addPointer(PointerEvent event) {
startTrackingPointer(event.pointer);
_velocityTrackers[event.pointer] = VelocityTracker();
if (_state == _ScaleState.ready) {
_state = _ScaleState.possible;
_initialSpan = 0.0;
_currentSpan = 0.0;
_pointerLocations = <int, Offset>{};
_pointerQueue = <int>[];
}
_doubleTapAddPoniter(event);
// else if (_state == _ScaleState.accepted && _pointerQueue.length == 0) {
// resolve(GestureDisposition.accepted);
// }
}
@override
void handleEvent(PointerEvent event) {
assert(_state != _ScaleState.ready);
bool didChangeConfiguration = false;
bool shouldStartIfAccepted = false;
if (event is PointerMoveEvent) {
final VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null);
if (!event.synthesized)
tracker.addPosition(event.timeStamp, event.position);
_pointerLocations[event.pointer] = event.position;
shouldStartIfAccepted = true;
pointCount = _pointerLocations.keys.length;
if (pointCount <= 1 && onUpdate != null && isOnlyOnePoint && !isFirstTap)
invokeCallback<void>(
'onUpdate',
() => onUpdate(ScaleUpdateDetails(
scale: _scaleFactor,
focalPoint: _currentFocalPoint,
rotation: _computeRotationFactor(),
pointerEvent: event,
pointCount: pointCount)));
} else if (event is PointerDownEvent) {
isOnlyOnePoint = _pointerQueue.length == 0;
_pointerLocations[event.pointer] = event.position;
_pointerQueue.add(event.pointer);
didChangeConfiguration = true;
shouldStartIfAccepted = true;
} else if (event is PointerUpEvent || event is PointerCancelEvent) {
_pointerLocations.remove(event.pointer);
_pointerQueue.remove(event.pointer);
didChangeConfiguration = true;
}
_updateLines();
_update();
if (!didChangeConfiguration || _reconfigure(event.pointer)) {
_advanceStateMachine(shouldStartIfAccepted, event);
}
stopTrackingIfPointerNoLongerDown(event);
}
void _update() {
final int count = _pointerLocations.keys.length;
// Compute the focal point
Offset focalPoint = Offset.zero;
for (int pointer in _pointerLocations.keys)
focalPoint += _pointerLocations[pointer];
_currentFocalPoint =
count > 0 ? focalPoint / count.toDouble() : Offset.zero;
// Span is the average deviation from focal point
double totalDeviation = 0.0;
for (int pointer in _pointerLocations.keys)
totalDeviation +=
(_currentFocalPoint - _pointerLocations[pointer]).distance;
_currentSpan = count > 0 ? totalDeviation / count : 0.0;
}
/// Updates [_initialLine] and [_currentLine] accordingly to the situation of
/// the registered pointers
void _updateLines() {
final int count = _pointerLocations.keys.length;
assert(_pointerQueue.length >= count);
/// In case of just one pointer registered, reconfigure [_initialLine]
if (count < 2) {
_initialLine = _currentLine;
} else if (_initialLine != null &&
_initialLine.pointerStartId == _pointerQueue[0] &&
_initialLine.pointerEndId == _pointerQueue[1]) {
/// Rotation updated, set the [_currentLine]
_currentLine = _LineBetweenPointers(
pointerStartId: _pointerQueue[0],
pointerStartLocation: _pointerLocations[_pointerQueue[0]],
pointerEndId: _pointerQueue[1],
pointerEndLocation: _pointerLocations[_pointerQueue[1]]);
} else {
/// A new rotation process is on the way, set the [_initialLine]
_initialLine = _LineBetweenPointers(
pointerStartId: _pointerQueue[0],
pointerStartLocation: _pointerLocations[_pointerQueue[0]],
pointerEndId: _pointerQueue[1],
pointerEndLocation: _pointerLocations[_pointerQueue[1]]);
_currentLine = null;
}
}
bool _reconfigure(int pointer) {
_initialFocalPoint = _currentFocalPoint;
_initialSpan = _currentSpan;
_initialLine = _currentLine;
if (_state == _ScaleState.started) {
if (onEnd != null) {
final VelocityTracker tracker = _velocityTrackers[pointer];
assert(tracker != null);
Velocity velocity = tracker.getVelocity();
if (_isFlingGesture(velocity)) {
final Offset pixelsPerSecond = velocity.pixelsPerSecond;
if (pixelsPerSecond.distanceSquared >
kMaxFlingVelocity * kMaxFlingVelocity)
velocity = Velocity(
pixelsPerSecond: (pixelsPerSecond / pixelsPerSecond.distance) *
kMaxFlingVelocity);
invokeCallback<void>(
'onEnd', () => onEnd(ScaleEndDetails(velocity: velocity)));
} else {
invokeCallback<void>(
'onEnd', () => onEnd(ScaleEndDetails(velocity: Velocity.zero)));
}
}
_state = _ScaleState.accepted;
return false;
}
return true;
}
void _advanceStateMachine(
bool shouldStartIfAccepted, PointerEvent pointerEvent) {
if (_state == _ScaleState.ready) _state = _ScaleState.possible;
if (_state == _ScaleState.possible) {
final double spanDelta = (_currentSpan - _initialSpan).abs();
final double focalPointDelta =
(_currentFocalPoint - _initialFocalPoint).distance;
if (spanDelta > kScaleSlop || focalPointDelta > kPanSlop)
resolve(GestureDisposition.accepted);
} else if (_state.index >= _ScaleState.accepted.index) {
resolve(GestureDisposition.accepted);
}
if (_state == _ScaleState.accepted && shouldStartIfAccepted) {
_state = _ScaleState.started;
_dispatchOnStartCallbackIfNeeded();
}
// if (_state == _ScaleState.started && onUpdate != null)
if (_state == _ScaleState.started && onUpdate != null)
invokeCallback<void>(
'onUpdate',
() => onUpdate(ScaleUpdateDetails(
scale: _scaleFactor,
focalPoint: _currentFocalPoint,
rotation: _computeRotationFactor(),
pointerEvent: pointerEvent,
pointCount: pointCount)));
}
void _dispatchOnStartCallbackIfNeeded() {
assert(_state == _ScaleState.started);
if (onStart != null)
invokeCallback<void>('onStart',
() => onStart(ScaleStartDetails(focalPoint: _currentFocalPoint)));
}
@override
void acceptGesture(int pointer) {
resolve(GestureDisposition.accepted);
if (_state == _ScaleState.possible) {
_state = _ScaleState.started;
_dispatchOnStartCallbackIfNeeded();
}
}
@override
void rejectGesture(int pointer) {
stopTrackingPointer(pointer);
}
@override
void didStopTrackingLastPointer(int pointer) {
switch (_state) {
case _ScaleState.possible:
resolve(GestureDisposition.rejected);
break;
case _ScaleState.ready:
assert(false); // We should have not seen a pointer yet
break;
case _ScaleState.accepted:
break;
case _ScaleState.started:
assert(false); // We should be in the accepted state when user is done
break;
}
_state = _ScaleState.ready;
}
@override
void dispose() {
_velocityTrackers.clear();
_reset();
super.dispose();
}
@override
String get debugDescription => 'scale';
}
import 'package:flutter/material.dart';
import './custom_gesture_detector.dart' as gd;
class ScaleChangedModel {
double scale;
Offset offset;
ScaleChangedModel({this.scale, this.offset});
@override
String toString() {
return 'ScaleChangedModel(scale: $scale, offset:$offset)';
}
}
class TouchableContainer extends StatefulWidget {
final Widget child;
final bool doubleTapStillScale;
///用来约束图和坐标轴的
///因为坐标轴和图是堆叠起来的,图在坐标轴的内部,需要制定margin,否则放大后图会超出坐标轴
final EdgeInsets margin;
ValueChanged<ScaleChangedModel> scaleChanged;
final Function(DragDownDetails details) _onPanDown;
TouchableContainer(this._onPanDown,
{this.child,
EdgeInsets margin,
this.scaleChanged,
this.doubleTapStillScale})
: this.margin = margin ?? EdgeInsets.all(0);
_TouchableContainerState createState() => _TouchableContainerState();
}
class _TouchableContainerState extends State<TouchableContainer>
with SingleTickerProviderStateMixin {
double _kMinFlingVelocity = 800.0;
AnimationController _controller;
Animation<Offset> _flingAnimation;
Offset _offset = Offset.zero;
double _scale = 1.0;
Offset _normalizedOffset;
double _previousScale;
Offset doubleDownPositon;
@override
void initState() {
super.initState();
_controller = new AnimationController(vsync: this)
..addListener(_handleFlingAnimation);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
// The maximum offset value is 0,0. If the size of this renderer's box is w,h
// then the minimum offset value is w - _scale * w, h - _scale * h.
//也就是最小值是原点0,0,点从最大值到0的区间,也就是这个图可以从最大值移动到原点
Offset _clampOffset(Offset offset) {
final Size size = context.size; //容器的大小
final Offset minOffset =
new Offset(size.width, size.height) * (1.0 - _scale);
return new Offset(
offset.dx.clamp(minOffset.dx, 0.0), offset.dy.clamp(minOffset.dy, 0.0));
}
void _handleFlingAnimation() {
setState(() {
_offset = _flingAnimation.value;
});
}
void _handleOnScaleStart(gd.ScaleStartDetails details) {
setState(() {
_previousScale = _scale;
_normalizedOffset = (details.focalPoint - _offset) / _scale;
// The fling animation stops if an input gesture starts.
_controller.stop();
});
}
void _handleOnScaleUpdate(gd.ScaleUpdateDetails details) {
setState(() {
if (details.pointCount > 1) {
_scale = (_previousScale * details.scale).clamp(1.0, double.infinity);
}
// Ensure that image location under the focal point stays in the same place despite scaling.
_offset = _clampOffset(details.focalPoint - _normalizedOffset * _scale);
});
ScaleChangedModel model =
new ScaleChangedModel(scale: _scale, offset: _offset);
if (widget.scaleChanged != null) widget.scaleChanged(model);
}
void _handleOnScaleEnd(gd.ScaleEndDetails details) {
final double magnitude = details.velocity.pixelsPerSecond.distance;
if (magnitude < _kMinFlingVelocity) return;
final Offset direction = details.velocity.pixelsPerSecond / magnitude;
final double distance = (Offset.zero & context.size).shortestSide;
_flingAnimation = new Tween<Offset>(
begin: _offset, end: _clampOffset(_offset + direction * distance))
.animate(_controller);
_controller
..value = 0.0
..fling(velocity: magnitude / 1000.0);
}
void _onDoubleTap(gd.DoubleDetails details) {
_normalizedOffset = (details.pointerEvent.position - _offset) / _scale;
if (!widget.doubleTapStillScale && _scale != 1.0) {
setState(() {
_scale = 1.0;
_offset = Offset.zero;
});
return;
}
setState(() {
if (widget.doubleTapStillScale) {
_scale *= (1 + 0.2);
} else {
_scale *= (2);
}
// Ensure that image location under the focal point stays in the same place despite scaling.
// _offset = doubleDownPositon;
_offset = _clampOffset(
details.pointerEvent.position - _normalizedOffset * _scale);
});
ScaleChangedModel model =
new ScaleChangedModel(scale: _scale, offset: _offset);
if (widget.scaleChanged != null) widget.scaleChanged(model);
}
@override
Widget build(BuildContext context) {
return new gd.GestureDetector(
onPanDown: widget._onPanDown,
onDoubleTap: _onDoubleTap,
onScaleStart: _handleOnScaleStart,
onScaleUpdate: _handleOnScaleUpdate,
// onScaleEnd: _handleOnScaleEnd,
child: Container(
margin: widget.margin,
constraints: const BoxConstraints(
minWidth: double.maxFinite,
minHeight: double.infinity,
),
child: new Transform(
transform: new Matrix4.identity()
..translate(_offset.dx, _offset.dy)
..scale(_scale, _scale, 1.0),
child: widget.child),
),
);
}
}
library flutter_drag_scale;
export './core/drag_scale_widget.dart';
/*
* @author lsy
* @date 2019-10-24
**/
import 'package:event_bus/event_bus.dart';
class GlobalEventBus{
EventBus event;
factory GlobalEventBus() => _getInstance();
static GlobalEventBus get instance => _getInstance();
static GlobalEventBus _instance;
GlobalEventBus._internal() {
// 创建对象
event = EventBus();
}
static GlobalEventBus _getInstance() {
if (_instance == null) {
_instance = GlobalEventBus._internal();
}
return _instance;
}
}
\ No newline at end of file
/*
* @author lsy
* @date 2019-10-24
**/
class LoginEvent {
final String userID;
final String cookie;
LoginEvent(this.userID, this.cookie);
}
/*
* @author lsy
* @date 2019-10-24
**/
class SyncMessageEvent {
SyncMessageEvent();
}
import 'package:flutter/material.dart';
// The base class for the different types of items the list can contain.
abstract class ListItem {}
\ No newline at end of file
/*
* @author lsy
* @date 2019-09-05
**/
import 'dart:async';
import 'package:rxdart/rxdart.dart';
abstract class BaseModel {
//TODO
void dispose();
}
/*
* @author lsy
* @date 2019-09-05
**/
import 'dart:async';
class LiveData<T> {
StreamController<T> _controller;
T data;
LiveData() {
print("!!!! ${_controller == null}");
this._controller = new StreamController<T>();
}
get stream => _controller.stream;
get controller => _controller;
void notifyView(T t) {
this.data = t;
_controller.sink.add(t);
}
void dispost() {
data = null;
_controller.close();
}
}
import 'package:dio/dio.dart';
import 'dart:async';
import 'dart:convert';
class NetworkSuccess {
NetworkSuccess({this.data});
final Map data;
Map get dataMap{
if (this.data.runtimeType == Map) {
return data;
}else return null;
}
}
class NetworkError {
NetworkError({this.error});
final Map error;
int get errorCode{
if (this.error.runtimeType == Map) {
return error['errorCode'];
}else return null;
}
}
class ALURL {
ALURL({this.api}) : assert(api != null);
final String api;
static final baseUrl = 'http://earth.igengmei.com';
String get originUrl => (baseUrl + api);
}
class ALNetworkHeader {
BaseOptions get options{
BaseOptions option = BaseOptions();
option.headers =this.header;
return option;
}
Map<String, dynamic> get header{
return {
'Host': 'earth.igengmei.com',
'Accept': '*/*',
'Cookie': '_gm_token=fb20fe1550833249; sessionid=qntnckxv4n4nzrl49jmaesc5ylru92yt; _gtid=ae355f92310911e9905700163e0a7a995288',
'User-Agent': 'GMAlpha/1.3.0 (iPhone; iOS 12.1.2; Scale/2.00)',
'Accept-Language': 'en-CN;q=1, zh-Hans-CN;q=0.9',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive'
};
}
Map<String, dynamic> get params {
return {
'platform': 'iPhone',
'os_version':'12.1.2',
'version':'1.3.0',
'model':'iPhone%206s',
'release':'0',
'idfa':'119A3567-6C81-40EA-A3ED-A63F7DCAD86B',
'idfv':'78BE2D94-7252-4C18-A816-2CEE6350B076',
'device_id':'119A3567-6C81-40EA-A3ED-A63F7DCAD86B',
'channel':'App%20Store',
'app_name':'gengmeiios',
'current_city_id':'worldwide',
'lat':'0',
'lng':'0',
'is_WiFi':'(null)',
'phone_id':'iPhone8'
};
}
}
// 管理任务
class ALNetworkTask {
ALNetworkTask({this.serviceInstance,this.networkContext, this.response});
final Dio serviceInstance;
final ALNetwork networkContext;
Response response;
void cancle(String api) {
// CancelToken
}
}
typedef NetworkSuccessCallback = void Function(NetworkSuccess success);
typedef NetWorkErrorCallback = void Function(NetworkError error);
typedef ProgressCallback = void Function(int count, int total);
class ALNetwork {
/**
* 任务映射表
* 外部可以通过 ALNetwork.taskMap 获取
*/
static Map<String, ALNetworkTask> taskMap = {};
const ALNetwork(
{this.success,
this.error,
this.progress,
this.api,
this.params,
this.formData}) : assert(api != null);
final NetworkSuccessCallback success;
final NetWorkErrorCallback error;
final ProgressCallback progress;
final String api;
final Map params;
final FormData formData;
ALURL get url => ALURL(api: this.api);
///post
Future<void> post() async{
ALNetworkTask task = _initNetworkEngin();
task.response = await task.serviceInstance.post(this.url.originUrl, data: this.params);
_handleNetworkService(task.response);
}
/**
* FormData formData = new FormData.from({
"name": "simon",
"age": 25,
});
*/
Future<void> postFormData() async{
ALNetworkTask task = _initNetworkEngin();
task.response = await task.serviceInstance.post(this.url.originUrl, data: this.formData);
_handleNetworkService(task.response);
}
///get
Future<void> excuteGet() async{
ALNetworkTask task = _initNetworkEngin();
task.response = await task.serviceInstance.get(this.url.originUrl, queryParameters: ALNetworkHeader().params);
_handleNetworkService(task.response);
}
/**
* FormData formData = new FormData.from({
"name": "wendux",
"age": 25,
"file1": new UploadFileInfo(new File("./upload.txt"), "upload1.txt"),
// upload with bytes (List<int>)
"file2": new UploadFileInfo.fromBytes(
utf8.encode("hello world"), "word.txt"),
// Pass multiple files within an Array
"files": [
new UploadFileInfo(new File("./example/upload.txt"), "upload.txt"),
new UploadFileInfo(new File("./example/upload.txt"), "upload.txt")
]
});
*/
Future<void> upload() async{
ALNetworkTask task = _initNetworkEngin();
task.response = await task.serviceInstance.post(this.url.originUrl, data: this.formData,onSendProgress: this.progress);
_handleNetworkService(task.response);
}
///download
Future<void> download(String filePath) async{
ALNetworkTask task = _initNetworkEngin();
task.response = await task.serviceInstance.download(this.url.originUrl, filePath, onReceiveProgress: this.progress);
_handleNetworkService(task.response);
}
ALNetworkTask _initNetworkEngin(){
Response response;
Dio dio = new Dio();
dio.options = ALNetworkHeader().options;
ALNetworkTask task = ALNetworkTask(
serviceInstance:dio,
response: response,
networkContext: this
);
//handle task
taskMap[this.api] = task;
return task;
}
void _handleNetworkService(Response response) {
var data = jsonDecode(response.toString());
if(data.runtimeType ==Map && response.statusCode == 200){
if (data['error'] == 0){
this.success(NetworkSuccess(data: data));
}else{
this.error(NetworkError(error: data));
}
}else{
this.error(NetworkError(error: data));
}
//remove task
taskMap.remove(this.api);
}
}
\ No newline at end of file
/*
* @author lsy
* @date 2019-09-16
**/
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:example_flutter/commonModel/net/DioUtil.dart';
/**
* 生产环境
*/
const String APP_HOST_RELEASE = "https://earth.iyanzhi.com";
/**
* 测试环境
*/
const String APP_HOST_DEBUG = "http://earth.gmapp.env";
/**
* 开发环境
*/
const String APP_HOST_DEV = "http://earth.alpha.newdev";
class Api {
static String BUILD_CONFIG;
static String PROVIDER_NAME;
static Api intance = new Api._();
Api._();
static Api getInstance() {
return intance;
}
bool initBuildConfig(Map params) {
if (params == null) {
return false;
}
String buildConfig = params["buildConfig"];
if (buildConfig == null) {
return false;
}
BUILD_CONFIG = buildConfig;
PROVIDER_NAME = params["provider"];
String baseUrl = getBaseUrl(buildConfig) + "/";
if (baseUrl == null) {
return false;
}
if (buildConfig == "debug" || buildConfig == "dev") {
String httpProxy = params["proxy"];
if (httpProxy != null && httpProxy.isNotEmpty) {
print("PROXY --> $httpProxy");
DioUtil().setProxy(httpProxy);
}
}
print("baseUrl --> $baseUrl");
DioUtil().setConfig(HttpConfig(
options: BaseOptions(
baseUrl: baseUrl,
),
nativeCookie: {"Cookie": params["Cookie"]}));
return true;
}
bool setDioCookie(Map params) {
if (params == null) {
return false;
}
var cookie = params["cookie"] == null ? params["Cookie"] : params["cookie"];
if (cookie == null) {
return false;
}
DioUtil().setCookie(cookie);
return true;
}
String getBaseUrl(String string) {
if (string == "debug") {
return APP_HOST_DEBUG;
} else if (string == "dev") {
return APP_HOST_DEV;
} else if (string == "release") {
return APP_HOST_RELEASE;
} else {
return null;
}
}
}
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:example_flutter/commonModel/cache/CacheManager.dart';
import 'package:example_flutter/commonModel/net/Api.dart';
const bool inProduction = const bool.fromEnvironment("dart.vm.product");
///Http配置.
class HttpConfig {
/// constructor.
HttpConfig({
this.status,
this.code,
this.msg,
this.data,
this.options,
this.pem,
this.pKCSPath,
this.pKCSPwd,
this.nativeCookie,
});
/// BaseResp [String status]字段 key, 默认:status.
String status;
/// BaseResp [int code]字段 key, 默认:errorCode.
String code;
/// BaseResp [String msg]字段 key, 默认:errorMsg.
String msg;
/// BaseResp [T data]字段 key, 默认:data.
String data;
/// Options.
BaseOptions options;
/// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验.
/// PEM证书内容.
String pem;
/// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验.
/// PKCS12 证书路径.
String pKCSPath;
/// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验.
/// PKCS12 证书密码.
String pKCSPwd;
//缓存
Map nativeCookie;
}
/// 单例 DioUtil.
/// debug模式下可以打印请求日志. DioUtil.openDebug().
/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio).
class DioUtil {
static final DioUtil _instance = DioUtil._init();
static Dio _dio;
/// BaseResp [String status]字段 key, 默认:status.
String _statusKey = "status";
/// BaseResp [int code]字段 key, 默认:error = 0 代表成功.
String _codeKey = "error";
/// BaseResp [String msg]字段 key, 默认:errorMsg.
String _msgKey = "message";
/// BaseResp [T data]字段 key, 默认:data.
String _dataKey = "data";
/// BaseResp [T data]字段 key, 默认:extra.
String _extraKey = 'extra';
// BaseResp [T data]字段 key, 默认:user_type.
String _userType = 'user_type';
/// Options.
static BaseOptions _options = getDefOptions();
/// PEM证书内容.
String _pem;
/// PKCS12 证书路径.
String _pKCSPath;
/// PKCS12 证书密码.
String _pKCSPwd;
String _proxy = '172.30.9.117:8888';
static Map<String, dynamic> addHeadMap;
/// 是否是debug模式.
static bool _isDebug = !inProduction;
static DioUtil getInstance() {
return _instance;
}
factory DioUtil() {
return _instance;
}
static var interceptor = InterceptorsWrapper(onRequest: (opt) {
var headers = opt.headers;
if (headers == null) {
opt.headers = Map();
}
if (CacheManager.getInstance().get(MEMORY_CACHE).get("token") != null) {
opt.headers.putIfAbsent(
"Authorization",
() =>
"Token " +
CacheManager.getInstance().get(MEMORY_CACHE).get("token"));
opt.headers
.putIfAbsent("Content-Type", () => "application/json;charset=UTF-8");
}
// var queryParameters = opt.queryParameters;
// Map<String, dynamic> map;
// if (queryParameters != null) {
// map = queryParameters;
// } else {
// map = new Map<String, dynamic>();
// }
// map.putIfAbsent(
// "app_name",
// () =>
// CacheManager.getInstance().get(MEMORY_CACHE).get("app_name") ?? '');
// map.putIfAbsent(
// "version",
// () =>
// CacheManager.getInstance().get(MEMORY_CACHE).get("version") ?? "");
// map.putIfAbsent("platform", () => Platform.isAndroid ? "android" : "ios");
// map.putIfAbsent(
// "device_id",
// () =>
// CacheManager.getInstance().get(MEMORY_CACHE).get("device_id") ??
// "");
// map.putIfAbsent(
// "os_version",
// () =>
// CacheManager.getInstance().get(MEMORY_CACHE).get("os_version") ??
// "");
// map.putIfAbsent("model",
// () => CacheManager.getInstance().get(MEMORY_CACHE).get("model") ?? "");
// map.putIfAbsent("lat",
// () => CacheManager.getInstance().get(MEMORY_CACHE).get("lat") ?? "");
// map.putIfAbsent("lng",
// () => CacheManager.getInstance().get(MEMORY_CACHE).get("lng") ?? "");
// map.putIfAbsent(
// "channel",
// () =>
// CacheManager.getInstance().get(MEMORY_CACHE).get("channel") ?? "");
// map.putIfAbsent(
// "current_city_id",
// () =>
// CacheManager.getInstance()
// .get(MEMORY_CACHE)
// .get("current_city_id") ??
// "");
// map.putIfAbsent(
// "manufacturer",
// () =>
// CacheManager.getInstance().get(MEMORY_CACHE).get("manufacturer") ??
// "");
// map.putIfAbsent("uuid",
// () => CacheManager.getInstance().get(MEMORY_CACHE).get("uuid") ?? "");
// opt.queryParameters = map;map
}, onResponse: (response) {
print("响应之前 response${response}");
}, onError: (e) {
print("网络错误 $e message ${e.message}");
});
DioUtil._init() {
_dio = new Dio(_options);
_dio.interceptors.add(interceptor);
}
void setProxy(String proxy) {
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
client.findProxy = (url) {
return 'PROXY $proxy';
};
};
}
/// set Config.
void setConfig(HttpConfig config) {
_statusKey = config.status ?? _statusKey;
_codeKey = config.code ?? _codeKey;
_msgKey = config.msg ?? _msgKey;
_dataKey = config.data ?? _dataKey;
_mergeOption(config.options);
_mergeNativeCookie(config);
_pem = config.pem ?? _pem;
if (_dio != null) {
_dio.options = _options;
// (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
// client.findProxy = (url) {
// return _isDebug ? 'PROXY $_proxy' : 'DIRECT';
// };
// };
if (_pem != null) {
// httpClientAdapter
(_dio.httpClientAdapter as DefaultHttpClientAdapter)
.onHttpClientCreate = (client) {
client.badCertificateCallback =
(X509Certificate cert, String host, int port) {
if (cert.pem == _pem) {
// 证书一致,则放行
return true;
}
return false;
};
};
}
if (_pKCSPath != null) {
(_dio.httpClientAdapter as DefaultHttpClientAdapter)
.onHttpClientCreate = (client) {
SecurityContext sc = new SecurityContext();
//file为证书路径
sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd);
HttpClient httpClient = new HttpClient(context: sc);
return httpClient;
};
}
}
}
/*
* get请求
*/
Future<Response> get(url, {data, options, cancelToken}) async {
Response response;
print("GET===> URL:$url data:$data");
try {
response = await _dio.get(url,
queryParameters: data, options: options, cancelToken: cancelToken);
// print('get success---------${response.statusCode}');
// print('get success---------${response.data}');
_printHttpLog(response);
// response.data; 响应体
// response.headers; 响应头
// response.request; 请求体
// response.statusCode; 状态码
} on DioError catch (e) {
print('get error---------$e formatError');
formatError(e);
}
return response;
}
/*
* post请求
*/
Future<Response> post(url, {data, options, cancelToken}) async {
Response response;
print("POST===> URL:$url data:$data");
try {
response = await _dio.post(url,
data: FormData.from(data),
options: options,
cancelToken: cancelToken);
print('post success---------${response.statusCode} ${response.data}');
} on DioError catch (e) {
print('post error---------$e message${e.message}');
formatError(e);
}
return response;
}
Future<Response> uploadFile(String url, String path) async {
var name = path.substring(path.lastIndexOf("/") + 1, path.length);
FormData formdata =
FormData.from({"file": new UploadFileInfo(new File(path), name)});
Response response;
try {
response = await _dio.post(
url,
data: formdata,
);
print(
'uploadFile success---------${response.statusCode} ${response.data}');
} on DioError catch (e) {
print('uploadFile error---------$e message${e.message}');
formatError(e);
}
return response;
}
/*
* 下载文件
*/
downloadFile(urlPath, savePath) async {
Response response;
try {
response = await _dio.download(urlPath, savePath,
onReceiveProgress: (int count, int total) {
//进度
print("$count $total");
});
print('downloadFile success---------${response.data}');
} on DioError catch (e) {
print('downloadFile error---------$e formatError');
formatError(e);
}
return response.data;
}
void formatError(DioError e) {
String reason = "";
if (e.type == DioErrorType.CONNECT_TIMEOUT) {
// It occurs when url is opened timeout.
print("连接超时");
reason = "连接超时 ${e.message}";
} else if (e.type == DioErrorType.SEND_TIMEOUT) {
// It occurs when url is sent timeout.
print("请求超时");
reason = "请求超时 ${e.message}";
} else if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
//It occurs when receiving timeout
print("响应超时");
reason = "响应超时 ${e.message}";
} else if (e.type == DioErrorType.RESPONSE) {
// When the server response, but with a incorrect status, such as 404, 503...
print("出现异常");
reason = "出现异常 ${e.message}";
} else if (e.type == DioErrorType.CANCEL) {
// When the request is cancelled, dio will throw a error with this type.
print("请求取消");
reason = "请求取消 ${e.message}";
} else {
//DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null.
print("未知错误");
reason = "未知错误 ${e.message}";
}
throw HttpException(reason);
}
Future<Response> download(
String urlPath,
savePath, {
CancelToken cancelToken,
data,
Options options,
}) {
return _dio.download(urlPath, savePath,
cancelToken: cancelToken, data: data, options: options);
}
/// check Options.
Options _checkOptions(method, options) {
if (options == null) {
options = new Options();
}
options.method = method;
return options;
}
/// merge Option.
void _mergeOption(BaseOptions opt) {
_options.method = opt.method ?? _options.method;
_options.headers = (new Map.from(_options.headers))..addAll(opt.headers);
_options.baseUrl = opt.baseUrl ?? _options.baseUrl;
_options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout;
_options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout;
_options.responseType = opt.responseType ?? _options.responseType;
_options.extra = (new Map.from(_options.extra))..addAll(opt.extra);
_options.contentType = opt.contentType ?? _options.contentType;
_options.validateStatus = opt.validateStatus ?? _options.validateStatus;
_options.followRedirects = opt.followRedirects ?? _options.followRedirects;
}
void _mergeNativeCookie(HttpConfig config) {
//合并native cookie
if (config.nativeCookie == null) {
return;
}
if (_options.headers == null) {
_options.headers = Map();
}
Map<String, dynamic> headers = _options.headers;
headers['Cookie'] = config.nativeCookie['Cookie'];
_options.headers = headers;
print('cookie---------');
print(_options.headers);
}
void setCookie(String cookie) {
if (_options.headers == null) {
_options.headers = Map();
}
Map<String, dynamic> headers = _options.headers;
headers['Cookie'] = cookie;
_options.headers = headers;
print('cookie---------');
print(_options.headers);
}
/// print Http Log.
void _printHttpLog(Response response) {
if (!_isDebug) {
return;
}
try {
print("----------------Http Log----------------" +
"\n[statusCode]: " +
response.statusCode.toString() +
"\n[request ]: " +
_getOptionsStr(response.request));
_printDataStr("reqdata ", response.request.data);
_printDataStr("response", response.data);
} catch (ex) {
print("Http Log" + " error......");
}
}
/// get Options Str.
String _getOptionsStr(Options request) {
return "method: " + request.method;
}
/// print Data Str.
void _printDataStr(String tag, Object value) {
String da = value.toString();
while (da.isNotEmpty) {
if (da.length > 512) {
print("[$tag ]: " + da.substring(0, 512));
da = da.substring(512, da.length);
} else {
print("[$tag ]: " + da);
da = "";
}
}
}
/// get dio.
Dio getDio() {
return _dio;
}
/// create new dio.
static Dio createNewDio([Options options]) {
Dio dio = new Dio();
return dio;
}
/// get Def Options.
static BaseOptions getDefOptions() {
BaseOptions options = BaseOptions();
options.connectTimeout = 10 * 1000;
options.receiveTimeout = 20 * 1000;
// options.contentType = ContentType.parse('application/x-www-form-urlencoded');
// options.contentType = ContentType.json;
options.responseType = ResponseType.plain;
options.baseUrl = "http://140.143.214.123/api" + "/";
Map<String, dynamic> headers = Map<String, dynamic>();
headers['Accept'] = 'application/json';
headers['version'] = '1.0.0';
options.headers = headers;
return options;
}
}
/*
* @author lsy
* @date 2019-09-05
**/
class SimpleResponce {
int error;
String message;
Null extra;
Data data;
SimpleResponce({this.error, this.message, this.extra, this.data});
SimpleResponce.fromJson(Map<String, dynamic> json) {
error = json['error'];
message = json['message'];
extra = json['extra'];
data = json['data'] != null ? new Data.fromJson(json['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['error'] = this.error;
data['message'] = this.message;
data['extra'] = this.extra;
if (this.data != null) {
data['data'] = this.data.toJson();
}
return data;
}
}
class Data {
int error;
String message;
Data({this.error, this.message});
Data.fromJson(Map<String, dynamic> json) {
error = json['error'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['error'] = this.error;
data['message'] = this.message;
return data;
}
}
/*
* @author lsy
* @date 2019-10-18
**/
import 'package:example_flutter/commonModel/base/BaseComponent.dart';
import 'package:example_flutter/commonModel/picker/base/DialogRouter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class BaseCenterPicker extends StatefulWidget {
BaseCenterPickerState centerState;
ICenterPicker picker;
bool cancelOutSide = false;
setPicker(ICenterPicker picker) {
this.picker = picker;
}
sync() {
centerState?.setState(() {});
}
setCancelOutside(bool cancel) {
this.cancelOutSide = cancel;
}
show(BuildContext context) {
Navigator.push(context, DialogRouter(this));
}
dismiss(BuildContext context) {
Navigator.pop(context);
}
@override
State<StatefulWidget> createState() {
centerState = BaseCenterPickerState();
return centerState;
}
}
class BaseCenterPickerState extends State<BaseCenterPicker> {
@override
Widget build(BuildContext context) {
// ScreenUtil.instance = ScreenUtil(width: 375, height: 667)..init(context);
return Container(
color: Colors.black54,
width: double.maxFinite,
height: double.maxFinite,
child: Stack(
children: <Widget>[
GestureDetector(
onTap: () {
if (widget.cancelOutSide) {
widget.dismiss(context);
}
},
),
Center(
child: Material(
color: Colors.transparent,
child: widget.picker.build(context),
))
],
),
);
}
}
abstract class ICenterPicker {
Widget build(BuildContext context);
}
/*
* @author lsy
* @date 2019-10-21
**/
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_animation_set/widget/transition_animations.dart';
import 'BaseCenterPicker.dart';
class BaseLoadingItem implements ICenterPicker {
final String loadingText;
BaseLoadingItem(this.loadingText);
@override
Widget build(BuildContext context) {
return new Container(
width: 120.0,
height: 120.0,
child: new Container(
///弹框背景和圆角
decoration: ShapeDecoration(
color: Colors.greenAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new YYWave(),
new Padding(
padding: const EdgeInsets.only(
top: 20.0,
),
child: new Text(
loadingText,
style: new TextStyle(fontSize: 16.0, color: Colors.white),
),
),
],
),
),
);
}
}
/*
* @author lsy
* @date 2019-10-18
**/
import 'package:flutter/material.dart';
class DialogRouter extends PageRouteBuilder {
final Widget page;
DialogRouter(this.page)
: super(
opaque: false,
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return child;
});
}
/*
* @author lsy
* @date 2019-10-18
**/
import 'package:flutter/material.dart';
import 'base/DialogRouter.dart';
Future popLoadingDialog(
BuildContext context, bool canceledOnTouchOutside, String text) {
return Navigator.push(
context, DialogRouter(LoadingDialog(canceledOnTouchOutside, text)));
}
void dismissLoadingDialog(BuildContext context) {
Navigator.pop(context);
}
class LoadingDialog extends Dialog {
LoadingDialog(this.canceledOnTouchOutside, this.text) : super();
///点击背景是否能够退出
final bool canceledOnTouchOutside;
final String text;
@override
Widget build(BuildContext context) {
return Center(
child: new Material(
///背景透明
color: Colors.black54,
///保证控件居中效果
child: Stack(
children: <Widget>[
GestureDetector(
///点击事件
onTap: () {
if (canceledOnTouchOutside) {
Navigator.pop(context);
}
},
),
_dialog()
],
)),
);
}
Widget _dialog() {
return new Center(
///弹框大小
child: new Container(
width: 120.0,
height: 120.0,
child: new Container(
///弹框背景和圆角
decoration: ShapeDecoration(
color: Color(0xffffffff),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8.0),
),
),
),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new CircularProgressIndicator(),
new Padding(
padding: const EdgeInsets.only(
top: 20.0,
),
child: new Text(
text,
style: new TextStyle(fontSize: 16.0),
),
),
],
),
),
),
);
}
}
import 'package:example_flutter/commonModel/GMBase.dart';
import 'package:flutter/material.dart';
class Toast {
static ToastView preToast;
static debugShow(BuildContext context, String msg) {
if (Api.BUILD_CONFIG != "release") {
show(context, msg);
}
}
static show(BuildContext context, String msg) {
if(preToast!=null){
preToast.dismiss();
}
var overlayState = Overlay.of(context);
var controllerShowAnim = new AnimationController(
vsync: overlayState,
duration: Duration(milliseconds: 250),
);
var controllerShowOffset = new AnimationController(
vsync: overlayState,
duration: Duration(milliseconds: 350),
);
var controllerHide = new AnimationController(
vsync: overlayState,
duration: Duration(milliseconds: 250),
);
var opacityAnim1 =
new Tween(begin: 0.0, end: 1.0).animate(controllerShowAnim);
var controllerCurvedShowOffset = new CurvedAnimation(
parent: controllerShowOffset, curve: _BounceOutCurve._());
var offsetAnim =
new Tween(begin: 30.0, end: 0.0).animate(controllerCurvedShowOffset);
var opacityAnim2 = new Tween(begin: 1.0, end: 0.0).animate(controllerHide);
OverlayEntry overlayEntry;
overlayEntry = new OverlayEntry(builder: (context) {
return ToastWidget(
opacityAnim1: opacityAnim1,
opacityAnim2: opacityAnim2,
offsetAnim: offsetAnim,
child: buildToastLayout(msg),
);
});
var toastView = ToastView();
toastView.overlayEntry = overlayEntry;
toastView.controllerShowAnim = controllerShowAnim;
toastView.controllerShowOffset = controllerShowOffset;
toastView.controllerHide = controllerHide;
toastView.overlayState = overlayState;
preToast = toastView;
toastView._show();
}
static LayoutBuilder buildToastLayout(String msg) {
return LayoutBuilder(builder: (context, constraints) {
return IgnorePointer(
ignoring: true,
child: Container(
child: Material(
color: Colors.white.withOpacity(0),
child: Container(
child: Container(
child: Text(
"${msg}",
style: TextStyle(color: Colors.white),
),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.6),
borderRadius: BorderRadius.all(
Radius.circular(5),
),
),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
),
margin: EdgeInsets.only(
bottom: constraints.biggest.height * 0.15,
left: constraints.biggest.width * 0.2,
right: constraints.biggest.width * 0.2,
),
),
),
alignment: Alignment.bottomCenter,
),
);
});
}
}
class ToastView {
OverlayEntry overlayEntry;
AnimationController controllerShowAnim;
AnimationController controllerShowOffset;
AnimationController controllerHide;
OverlayState overlayState;
bool dismissed = false;
_show() async {
overlayState.insert(overlayEntry);
controllerShowAnim.forward();
controllerShowOffset.forward();
await Future.delayed(Duration(milliseconds: 3500));
this.dismiss();
}
dismiss() async {
if (dismissed) {
return;
}
this.dismissed = true;
controllerHide.forward();
await Future.delayed(Duration(milliseconds: 250));
overlayEntry?.remove();
}
}
class ToastWidget extends StatelessWidget {
final Widget child;
final Animation<double> opacityAnim1;
final Animation<double> opacityAnim2;
final Animation<double> offsetAnim;
ToastWidget(
{this.child, this.offsetAnim, this.opacityAnim1, this.opacityAnim2});
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: opacityAnim1,
child: child,
builder: (context, child_to_build) {
return Opacity(
opacity: opacityAnim1.value,
child: AnimatedBuilder(
animation: offsetAnim,
builder: (context, _) {
return Transform.translate(
offset: Offset(0, offsetAnim.value),
child: AnimatedBuilder(
animation: opacityAnim2,
builder: (context, _) {
return Opacity(
opacity: opacityAnim2.value,
child: child_to_build,
);
},
),
);
},
),
);
},
);
}
}
class _BounceOutCurve extends Curve {
const _BounceOutCurve._();
@override
double transform(double t) {
t -= 1.0;
return t * t * ((2 + 1) * t + 2) + 1.0;
}
}
/*
* @author lsy
* @date 2019-11-22
**/
import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
Future<ui.Image> loadNetWorkImage(var path) async {
ImageStream stream = NetworkImage(
path,
).resolve(ImageConfiguration.empty);
Completer<ui.Image> completer = Completer<ui.Image>();
void listener(ImageInfo frame, bool synchronousCall) {
final ui.Image image = frame.image as ui.Image;
completer.complete(image);
stream.removeListener(ImageStreamListener(listener));
}
stream.addListener(ImageStreamListener(listener));
return completer.future;
}
\ No newline at end of file
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import 'package:example_flutter/Annotations/RouterCenterRestore.mark.dart';
import 'package:flutter/foundation.dart'
show debugDefaultTargetPlatformOverride;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:file_chooser/file_chooser.dart';
void main() {
// See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
showSemanticsDebugger: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
// See https://github.com/flutter/flutter/wiki/Desktop-shells#fonts
fontFamily: 'Roboto',
),
home: MyHomePage());
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Widget home;
_MyHomePageState() {
home = RouterCenterImpl().findUserRouter()?.getLoginPage();
}
@override
Widget build(BuildContext context) {
var screenUtil = ScreenUtil(width: 800.0, height: 600.0)..init(context);
return home;
}
}
/*
* @author lsy
* @date 2019-10-15
**/
library GMRes;
export 'anim/Anim.dart';
export 'value/ALColors.dart';
export 'value/ALFont.dart';
/*
* @author lsy
* @date 2019-10-14
**/
import 'dart:io';
import 'package:flutter/material.dart';
enum RouteWay {
SCARE,
TRAN_RIGHT_TO_LEFT,
ALP,
}
class CustomRoute extends PageRouteBuilder {
final Widget widget;
RouteWay routeWay;
CustomRoute(this.widget, {RouteWay routeWay = RouteWay.TRAN_RIGHT_TO_LEFT})
: super(
// 设置过度时间
transitionDuration: Duration(milliseconds: 230),
// 构造器
pageBuilder: (
// 上下文和动画
BuildContext context,
Animation<double> animaton1,
Animation<double> animaton2,
) {
return widget;
},
transitionsBuilder: (
BuildContext context,
Animation<double> animaton1,
Animation<double> animaton2,
Widget child,
) {
// 渐变效果
if (routeWay.index == 2) {
return FadeTransition(
// 从0开始到1
opacity: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
// 传入设置的动画
parent: animaton1,
// 设置效果,快进漫出 这里有很多内置的效果
curve: Curves.fastOutSlowIn,
)),
child: child,
);
} else if (routeWay.index == 1) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0))
.animate(CurvedAnimation(
parent: animaton1, curve: Curves.fastOutSlowIn)),
child: child,
);
// } else {
// return SlideTransition(
// position: Tween<Offset>(
// begin: Offset(0.0, 1.0), end: Offset(0.0, 0.0))
// .animate(CurvedAnimation(
// parent: animaton1, curve: Curves.fastOutSlowIn)),
// child: child,
// );
// }
} else {
return ScaleTransition(
scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: animaton1, curve: Curves.fastOutSlowIn)),
child: child,
);
}
// 旋转加缩放动画效果
// return RotationTransition(
// turns: Tween(begin: 0.0,end: 1.0)
// .animate(CurvedAnimation(
// parent: animaton1,
// curve: Curves.fastOutSlowIn,
// )),
// child: ScaleTransition(
// scale: Tween(begin: 0.0,end: 1.0)
// .animate(CurvedAnimation(
// parent: animaton1,
// curve: Curves.fastOutSlowIn
// )),
// child: child,
// ),
// );
});
}
// Copyright 2019 All rights reserved.
// Authors: Mikasa Authors.
import 'dart:ui' show Color;
import 'package:flutter/painting.dart';
// 关于颜色的定义
// Color(0xFF323232);
// FF 表示透明度 323232 表示RGB颜色值
class ALColors {
ALColors._();
static const Color Color323232 = Color(0xFF323232);
static const Color Color464646 = Color(0xFF464646);
static const Color Color999999 = Color(0xFF999999);
static const Color ColorFFFFFF = Color(0xFFffffff);
static const Color Color8E8E8E = Color(0xFF8e8e8e);
static const Color ColorC4C4C4 = Color(0xFFc4c4c4);
static const Color ColorF8F8F8 = Color(0xFFf8f8f8);
static const Color ColorE4E4E4 = Color(0xFFe4e4e4);
static const Color ColorF4F3F8 = Color(0xFFf4f3f8);
static const Color Color282828 = Color(0xFF282828);
static const Color ColorE5E5E5 = Color(0xFFe5e5e5);
static const Color Color5276F4 = Color(0xFF5276F4);
static const Color Color0093FF = Color(0xFF0093FF);
static const Color Color666666 = Color(0xFF666666);
static const Color Color33000000 = Color(0x33000000);
}
//
// ALFont
//
// gmalpha_flutter
// Created by lxrent on 2019/2/19.
// Copyright © 2019 Gengmei. All rights reserved.
//
/*
* @author lsy
* @date 2019-10-15
**/
const ST_SELECT_COUNTRY = "选择国家";
flutter/ephemeral
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Executable name.
BINARY_NAME=flutter_desktop_example
# Any extra source files to build.
EXTRA_SOURCES=
# Paths of any additional libraries to be bundled in the output directory.
EXTRA_BUNDLED_LIBRARIES=
# Extra flags (e.g., for library dependencies).
SYSTEM_LIBRARIES=
EXTRA_CXXFLAGS=
EXTRA_CPPFLAGS=
EXTRA_LDFLAGS=
# Default build type. For a release build, set BUILD=release.
# Currently this only sets NDEBUG, which is used to control the flags passed
# to the Flutter engine in the example shell, and not the complation settings
# (e.g., optimization level) of the C++ code.
BUILD=debug
FLUTTER_EPHEMERAL_DIR=flutter/ephemeral
# Configuration provided via flutter tool.
FLUTTER_CONFIG_FILE=$(FLUTTER_EPHEMERAL_DIR)/generated_config.mk
include $(FLUTTER_CONFIG_FILE)
# Dependency locations
FLUTTER_APP_DIR=$(CURDIR)/..
FLUTTER_APP_BUILD_DIR=$(FLUTTER_APP_DIR)/build
OUT_DIR=$(FLUTTER_APP_BUILD_DIR)/linux
OBJ_DIR=$(OUT_DIR)/obj/$(BUILD)
# Libraries
FLUTTER_LIB_NAME=flutter_linux_glfw
FLUTTER_LIB=$(FLUTTER_EPHEMERAL_DIR)/lib$(FLUTTER_LIB_NAME).so
# Tools
FLUTTER_BIN=$(FLUTTER_ROOT)/bin/flutter
LINUX_BUILD=$(FLUTTER_ROOT)/packages/flutter_tools/bin/tool_backend.sh
# Resources
ICU_DATA_NAME=icudtl.dat
ICU_DATA_SOURCE=$(FLUTTER_EPHEMERAL_DIR)/$(ICU_DATA_NAME)
FLUTTER_ASSETS_NAME=flutter_assets
FLUTTER_ASSETS_SOURCE=$(FLUTTER_APP_BUILD_DIR)/$(FLUTTER_ASSETS_NAME)
# Bundle structure
BUNDLE_OUT_DIR=$(OUT_DIR)/$(BUILD)
BUNDLE_DATA_DIR=$(BUNDLE_OUT_DIR)/data
BUNDLE_LIB_DIR=$(BUNDLE_OUT_DIR)/lib
BIN_OUT=$(BUNDLE_OUT_DIR)/$(BINARY_NAME)
ICU_DATA_OUT=$(BUNDLE_DATA_DIR)/$(ICU_DATA_NAME)
FLUTTER_LIB_OUT=$(BUNDLE_LIB_DIR)/$(notdir $(FLUTTER_LIB))
ALL_LIBS_OUT=$(FLUTTER_LIB_OUT) \
$(foreach lib,$(EXTRA_BUNDLED_LIBRARIES),$(BUNDLE_LIB_DIR)/$(notdir $(lib)))
# Add relevant code from the wrapper library, which is intended to be statically
# built into the client.
# Use abspath for the wrapper root, which can contain relative paths; the
# intermediate build files will be based on the source path, which will cause
# issues if they start with one or more '../'s.
WRAPPER_ROOT=$(abspath $(FLUTTER_EPHEMERAL_DIR)/cpp_client_wrapper_glfw)
WRAPPER_SOURCES= \
$(WRAPPER_ROOT)/flutter_window_controller.cc \
$(WRAPPER_ROOT)/plugin_registrar.cc \
$(WRAPPER_ROOT)/engine_method_result.cc
# Use abspath for extra sources, which may also contain relative paths (see
# note above about WRAPPER_ROOT).
SOURCES=main.cc flutter/generated_plugin_registrant.cc $(WRAPPER_SOURCES) \
$(abspath $(EXTRA_SOURCES))
# Headers
WRAPPER_INCLUDE_DIR=$(WRAPPER_ROOT)/include
INCLUDE_DIRS=$(FLUTTER_EPHEMERAL_DIR) $(WRAPPER_INCLUDE_DIR)
# Build settings
ifneq ($(strip $(SYSTEM_LIBRARIES)),)
EXTRA_CPPFLAGS+=$(patsubst -I%,-isystem%,$(shell pkg-config --cflags $(SYSTEM_LIBRARIES)))
EXTRA_LDFLAGS+=$(shell pkg-config --libs $(SYSTEM_LIBRARIES))
endif
CXX=clang++ $(EXTRA_CXXFLAGS)
CXXFLAGS.release=-DNDEBUG
CXXFLAGS=-std=c++14 -Wall -Werror $(CXXFLAGS.$(BUILD))
CPPFLAGS=$(patsubst %,-I%,$(INCLUDE_DIRS)) $(EXTRA_CPPFLAGS)
LDFLAGS=-L$(BUNDLE_LIB_DIR) \
-l$(FLUTTER_LIB_NAME) \
$(EXTRA_LDFLAGS) \
-Wl,-rpath=\$$ORIGIN/lib
# Intermediate files.
OBJ_FILES=$(SOURCES:%.cc=$(OBJ_DIR)/%.o)
DEPENDENCY_FILES=$(OBJ_FILES:%.o=%.d)
# Targets
.PHONY: all
all: $(BIN_OUT) bundle
# This is a phony target because the flutter tool cannot describe
# its inputs and outputs yet.
.PHONY: sync
sync: $(FLUTTER_CONFIG_FILE)
$(LINUX_BUILD) linux-x64 $(BUILD)
.PHONY: bundle
bundle: $(ICU_DATA_OUT) $(ALL_LIBS_OUT) bundleflutterassets
$(BIN_OUT): $(OBJ_FILES) $(ALL_LIBS_OUT)
mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OBJ_FILES) $(LDFLAGS) -o $@
$(WRAPPER_SOURCES) $(FLUTTER_LIB) $(ICU_DATA_SOURCE) $(FLUTTER_ASSETS_SOURCE): \
| sync
$(FLUTTER_LIB_OUT): $(FLUTTER_LIB)
mkdir -p $(@D)
cp $< $@
$(ICU_DATA_OUT): $(ICU_DATA_SOURCE)
mkdir -p $(@D)
cp $< $@
-include $(DEPENDENCY_FILES)
$(OBJ_DIR)/%.o : %.cc | sync
mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -c $< -o $@
# Fully re-copy the assets directory on each build to avoid having to keep a
# comprehensive list of all asset files here, which would be fragile to changes
# in the Flutter example (e.g., adding a new font to pubspec.yaml would require
# changes here).
.PHONY: bundleflutterassets
bundleflutterassets: $(FLUTTER_ASSETS_SOURCE)
mkdir -p $(BUNDLE_DATA_DIR)
rsync -rpu --delete $(FLUTTER_ASSETS_SOURCE) $(BUNDLE_DATA_DIR)
.PHONY: clean
clean:
rm -rf $(OUT_DIR); \
cd $(FLUTTER_APP_DIR); \
$(FLUTTER_BIN) clean
//
// Generated file. Do not edit.
//
#include "generated_plugin_registrant.h"
void RegisterPlugins(flutter::PluginRegistry* registry) {
}
//
// Generated file. Do not edit.
//
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <flutter/flutter_window_controller.h>
#include <linux/limits.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <vector>
#include "flutter/generated_plugin_registrant.h"
namespace {
// Returns the path of the directory containing this executable, or an empty
// string if the directory cannot be found.
std::string GetExecutableDirectory() {
char buffer[PATH_MAX + 1];
ssize_t length = readlink("/proc/self/exe", buffer, sizeof(buffer));
if (length > PATH_MAX) {
std::cerr << "Couldn't locate executable" << std::endl;
return "";
}
std::string executable_path(buffer, length);
size_t last_separator_position = executable_path.find_last_of('/');
if (last_separator_position == std::string::npos) {
std::cerr << "Unabled to find parent directory of " << executable_path
<< std::endl;
return "";
}
return executable_path.substr(0, last_separator_position);
}
} // namespace
int main(int argc, char **argv) {
// Resources are located relative to the executable.
std::string base_directory = GetExecutableDirectory();
if (base_directory.empty()) {
base_directory = ".";
}
std::string data_directory = base_directory + "/data";
std::string assets_path = data_directory + "/flutter_assets";
std::string icu_data_path = data_directory + "/icudtl.dat";
// Arguments for the Flutter Engine.
std::vector<std::string> arguments;
flutter::FlutterWindowController flutter_controller(icu_data_path);
flutter::WindowProperties window_properties = {};
window_properties.title = "Flutter Desktop Example";
window_properties.width = 800;
window_properties.height = 600;
// Start the engine.
if (!flutter_controller.CreateWindow(window_properties, assets_path,
arguments)) {
return EXIT_FAILURE;
}
RegisterPlugins(&flutter_controller);
// Run until the window is closed.
while (flutter_controller.RunEventLoopWithTimeout(
std::chrono::milliseconds::max())) {
}
return EXIT_SUCCESS;
}
File added
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/xcuserdata/
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import file_chooser
import path_provider_fde
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FileChooserPlugin.register(with: registry.registrar(forPlugin: "FileChooserPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
}
platform :osx, '10.11'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
def pubspec_supports_macos(file)
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return false;
end
File.foreach(file_abs_path) { |line|
return true if line =~ /^\s*macos:/
}
return false
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
ephemeral_dir = File.join('Flutter', 'ephemeral')
symlink_dir = File.join(ephemeral_dir, '.symlinks')
symlink_plugins_dir = File.join(symlink_dir, 'plugins')
system("rm -rf #{symlink_dir}")
system("mkdir -p #{symlink_plugins_dir}")
# Flutter Pods
generated_xcconfig = parse_KV_file(File.join(ephemeral_dir, 'Flutter-Generated.xcconfig'))
if generated_xcconfig.empty?
puts "Flutter-Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcconfig.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join(symlink_dir, 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'FlutterMacOS', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join(symlink_plugins_dir, p[:name])
File.symlink(p[:path], symlink)
if pubspec_supports_macos(File.join(symlink, 'pubspec.yaml'))
pod p[:name], :path => File.join(symlink, 'macos')
end
}
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true
PODS:
- file_chooser (0.0.2):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- path_provider_fde (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- file_chooser (from `Flutter/ephemeral/.symlinks/plugins/file_chooser/macos`)
- FlutterMacOS (from `Flutter/ephemeral/.symlinks/flutter/darwin-x64`)
- path_provider_fde (from `Flutter/ephemeral/.symlinks/plugins/path_provider_fde/macos`)
EXTERNAL SOURCES:
file_chooser:
:path: Flutter/ephemeral/.symlinks/plugins/file_chooser/macos
FlutterMacOS:
:path: Flutter/ephemeral/.symlinks/flutter/darwin-x64
path_provider_fde:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_fde/macos
SPEC CHECKSUMS:
file_chooser: 24432cf5dc836722b05c11c2a0a30d19c3c9b996
FlutterMacOS: 15bea8a44d2fa024068daa0140371c020b4b6ff9
path_provider_fde: ac05eee380688ce8414a9003c3ac2d3c106dcbf8
PODFILE CHECKSUM: d8ba9b3e9e93c62c74a660b46c6fcb09f03991a7
COCOAPODS: 1.8.4
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 51;
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 */
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 */; };
33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; };
33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = 33D1A10322148B71006C7A3E /* FlutterMacOS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
AC484BA342B7F3D708348C24 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A60FEE9A14B6B89D3B4B69AB /* Pods_Runner.framework */; };
D73912F022F37F9E000D13A0 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; };
D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */ = {isa = PBXBuildFile; fileRef = D73912EF22F37F9E000D13A0 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
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 = (
D73912F222F3801D000D13A0 /* App.framework in Bundle Framework */,
33D1A10522148B93006C7A3E /* FlutterMacOS.framework in Bundle Framework */,
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* Flutter Desktop Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Flutter Desktop Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33D1A10322148B71006C7A3E /* FlutterMacOS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FlutterMacOS.framework; path = Flutter/ephemeral/FlutterMacOS.framework; sourceTree = SOURCE_ROOT; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
5CCA470CB94BB4ED9CED90FD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
99C221DD8322FAAED0195075 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
A60FEE9A14B6B89D3B4B69AB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CD35B283F1E83A3FDDB957B8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
D73912EF22F37F9E000D13A0 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/ephemeral/App.framework; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D73912F022F37F9E000D13A0 /* App.framework in Frameworks */,
33D1A10422148B71006C7A3E /* FlutterMacOS.framework in Frameworks */,
AC484BA342B7F3D708348C24 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
80225BE95F630EF42D03F4EB /* Pods */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* Flutter Desktop Example.app */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
D73912EF22F37F9E000D13A0 /* App.framework */,
33D1A10322148B71006C7A3E /* FlutterMacOS.framework */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
80225BE95F630EF42D03F4EB /* Pods */ = {
isa = PBXGroup;
children = (
CD35B283F1E83A3FDDB957B8 /* Pods-Runner.debug.xcconfig */,
5CCA470CB94BB4ED9CED90FD /* Pods-Runner.release.xcconfig */,
99C221DD8322FAAED0195075 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
A60FEE9A14B6B89D3B4B69AB /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
B463C5461AA1D4AF54BD4307 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
B1E68EDAA20C50552F91FEEE /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* Flutter Desktop Example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Google LLC";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 0920;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
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;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename\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\ntouch Flutter/ephemeral/tripwire\n";
};
B1E68EDAA20C50552F91FEEE /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
B463C5461AA1D4AF54BD4307 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
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 */
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 = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
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.11;
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;
DEVELOPMENT_TEAM = 86R4V3XFLU;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.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.11;
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.11;
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;
DEVELOPMENT_TEAM = 86R4V3XFLU;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.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;
DEVELOPMENT_TEAM = 86R4V3XFLU;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter/ephemeral",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.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 */
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 */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/stuartmorgan/src/embedder-opensource/flutter-desktop-embedding/example/macos/Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Flutter Desktop Example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00380F9121DF178D00097171"
BuildableName = "RunnerUITests.xctest"
BlueprintName = "RunnerUITests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Flutter Desktop Example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Flutter Desktop Example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "Flutter Desktop Example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
import Cocoa
import FlutterMacOS
@NSApplicationMain
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}
{
"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"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Flutter_Desktop_Example" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Flutter_Desktop_Example" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>
// 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 = Flutter Desktop Example
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterDesktopExample
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2019 com.example. All rights reserved.
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"
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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.movies.read-write</key>
<true/>
<key>com.apple.security.assets.music.read-write</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.personal-information.addressbook</key>
<true/>
<key>com.apple.security.personal-information.calendars</key>
<true/>
<key>com.apple.security.personal-information.location</key>
<true/>
<key>com.apple.security.print</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController.init()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
// guard let controller = flutterViewController as? FlutterPluginRegistrar else {
// fatalError("rootViewController is not type FlutterViewController")
// }
//
// let batteryChannel = FlutterMethodChannel(name:"GM_Desktop",
// binaryMessenger: controller.messenger)
//
// batteryChannel.setMethodCallHandler({
// [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
// guard call.method == "getBatteryLevel" else {
// result(FlutterMethodNotImplemented)
// return
// }
// self?.receiveBatteryLevel(result: result)
// })
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.movies.read-write</key>
<true/>
<key>com.apple.security.assets.music.read-write</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.personal-information.addressbook</key>
<true/>
<key>com.apple.security.personal-information.calendars</key>
<true/>
<key>com.apple.security.personal-information.location</key>
<true/>
<key>com.apple.security.print</key>
<true/>
</dict>
</plist>
name: example_flutter
description: An example project for flutter-desktop-embedding.
version: 0.1.0
environment:
sdk: '>=2.0.0 <3.0.0'
# The example interacts with build scripts on the Flutter side that are not
# yet stable, so it requires a very recent version of Flutter.
# This version will increase regularly as the build scripts change.
flutter: '>=1.10.2-pre.54'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.0
flutter_screenutil: ^0.5.3
event_bus: ^1.1.0
dio: ^2.2.2
rxdart: ^0.22.0 #链式编程
flutter_svg: ^0.14.1
file_chooser:
git:
url: https://github.com/hpoul/flutter-desktop-embedding.git
path: plugins/file_chooser
dropdown_menu: ^1.1.0
flutter_animation_set: ^0.0.4
path_provider_fde:
# git:
# url: https://github.com/hpoul/flutter-desktop-embedding.git
# path: plugins/flutter_plugins/path_provider_fde
path: /Users/apple/lsy/flutter-desktop-embedding/plugins/flutter_plugins/path_provider_fde
dev_dependencies:
flutter_test:
sdk: flutter
source_gen: '>=0.8.0'
build_runner: ^1.6.1
flutter:
uses-material-design: true
assets:
- image/
# See https://github.com/flutter/flutter/wiki/Desktop-shells#fonts
fonts:
- family: Roboto
fonts:
- asset: fonts/Roboto/Roboto-Thin.ttf
weight: 100
- asset: fonts/Roboto/Roboto-Light.ttf
weight: 300
- asset: fonts/Roboto/Roboto-Regular.ttf
weight: 400
- asset: fonts/Roboto/Roboto-Medium.ttf
weight: 500
- asset: fonts/Roboto/Roboto-Bold.ttf
weight: 700
- asset: fonts/Roboto/Roboto-Black.ttf
weight: 900
// This is a basic Flutter widget test.
// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
// provides. 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:example_flutter/main.dart';
void main() {
testWidgets('Counter increments smoke test', (tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(new 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);
});
}
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# Local additions, not from the link above
flutter/ephemeral/
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetName>Flutter Desktop Example</TargetName>
</PropertyGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}</ProjectGuid>
<ProjectName>Flutter Build</ProjectName>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="flutter\ephemeral\Generated.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup>
<CustomBuildStep>
<Command>"$(ProjectDir)scripts\prepare_dependencies" $(Configuration)</Command>
<Message>Running Flutter backend build</Message>
<Outputs>force_to_run_every_time</Outputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemGroup>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup />
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
</Project>
B// Microsoft Visual C++ generated resource script. B// Microsoft Visual C++ generated resource script.

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.645
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Runner", "Runner.vcxproj", "{5A827760-CF8B-408A-99A3-B6C0AD2271E7}"
ProjectSection(ProjectDependencies) = postProject
{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F} = {6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Flutter Build", "FlutterBuild.vcxproj", "{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Debug|x64.ActiveCfg = Debug|x64
{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Debug|x64.Build.0 = Debug|x64
{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Release|x64.ActiveCfg = Release|x64
{5A827760-CF8B-408A-99A3-B6C0AD2271E7}.Release|x64.Build.0 = Release|x64
{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.ActiveCfg = Debug|x64
{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Debug|x64.Build.0 = Debug|x64
{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.ActiveCfg = Release|x64
{6419BF13-6ECD-4CD2-9E85-E566A1F03F8F}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B8A69CB0-A974-4774-9EBD-1E5EECACD186}
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{5A827760-CF8B-408A-99A3-B6C0AD2271E7}</ProjectGuid>
<RootNamespace>GLFWExample</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
<PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="flutter\ephemeral\Generated.props" />
<Import Project="AppConfiguration.props" />
<Import Project="FlutterPlugins.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="flutter\ephemeral\Generated.props" />
<Import Project="AppConfiguration.props" />
<Import Project="FlutterPlugins.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(ProjectDir)..\build\windows\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
<IntDir>$(ProjectDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<IncludePath>$(ProjectDir);$(FLUTTER_EPHEMERAL_DIR)\;$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include\;$(OutDir)..\Plugins;$(IncludePath)</IncludePath>
<LibraryPath>$(FLUTTER_EPHEMERAL_DIR);$(OutDir)..\Plugins;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(ProjectDir)..\build\windows\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
<IntDir>$(ProjectDir)..\build\windows\intermediates\$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
<IncludePath>$(ProjectDir);$(FLUTTER_EPHEMERAL_DIR)\;$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\include\;$(OutDir)..\Plugins;$(IncludePath)</IncludePath>
<LibraryPath>$(FLUTTER_EPHEMERAL_DIR);$(OutDir)..\Plugins;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Message>
</Message>
</PreBuildEvent>
<PreLinkEvent>
<Command>
</Command>
<Message>
</Message>
</PreLinkEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>
</Message>
</PostBuildEvent>
<CustomBuildStep>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)"</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Bundling dependencies</Message>
<Outputs>Dummy_Run_Always</Outputs>
<Inputs>
</Inputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Message>
</Message>
</PreBuildEvent>
<PreLinkEvent>
<Command>
</Command>
<Message>
</Message>
</PreLinkEvent>
<PostBuildEvent>
<Command>
</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>
</Message>
</PostBuildEvent>
<CustomBuildStep>
<Command>"$(ProjectDir)scripts\bundle_assets_and_deps" "$(FLUTTER_EPHEMERAL_DIR)\" "$(OutputPath)" "$(OutputPath)..\Plugins\" "$(TargetFileName)"</Command>
</CustomBuildStep>
<CustomBuildStep>
<Message>Bundling dependencies</Message>
<Outputs>Dummy_Run_Always</Outputs>
<Inputs>
</Inputs>
</CustomBuildStep>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="flutter\generated_plugin_registrant.cc" />
<ClCompile Include="window_configuration.cpp" />
<ClCompile Include="win32_window.cc" />
<ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\engine_method_result.cc" />
<ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\flutter_view_controller.cc" />
<ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\plugin_registrar.cc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="flutter\generated_plugin_registrant.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="win32_window.h" />
<ClInclude Include="window_configuration.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="runner.exe.manifest" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Runner.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="resources\app_icon.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<PropertyGroup>
<LocalDebuggerWorkingDirectory>$(SolutionDir)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\Client Wrapper">
<UniqueIdentifier>{2761a4b5-57b2-4d50-a677-d20ddc17a7f1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="flutter\generated_plugin_registrant.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="win32_window.cc">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="window_configuration.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\engine_method_result.cc">
<Filter>Source Files\Client Wrapper</Filter>
</ClCompile>
<ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\flutter_view_controller.cc">
<Filter>Source Files\Client Wrapper</Filter>
</ClCompile>
<ClCompile Include="$(FLUTTER_EPHEMERAL_DIR)\cpp_client_wrapper\plugin_registrar.cc">
<Filter>Source Files\Client Wrapper</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="flutter\generated_plugin_registrant.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="win32_window.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="window_configuration.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Manifest Include="runner.exe.manifest" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Runner.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="resources\app_icon.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>
//
// Generated file. Do not edit.
//
#include "generated_plugin_registrant.h"
void RegisterPlugins(flutter::PluginRegistry* registry) {
}
//
// Generated file. Do not edit.
//
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
#include <flutter/plugin_registry.h>
// Registers Flutter plugins.
void RegisterPlugins(flutter::PluginRegistry* registry);
#endif // GENERATED_PLUGIN_REGISTRANT_
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <flutter/flutter_view_controller.h>
#include <windows.h>
#include <chrono>
#include <codecvt>
#include <iostream>
#include <string>
#include <vector>
#include "flutter/generated_plugin_registrant.h"
#include "win32_window.h"
#include "window_configuration.h"
namespace {
// Returns the path of the directory containing this executable, or an empty
// string if the directory cannot be found.
std::string GetExecutableDirectory() {
wchar_t buffer[MAX_PATH];
if (GetModuleFileName(nullptr, buffer, MAX_PATH) == 0) {
std::cerr << "Couldn't locate executable" << std::endl;
return "";
}
std::wstring_convert<std::codecvt_utf8<wchar_t>> wide_to_utf8;
std::string executable_path = wide_to_utf8.to_bytes(buffer);
size_t last_separator_position = executable_path.find_last_of('\\');
if (last_separator_position == std::string::npos) {
std::cerr << "Unabled to find parent directory of " << executable_path
<< std::endl;
return "";
}
return executable_path.substr(0, last_separator_position);
}
} // namespace
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t *command_line,
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()) {
::AllocConsole();
}
// Resources are located relative to the executable.
std::string base_directory = GetExecutableDirectory();
if (base_directory.empty()) {
base_directory = ".";
}
std::string data_directory = base_directory + "\\data";
std::string assets_path = data_directory + "\\flutter_assets";
std::string icu_data_path = data_directory + "\\icudtl.dat";
// Arguments for the Flutter Engine.
std::vector<std::string> arguments;
// Top-level window frame.
Win32Window::Point origin(kFlutterWindowOriginX, kFlutterWindowOriginY);
Win32Window::Size size(kFlutterWindowWidth, kFlutterWindowHeight);
flutter::FlutterViewController flutter_controller(
icu_data_path, size.width, size.height, assets_path, arguments);
RegisterPlugins(&flutter_controller);
// Create a top-level win32 window to host the Flutter view.
Win32Window window;
if (!window.CreateAndShow(kFlutterWindowTitle, origin, size)) {
return EXIT_FAILURE;
}
// Parent and resize Flutter view into top-level window.
window.SetChildContent(flutter_controller.GetNativeWindow());
// Run messageloop with a hook for flutter_controller to do work until
// the window is closed.
std::chrono::nanoseconds wait_duration(0);
// Run until the window is closed.
while (window.GetHandle() != nullptr) {
MsgWaitForMultipleObjects(0, NULL, FALSE,
static_cast<DWORD>(wait_duration.count() / 1000),
QS_ALLINPUT);
MSG message;
// All pending Windows messages must be processed; MsgWaitForMultipleObjects
// won't return again for items left in the queue after PeekMessage.
while (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
if (message.message == WM_QUIT) {
window.Destroy();
break;
}
TranslateMessage(&message);
DispatchMessage(&message);
}
// Allow Flutter to process its messages.
// TODO: Consider interleaving processing on a per-message basis to avoid
// the possibility of one queue starving the other.
wait_duration = flutter_controller.ProcessMessages();
}
return EXIT_SUCCESS;
}
//{{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
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>
\ No newline at end of file
:: Copyright 2018 Google LLC
::
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
@echo off
set FLUTTER_CACHE_DIR=%~1
set BUNDLE_DIR=%~2
set PLUGIN_DIR=%~3
set EXE_NAME=%~4
set DATA_DIR=%BUNDLE_DIR%data
if not exist "%DATA_DIR%" call mkdir "%DATA_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
:: Write the executable name to the location expected by the Flutter tool.
echo %EXE_NAME%>"%FLUTTER_CACHE_DIR%exe_filename"
:: Copy the Flutter assets to the data directory.
set FLUTTER_APP_DIR=%~dp0..\..
set ASSET_DIR_NAME=flutter_assets
set TARGET_ASSET_DIR=%DATA_DIR%\%ASSET_DIR_NAME%
if exist "%TARGET_ASSET_DIR%" call rmdir /s /q "%TARGET_ASSET_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
call xcopy /s /e /i /q "%FLUTTER_APP_DIR%\build\%ASSET_DIR_NAME%" "%TARGET_ASSET_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
:: Copy the icudtl.dat file from the Flutter tree to the data directory.
call xcopy /y /d /q "%FLUTTER_CACHE_DIR%icudtl.dat" "%DATA_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
:: Copy the Flutter DLL to the target location.
call xcopy /y /d /q "%FLUTTER_CACHE_DIR%flutter_windows.dll" "%BUNDLE_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
:: Copy any Plugin DLLs to the target location.
if exist "%PLUGIN_DIR%" (
call xcopy /y /d /q "%PLUGIN_DIR%"*.dll "%BUNDLE_DIR%"
if %errorlevel% neq 0 exit /b %errorlevel%
)
:: Copyright 2018 Google LLC
::
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
@echo off
:: Run flutter tool backend.
set BUILD_MODE=%~1
"%FLUTTER_ROOT%\packages\flutter_tools\bin\tool_backend" windows-x64 %BUILD_MODE%
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "win32_window.h"
#include "resource.h"
#include "shellscalingapi.h"
namespace {
// the Windows DPI system is based on this
// constant for machines running at 100% scaling.
constexpr int kBaseDpi = 96;
constexpr LPCWSTR kClassName = L"CLASSNAME";
// Scale helper to convert logical scaler values to physical using passed in
// scale factor
int Scale(int source, double scale_factor) {
return static_cast<int>(source * scale_factor);
}
} // namespace
Win32Window::Win32Window() {}
Win32Window::~Win32Window() { Destroy(); }
bool Win32Window::CreateAndShow(const std::wstring &title, const Point &origin,
const Size &size) {
Destroy();
WNDCLASS window_class = RegisterWindowClass();
HMONITOR defaut_monitor =
MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
UINT dpi_x = 0, dpi_y = 0;
GetDpiForMonitor(defaut_monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
double scale_factor = static_cast<double>(dpi_x) / kBaseDpi;
HWND window = CreateWindow(
window_class.lpszClassName, title.c_str(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, Scale(origin.x, scale_factor),
Scale(origin.y, scale_factor), Scale(size.width, scale_factor),
Scale(size.height, scale_factor), nullptr, nullptr,
window_class.hInstance, this);
return window != nullptr;
}
WNDCLASS Win32Window::RegisterWindowClass() {
WNDCLASS window_class{};
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
window_class.lpszClassName = kClassName;
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 = WndProc;
RegisterClass(&window_class);
return window_class;
}
LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
if (message == WM_NCCREATE) {
auto cs = reinterpret_cast<CREATESTRUCT *>(lparam);
SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
auto that = static_cast<Win32Window *>(cs->lpCreateParams);
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 {
auto window =
reinterpret_cast<Win32Window *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (window == nullptr) {
return 0;
}
switch (message) {
case WM_DESTROY:
window_handle_ = nullptr;
Destroy();
return 0;
case WM_SIZE:
RECT rect;
GetClientRect(hwnd, &rect);
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;
// Messages that are directly forwarded to embedding.
case WM_FONTCHANGE:
SendMessage(child_content_, WM_FONTCHANGE, NULL, NULL);
return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
}
void Win32Window::Destroy() {
if (window_handle_) {
DestroyWindow(window_handle_);
window_handle_ = nullptr;
}
UnregisterClass(kClassName, nullptr);
}
Win32Window *Win32Window::GetThisFromHandle(HWND const window) noexcept {
return reinterpret_cast<Win32Window *>(
GetWindowLongPtr(window, GWLP_USERDATA));
}
void Win32Window::SetChildContent(HWND content) {
child_content_ = content;
auto res = SetParent(content, window_handle_);
RECT frame;
GetClientRect(window_handle_, &frame);
MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
frame.bottom - frame.top, true);
SetFocus(child_content_);
}
HWND Win32Window::GetHandle() { return window_handle_; }
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WIN32_WINDOW_H_
#define WIN32_WINDOW_H_
#include <Windows.h>
#include <Windowsx.h>
#include <functional>
#include <memory>
#include <string>
// 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();
~Win32Window();
// Creates and shows a win32 window with |title| and position and size 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 to will treat the width height passed in to this function
// as logical pixels and scale to appropriate for the default monitor. Returns
// true if the window was created successfully.
bool CreateAndShow(const std::wstring &title, const Point &origin,
const Size &size);
// Release OS resources asociated 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();
protected:
// Registers a window class with default style attributes, cursor and
// icon.
WNDCLASS RegisterWindowClass();
// 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
// responsponds 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;
// 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.
LRESULT
MessageHandler(HWND window, UINT const message, WPARAM const wparam,
LPARAM const lparam) noexcept;
private:
// should message loop keep running
bool messageloop_running_ = true;
// Retrieves a class instance pointer for |window|
static Win32Window *GetThisFromHandle(HWND const window) noexcept;
// window handle for top level window.
HWND window_handle_ = nullptr;
// window handle for hosted content.
HWND child_content_ = nullptr;
};
#endif // WIN32_WINDOW_H_
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "window_configuration.h"
const wchar_t *kFlutterWindowTitle = L"Flutter Desktop Example";
const unsigned int kFlutterWindowOriginX = 10;
const unsigned int kFlutterWindowOriginY = 10;
const unsigned int kFlutterWindowWidth = 800;
const unsigned int kFlutterWindowHeight = 600;
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef WINDOW_CONFIGURATION_
#define WINDOW_CONFIGURATION_
// This is a temporary approach to isolate changes that people are likely to
// make to the example project from main.cpp, where the APIs are still in flux.
// This will avoid people needing to resolve conflicts or re-create changes
// slightly different every time the Windows Flutter API surface changes just
// because of, e.g., a local change to the window title.
//
// Longer term there should be simpler configuration options for common
// customizations like this, without requiring native code changes.
extern const wchar_t *kFlutterWindowTitle;
extern const unsigned int kFlutterWindowOriginX;
extern const unsigned int kFlutterWindowOriginY;
extern const unsigned int kFlutterWindowWidth;
extern const unsigned int kFlutterWindowHeight;
#endif // WINDOW_CONFIGURATION_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment