Merge branch 'new_main' into mcy_new

This commit is contained in:
machuanyu 2024-09-03 16:23:09 +08:00
commit c27eff0462
70 changed files with 2139 additions and 1023 deletions

2
.gitignore vendored
View File

@ -53,3 +53,5 @@ making_school_asignment_app/lib/common/api/retrofit_client.g.dart
making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart
.vscode/settings.json
.vscode/launch.json
making_school_asignment_app/.fvm/fvm_config.json
making_school_asignment_app/.fvm/flutter_sdk

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

After

Width:  |  Height:  |  Size: 69 B

View File

@ -6,6 +6,7 @@
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#eeeeee</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.

View File

@ -6,6 +6,7 @@
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#eeeeee</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.

View File

@ -29,7 +29,7 @@
type="application/octet-stream" />
</item> -->
<item>
<title>Version 1.0.0</title>
<title>Version 1.0.1+2</title>
#发行说明-读取html方式(2选1)
<!-- <sparkle:releaseNotesLink>
https://your_domain/your_path/release_notes.html
@ -38,16 +38,16 @@
<description>
<![CDATA[
<ul>
<li>1、新增XX功能</li>
<li>2、新增XX功能</li>
<li>1、优化批阅提示</li>
<li>2、优化启动图和展示页面</li>
</ul>
]]>
</description>
<pubDate>Sun, 16 Feb 2022 12:00:00 +0800</pubDate>
<pubDate>Sun, 16 Feb 2024 12:00:00 +0800</pubDate>
#你更新程序的地址
<enclosure url="https://dpc-job-oss.23544.com/infra-app/making_school_asignment_app/1.0.0/3/making_school_asignment_app-1.0.0+1-windows-setup.exe"
sparkle:dsaSignature="MEUCICOob1N5PNhjRDWh2gHHOuJayep41hP+BMyF26BoYjQLAiEA2dG22KMc2HCQTUyWe1pxWmCJqVmdNQU+Mmfvojg0K2M="
sparkle:version="1.0.0+1"
<enclosure url="https://dpc-job-oss.23544.com/infra-app/making_school_asignment_app/1.0.1/3/making_school_asignment_app-1.0.1+2-windows-setup.exe"
sparkle:dsaSignature="MEUCIG2O7ZNPeIs/fi2GF/UCRvooqIZMFjLPyfGsIqTnmfHkAiEAuFusRpYjkf05fqBv3nQqfyy8Y8u6ub5X+QWZU7NJ5qU="
sparkle:version="1.0.1+2"
sparkle:os="windows"
length="0"
type="application/octet-stream" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

View File

@ -5,7 +5,9 @@ flutter_native_splash:
# 如需恢复默认的白屏,执行如下命令
# flutter pub run flutter_native_splash:remove
# 设置闪屏页的默认态logo或背景图片路径
background_image: assets/images/splash_native.png
color: "#eeeeee"
image_ios: assets/images/splash_native.png
background_image_android: assets/images/splash_native.png
android_12:
image: assets/images/splash.png
android: true

View File

@ -43,6 +43,8 @@
/* Begin PBXFileReference section */
02826AB13A0419EF6A6BEE4C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0B2C69D12C734FA600ABD561 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
0B2C69D22C743A7D00ABD561 /* RunnerRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerRelease.entitlements; sourceTree = "<group>"; };
12C576EE23C708825E0F6031 /* 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>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
@ -97,7 +99,6 @@
20D60590541077F4B12F8462 /* Pods-RunnerTests.release.xcconfig */,
168BD706454188B9AD4262F4 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@ -144,6 +145,8 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
0B2C69D22C743A7D00ABD561 /* RunnerRelease.entitlements */,
0B2C69D12C734FA600ABD561 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@ -454,6 +457,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -488,17 +492,28 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = Z778GC45N8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp;
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = "com.yuanxuan.makingS--buneng--choolAsignmentApp";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@ -528,6 +543,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = Z778GC45N8;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp.RunnerTests;
@ -577,6 +593,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -634,6 +651,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -670,18 +688,26 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = Z778GC45N8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -692,17 +718,25 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = Z778GC45N8;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

View File

@ -1,122 +1,122 @@
{
"images" : [
"images": [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"filename": "Icon-App-20x20@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "20x20"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
"filename": "Icon-App-20x20@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "20x20"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"filename": "Icon-App-29x29@1x.png",
"idiom": "iphone",
"scale": "1x",
"size": "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"filename": "Icon-App-29x29@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "29x29"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
"filename": "Icon-App-29x29@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "29x29"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"filename": "Icon-App-40x40@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "40x40"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
"filename": "Icon-App-40x40@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "40x40"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
"filename": "Icon-App-60x60@2x.png",
"idiom": "iphone",
"scale": "2x",
"size": "60x60"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
"filename": "Icon-App-60x60@3x.png",
"idiom": "iphone",
"scale": "3x",
"size": "60x60"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
"filename": "Icon-App-20x20@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "20x20"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"filename": "Icon-App-20x20@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "20x20"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"filename": "Icon-App-29x29@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "29x29"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"filename": "Icon-App-29x29@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "29x29"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
"filename": "Icon-App-40x40@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "40x40"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"filename": "Icon-App-40x40@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "40x40"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
"filename": "Icon-App-76x76@1x.png",
"idiom": "ipad",
"scale": "1x",
"size": "76x76"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
"filename": "Icon-App-76x76@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "76x76"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
"filename": "Icon-App-83.5x83.5@2x.png",
"idiom": "ipad",
"scale": "2x",
"size": "83.5x83.5"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
"filename": "Icon-App-1024x1024@1x.png",
"idiom": "ios-marketing",
"scale": "1x",
"size": "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"author": "icons_launcher",
"version": 1
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 956 B

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "background.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 258 KiB

View File

@ -1,5 +0,0 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -38,7 +38,7 @@
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
<image name="LaunchImage" width="750" height="1735"/>
<image name="LaunchBackground" width="1" height="1"/>
</resources>
</document>

View File

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
@ -14,13 +16,14 @@
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="55" y="-34"/>
</scene>
</scenes>
</document>

View File

@ -2,10 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Making School Asignment App</string>
<string>点智学</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -24,10 +26,19 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict/>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
@ -41,12 +52,6 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIStatusBarHidden</key>
<false/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>

View File

@ -0,0 +1,22 @@
<?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.developer.associated-domains</key>
<array/>
<key>com.apple.developer.devicecheck.appattest-environment</key>
<string>development</string>
<key>com.apple.developer.networking.networkextension</key>
<array/>
<key>com.apple.developer.networking.slicing.appcategory</key>
<array/>
<key>com.apple.developer.networking.slicing.trafficcategory</key>
<array/>
<key>com.apple.developer.networking.wifi-info</key>
<true/>
<key>com.apple.developer.user-fonts</key>
<array/>
<key>com.apple.security.application-groups</key>
<array/>
</dict>
</plist>

View File

@ -0,0 +1,22 @@
<?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.developer.associated-domains</key>
<array/>
<key>com.apple.developer.devicecheck.appattest-environment</key>
<string>development</string>
<key>com.apple.developer.networking.networkextension</key>
<array/>
<key>com.apple.developer.networking.slicing.appcategory</key>
<array/>
<key>com.apple.developer.networking.slicing.trafficcategory</key>
<array/>
<key>com.apple.developer.networking.wifi-info</key>
<true/>
<key>com.apple.developer.user-fonts</key>
<array/>
<key>com.apple.security.application-groups</key>
<array/>
</dict>
</plist>

View File

@ -5,6 +5,7 @@ import 'package:making_school_asignment_app/common/job/marking_models/do_paper_d
import 'package:making_school_asignment_app/common/job/marking_models/favor_param.dart';
import 'package:making_school_asignment_app/common/job/marking_models/original_manuscript_handwriting_params.dart';
import 'package:making_school_asignment_app/common/job/marking_models/review_submission_params.dart';
import 'package:making_school_asignment_app/common/job/user_register_params.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart';
import 'package:retrofit/retrofit.dart';
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
@ -40,6 +41,12 @@ abstract class RetrofitClient {
@POST("/api/rbac/Auth/DcLogin")
Future toLogin(@Field() String account, @Field() String password);
@POST("/api/rbac/Auth/Register")
Future<String> toRegister(@Body() UserRegisterParams params);
@DELETE("/api/rbac/User/Delete")
Future<String> toUserLogout(@Field() int id);
@GET("/api/rbac/User/GetUser")
Future<UserInfoDetail?> getUser(@Query('userId') String userId);

View File

@ -27,8 +27,8 @@ class AppVersion extends Object {
@JsonKey(name: 'ftuType')
int ftuType;
@JsonKey(name: 'downloadUrl')
String? downloadUrl;
@JsonKey(name: 'appFileUrl')
String? appFileUrl;
@JsonKey(name: 'description')
String? description;
@ -41,10 +41,10 @@ class AppVersion extends Object {
this.appName,
this.version,
this.ftuType,
this.downloadUrl,
this.appFileUrl,
this.description,
) {
if (downloadUrl != null) downloadUrl = RequestConfig.imgUrl + downloadUrl!;
if (appFileUrl != null) appFileUrl = RequestConfig.imgUrl + appFileUrl!;
}
factory AppVersion.fromJson(Map<String, dynamic> srcJson) => _$AppVersionFromJson(srcJson);

View File

@ -1,5 +1,4 @@
import 'package:get/get.dart';
import 'package:get/get_connect/http/src/request/request.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:making_school_asignment_app/common/config/request_config.dart';
@ -73,28 +72,31 @@ class DoPaperDetailsResult extends Object {
@JsonKey(name: 'totalUnAnnotateCount')
int totalUnAnnotateCount;
@JsonKey(name: 'needAnnotate') //
bool needAnnotate;
DoPaperDetailsResult(
this.totalUnAnnotateCount,
this.templateIds,
this.students,
this.templateId,
this.studentId,
this.annotatedCount,
this.submitCount,
this.zgtAnswer,
this.zgtAnnotate,
this.lastAnswerTime,
this.isFav,
this.studentQuestions,
this.unSubmitStudents,
this.lastPage,
this.nextPage,
this.templateIdKeys,
this.templateIdKeyMap,
this.priority,
this.annotateTime,
this.showZgtAnnotate,
) {
this.totalUnAnnotateCount,
this.templateIds,
this.students,
this.templateId,
this.studentId,
this.annotatedCount,
this.submitCount,
this.zgtAnswer,
this.zgtAnnotate,
this.lastAnswerTime,
this.isFav,
this.studentQuestions,
this.unSubmitStudents,
this.lastPage,
this.nextPage,
this.templateIdKeys,
this.templateIdKeyMap,
this.priority,
this.annotateTime,
this.showZgtAnnotate,
{this.needAnnotate = false}) {
if (templateIds.keys.isNotEmpty) {
templateIdKeys = templateIds.keys.map((e) => int.parse(e)).toList();
templateIdKeyMap = <int, int>{};
@ -114,14 +116,21 @@ class DoPaperDetailsResult extends Object {
if (zgtAnnotate?.isNotEmpty ?? false) {
showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; //
if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
if (annotateTime != null)
showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
}
//
if (annotateTime == null ||
studentQuestions.indexWhere((e) => e.studentScore == null) != -1) {
needAnnotate = true;
}
// print('学生作答图片:${annotatedCount}');
// print('老师批注图片提交数量:${submitCount}');
}
factory DoPaperDetailsResult.fromJson(Map<String, dynamic> srcJson) => _$DoPaperDetailsResultFromJson(srcJson);
factory DoPaperDetailsResult.fromJson(Map<String, dynamic> srcJson) =>
_$DoPaperDetailsResultFromJson(srcJson);
Map<String, dynamic> toJson() => _$DoPaperDetailsResultToJson(this);
}
@ -144,7 +153,8 @@ class PaperStudents extends Object {
this.isPriority,
);
factory PaperStudents.fromJson(Map<String, dynamic> srcJson) => _$PaperStudentsFromJson(srcJson);
factory PaperStudents.fromJson(Map<String, dynamic> srcJson) =>
_$PaperStudentsFromJson(srcJson);
Map<String, dynamic> toJson() => _$PaperStudentsToJson(this);
}
@ -192,7 +202,8 @@ class StudentQuestions extends Object {
this.isCorrect,
});
factory StudentQuestions.fromJson(Map<String, dynamic> srcJson) => _$StudentQuestionsFromJson(srcJson);
factory StudentQuestions.fromJson(Map<String, dynamic> srcJson) =>
_$StudentQuestionsFromJson(srcJson);
Map<String, dynamic> toJson() => _$StudentQuestionsToJson(this);
}
@ -210,7 +221,8 @@ class LastPage extends Object {
this.studentId,
);
factory LastPage.fromJson(Map<String, dynamic> srcJson) => _$LastPageFromJson(srcJson);
factory LastPage.fromJson(Map<String, dynamic> srcJson) =>
_$LastPageFromJson(srcJson);
Map<String, dynamic> toJson() => _$LastPageToJson(this);
}
@ -228,7 +240,8 @@ class NextPage extends Object {
this.studentId,
);
factory NextPage.fromJson(Map<String, dynamic> srcJson) => _$NextPageFromJson(srcJson);
factory NextPage.fromJson(Map<String, dynamic> srcJson) =>
_$NextPageFromJson(srcJson);
Map<String, dynamic> toJson() => _$NextPageToJson(this);
}

View File

@ -0,0 +1,21 @@
import 'package:json_annotation/json_annotation.dart';
part 'user_register_params.g.dart';
@JsonSerializable()
class UserRegisterParams extends Object {
@JsonKey(name: 'account')
String account;
@JsonKey(name: 'password')
String password;
UserRegisterParams({
required this.account,
required this.password,
});
factory UserRegisterParams.fromJson(Map<String, dynamic> srcJson) => _$UserRegisterParamsFromJson(srcJson);
Map<String, dynamic> toJson() => _$UserRegisterParamsToJson(this);
}

View File

@ -98,7 +98,7 @@ class AuthInterceptor extends Interceptor {
headers["x-Authorization"] = xToken!;
}
/* if ((userInfo?.isExpired() ?? false) && userInfo?.termYear != '') {
/* if ((userInfo?.isExpired() ?? false) && userInfo?.termYear != '') {
headers["term-year"] = userInfo!.termYear;
}*/
@ -160,6 +160,16 @@ class TheError extends Interceptor {
int? statusCode = response.statusCode;
var errorMap = response.data;
if (errorMap is String && errorMap.length > 0) {
try {
var errorModel = jsonDecode(errorMap);
var error = errorModel['error'];
if (error != null && error["message"] != null) {
message = error["message"];
}
} catch (e) {}
}
// var runtimeType = errorMap.runtimeType;
if (errorMap is Map && errorMap['error'] != null) {
message = errorMap['error']?['message'] ?? '请求错误,请重试';
@ -198,7 +208,7 @@ class TheError extends Interceptor {
if (message == '用户登录失效,请重新登录' && userInfo.value?.id == null) {
return handler.next(error);
}
ToastUtils.showError(message);
Future.delayed(const Duration(milliseconds: 600), () => ToastUtils.showError(message));
return handler.next(error);
}
}

View File

@ -7,7 +7,8 @@ enum AppStorageKey {
userInfo(value: 'USERINFO', label: "登录用户的基本信息 及 token过期时间"),
userDetailInfo(value: 'USERDETAILINFO', label: "用户的详细信息"),
account(value: 'ACCOUNT', label: "用户名"),
pwd(value: 'PWD', label: "密码");
pwd(value: 'PWD', label: "密码"),
privacyAgreement(value: 'PRIVACYAGREEMENT', label: "用户同意隐私协议");
final String label;
final String value;

View File

@ -51,7 +51,7 @@ class UpgradeLogic extends GetxController with RequestToolMixin {
// String buildNumber = packageInfo.buildNumber; //
Map json = {
'downloadPath': Platform.isWindows ? '' : result.downloadUrl,
'downloadPath': Platform.isWindows ? '' : result.appFileUrl,
'version': result.version,
'systemType': deviceType,
'description': result.description ?? 'APP新版本更新'

View File

@ -12,7 +12,6 @@ import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:permission_handler/permission_handler.dart';
import 'common/config/request_config.dart';
import 'common/utils/app_upgrade/upgradeLogic.dart';
@ -23,6 +22,7 @@ void main() async {
Get.testMode = true;
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
///
await Get.putAsync(() => StorageService().init());
@ -41,13 +41,11 @@ void main() async {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, //
statusBarIconBrightness: Brightness.dark // dark: light
statusBarIconBrightness: Brightness.light // dark: light
));
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); //
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); //
runApp(const MyApp());
Permission.storage.request();
}
class MyApp extends StatelessWidget {

View File

@ -2,6 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/const_text.dart';
import 'package:making_school_asignment_app/common/job/user_info_detail.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
@ -14,7 +18,8 @@ class OhterPage extends StatefulWidget {
State<OhterPage> createState() => _OhterPageState();
}
class _OhterPageState extends State<OhterPage> {
class _OhterPageState extends State<OhterPage> with RequestToolMixin {
late Rx<UserInfoDetail?> userInfo = UserStore.to.userDetailInfo;
RxString localVersion = ''.obs;
@override
@ -29,16 +34,48 @@ class _OhterPageState extends State<OhterPage> {
localVersion.value = packageInfo.version;
}
//
_showAlertDialog(context1) async {
await showDialog(
//
barrierDismissible: false,
context: context1,
builder: (context) {
return AlertDialog(title: quickText("提示信息"), content: quickText("账户注销无法恢复,您确定要注销账户吗?"), actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () {
Navigator.pop(context, 'Cancle');
},
),
TextButton(
child: quickText("确定"),
onPressed: () async {
/* ref.read(markingKeyboardProvider.notifier).clean();
ref.read(markingSubtopicSwitchingProvider.notifier).clean();
ref.read(userTokenProvider.notifier).clean();
ref.read(userProvider.notifier).clean();*/
await getClient().toUserLogout(userInfo.value!.id);
try {
UserStore.to.erase();
var msg = await StorageService.to.erase();
print(msg);
Navigator.pop(context, "Ok");
Get.offAllNamed(Routes.login);
} catch (e) {
print(e);
}
})
]);
});
}
@override
Widget build(BuildContext context) {
final personalInfoTitleStly = TextStyle(
color: const Color.fromRGBO(80, 87, 103, 1),
fontSize: 16.sp,
);
final personalInfoValStly = TextStyle(
color: const Color.fromRGBO(148, 163, 182, 1),
fontSize: 16.sp,
);
return Scaffold(
backgroundColor: const Color.fromRGBO(248, 248, 248, 1),
@ -108,10 +145,53 @@ class _OhterPageState extends State<OhterPage> {
),
],
),
Positioned(
bottom: 50.h,
child: InkWell(
child: Container(
height: 46.h,
width: ScreenUtil().screenWidth - 60.w,
padding: EdgeInsets.symmetric(vertical: 14.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(6.w),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(2.w, 2.h), //y轴偏移量
blurRadius: 14, //
spreadRadius: 0.5, //
)
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.exit_to_app_outlined,
size: 13.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
),
Container(
width: 6.w,
),
Text(
'账户注销',
style: TextStyle(color: const Color.fromRGBO(148, 163, 182, 1), fontSize: 13.sp),
),
],
),
),
onTap: () => _showAlertDialog(context),
),
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [Text('APP备案号: ', style: personalInfoTitleStly), quickText('渝ICP备17007225号-3A', size: 14.sp)],
children: [Text('APP备案号: ', style: personalInfoTitleStly), quickText('渝ICP备17007225号-4A', size: 14.sp)],
),
],
));

View File

@ -1,6 +1,8 @@
import 'dart:async';
import 'package:app_settings/app_settings.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
@ -17,6 +19,7 @@ import 'package:making_school_asignment_app/page/home_page/home_view.dart';
import 'package:making_school_asignment_app/page/work_page/work_logic.dart';
import 'package:making_school_asignment_app/page/work_page/work_view.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:permission_handler/permission_handler.dart';
class StartPage extends StatefulWidget {
const StartPage({super.key});
@ -27,16 +30,73 @@ class StartPage extends StatefulWidget {
class _StartPageState extends State<StartPage> with RequestToolMixin {
Timer? _timer;
Timer? _timerPermission;
DateTime? lastPopTime;
final _pageController = Get.find<PageIndexController>();
final _upgradeLogic = Get.find<UpgradeLogic>();
late final List<Widget> _bodyList;
void getStoragePermission() async {
_timerPermission?.cancel();
_timerPermission = null;
var status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
print(status);
if (status == PermissionStatus.denied) {
await showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text("权限拒绝"),
content: Text("权限被永久拒绝,请前往权限设置页面通过权限"),
actions: [
ElevatedButton(
onPressed: () async {
await AppSettings.openAppSettings(asAnotherTask: true);
Navigator.of(context).pop();
_timerPermission = Timer.periodic(const Duration(seconds: 30), (_) => getStoragePermission());
},
child: Text('前往'),
)
],
);
},
);
return;
}
await showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text("内存权限"),
content: Text("为了提供更好的服务,需要获取到存储权限用于保存批阅笔记"),
actions: [
ElevatedButton(
onPressed: () async {
await Permission.storage.request();
Navigator.of(context).pop();
getStoragePermission();
},
child: Text('允许'),
)
],
);
},
);
}
}
@override
void initState() {
super.initState();
FlutterNativeSplash.remove();
Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove());
Future.delayed(const Duration(seconds: 4), () => getStoragePermission());
Get.put(HomeLogic());
Get.put(WorkLogic());
@ -72,6 +132,7 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
void dispose() {
Get.delete<PageIndexController>();
_timer?.cancel();
_timerPermission?.cancel();
super.dispose();
}
@ -87,6 +148,7 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.dark));
return WillPopScope(
child: Scaffold(
body: PageView(
@ -94,6 +156,11 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
physics: const BouncingScrollPhysics(),
onPageChanged: (index) {
_pageController._pageIndexState.pageIndex.value = index;
if (index == 2) {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.light));
} else {
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.dark));
}
},
children: _bodyList,
),
@ -118,11 +185,14 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
],
//
type: BottomNavigationBarType.fixed,
fixedColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.grey,
// unselectedItemColor: const Color.fromRGBO(80, 87, 103, 1),
// backgroundColor: Colors.white,
//
currentIndex: _pageController._pageIndexState.pageIndex.value,
//tabBottom的点击监听
onTap: (index) {
print('appbar下标${index}');
_pageController._pageIndexState.pageController.jumpToPage(index);
},
);

View File

@ -11,7 +11,7 @@ import 'annotate_class_logic.dart';
import 'widget/completed_annotate_item.dart';
class AnnotateClassPage extends StatefulWidget {
const AnnotateClassPage({Key? key}) : super(key: key);
const AnnotateClassPage({super.key});
@override
State<AnnotateClassPage> createState() => _AnnotateClassPageState();
@ -25,109 +25,110 @@ class _AnnotateClassPageState extends State<AnnotateClassPage> {
Widget build(BuildContext context) {
String homeworkId = state.homeworkId.value;
return OrientationBuilder(
builder: (BuildContext context, Orientation orientation){
return Scaffold(
backgroundColor: const Color.fromRGBO(245, 245, 245, 1),
appBar: AppBar(
backgroundColor: Colors.white,
title: Obx(() {
return Text(state.name.value, style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)));
}),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () {
Get.back();
builder: (BuildContext context, Orientation orientation) {
return Scaffold(
backgroundColor: const Color.fromRGBO(245, 245, 245, 1),
appBar: AppBar(
backgroundColor: Colors.white,
title: Obx(() {
return Text(state.name.value,
style:
TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)));
}),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () {
Get.back();
},
),
actions: const [
ReturnToHomepage(),
],
),
body: Padding(
padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r),
child: Obx(() {
return EasyRefresh(
firstRefresh: false,
taskIndependence: true,
controller: logic.refreshController,
header: MaterialHeader(),
footer: TaurusFooter(),
onRefresh: () async {
return logic.getList();
},
),
actions: const [
ReturnToHomepage(),
],
),
body: Padding(
padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r),
child: Obx(() {
return EasyRefresh(
firstRefresh: false,
taskIndependence: true,
controller: logic.refreshController,
header: MaterialHeader(),
footer: TaurusFooter(),
onRefresh: () async{
return logic.getList();
},
child: state.completed.value
? Utils.isPad()
child: state.completed.value
? Utils.isPad()
? GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, //widget
mainAxisSpacing: 10.h,
crossAxisSpacing: 6.w,
childAspectRatio: 1.48 //1widget
),
children: state.classList.map((taskItem) {
return CompletedAnnotateItem(
taskItem: taskItem,
logic: logic,
name: state.name.value,
);
}).toList(),
)
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, //widget
mainAxisSpacing: 10.h,
crossAxisSpacing: 6.w,
childAspectRatio: 1.48 //1widget
),
children: state.classList.map((taskItem) {
return CompletedAnnotateItem(
taskItem: taskItem,
logic: logic,
name: state.name.value,
);
}).toList(),
)
: ListView.builder(
itemCount: state.classList.length,
itemBuilder: (context, index) {
AnnotatedClass taskItem = state.classList[index];
return CompletedAnnotateItem(
taskItem: taskItem,
logic: logic,
name: state.name.value,
);
})
: Utils.isPad()
itemCount: state.classList.length,
itemBuilder: (context, index) {
AnnotatedClass taskItem = state.classList[index];
return CompletedAnnotateItem(
taskItem: taskItem,
logic: logic,
name: state.name.value,
);
})
: Utils.isPad()
? MasonryGridView.count(
crossAxisCount: 2, //
mainAxisSpacing: 4.w, //
crossAxisSpacing: 4.h, //
itemCount: state.classList.length,
itemBuilder: (context, index) {
AnnotatedClass item = state.classList[index];
return AnnotateItem(
homeworkId: homeworkId,
item: item,
font: 11.sp,
name: state.name.value,
logic: logic,
);
},
)
crossAxisCount: 2, //
mainAxisSpacing: 4.w, //
crossAxisSpacing: 4.h, //
itemCount: state.classList.length,
itemBuilder: (context, index) {
AnnotatedClass item = state.classList[index];
return AnnotateItem(
homeworkId: homeworkId,
item: item,
font: 11.sp,
name: state.name.value,
logic: logic,
);
},
)
: ListView.builder(
itemCount: state.classList.length,
itemBuilder: (context, index) {
AnnotatedClass item = state.classList[index];
return AnnotateItem(
homeworkId: homeworkId,
item: item,
font: 12.sp,
name: state.name.value,
logic: logic,
);
}));
}),
),
);
}
);
itemCount: state.classList.length,
itemBuilder: (context, index) {
AnnotatedClass item = state.classList[index];
return AnnotateItem(
homeworkId: homeworkId,
item: item,
font: 12.sp,
name: state.name.value,
logic: logic,
);
}));
}),
),
);
});
}
@override
void dispose() {
Get.delete<AnnotateClassLogic>();
super.dispose();
if(state.preIndex != 3){
if (state.preIndex != 3) {
// logic.readOverController.state.tabIndex.value = state.preIndex;
}else{
} else {
// logic.homeController.getList();
}
}
}

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
@ -32,13 +31,21 @@ class AnswerHandwriting extends Dialog {
final String? questionNo;
final Function closeCall;
AnswerHandwriting(
{super.key, required this.homeworkId, required this.studentId, required this.closeCall, this.templateId, this.pageNum, this.questionNo});
{super.key,
required this.homeworkId,
required this.studentId,
required this.closeCall,
this.templateId,
this.pageNum,
this.questionNo});
final _handwritingLogic = Get.find<HandwritingLogic>();
@override
Widget build(BuildContext context) {
return OrientationBuilder(builder: (BuildContext context, Orientation orientation) {
return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
var boxHeight = ScreenUtil().screenHeight / 1.168; //
var boxWidth = ScreenUtil().screenWidth - (ScreenUtil().scaleWidth < 1.5 ? 40.r : 40.r); //
var boxWidth = ScreenUtil().screenWidth -
(ScreenUtil().scaleWidth < 1.5 ? 40.r : 40.r); //
return Center(
child: Container(
@ -75,7 +82,8 @@ Future<void> showAnswerHandwriting(
}
Get.put(HandwritingLogic(backCall));
Get.find<HandwritingLogic>().params.value = OriginalManuscriptHandwritingParams(
Get.find<HandwritingLogic>().params.value =
OriginalManuscriptHandwritingParams(
homeworkId: homeworkId,
studentId: studentId,
templateId: templateId,
@ -123,10 +131,12 @@ class AnswerHandwritingMainBox extends HookWidget with EventBusMixin {
@override
Widget build(BuildContext context) {
var _useStateModel = UseMainBoxState.use(homeworkId, studentId, pageNum, questionNo, templateId);
var _useStateModel = UseMainBoxState.use(
homeworkId, studentId, pageNum, questionNo, templateId);
double barHeight = 62.h;
double imageHeight = boxHeight - barHeight;
useValueChanged<JobHandwriting?, void>(_useStateModel.handwritingData.value, (_, __) {
useValueChanged<JobHandwriting?, void>(_useStateModel.handwritingData.value,
(_, __) {
var theData = _useStateModel.handwritingData.value;
_useStateModel.pageNum.value = theData?.pageNum;
_useStateModel.pageCount.value = theData?.pageCount ?? 0;
@ -210,7 +220,8 @@ class UseMainBoxState with RequestToolMixin {
});
//
factory UseMainBoxState.use(String homeworkId, int studentId, [int? pageNum, String? questionNo, int? templateId]) {
factory UseMainBoxState.use(String homeworkId, int studentId,
[int? pageNum, String? questionNo, int? templateId]) {
return UseMainBoxState._(
homeworkId: homeworkId,
templateId: templateId,
@ -236,7 +247,8 @@ class PreviousNutton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Obx(() {
if (handwritingLogic.resultData.value?.pageNum != null && handwritingLogic.resultData.value!.pageNum > 1) {
if (handwritingLogic.resultData.value?.pageNum != null &&
handwritingLogic.resultData.value!.pageNum > 1) {
return Positioned(
left: 3.w,
child: FloatingActionButton(
@ -252,7 +264,8 @@ class PreviousNutton extends StatelessWidget {
params.pageNum = resultData.pageNum - 1;
params.templateId = null;
params.questionNo = null;
handwritingLogic.params.value = OriginalManuscriptHandwritingParams.fromJson(params.toJson());
handwritingLogic.params.value =
OriginalManuscriptHandwritingParams.fromJson(params.toJson());
// handwritingLogic.params.value = params;
}),
child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp),
@ -275,7 +288,8 @@ class NextPageButton extends StatelessWidget {
Widget build(BuildContext context) {
return Obx(() {
if (handwritingLogic.resultData.value?.pageNum != null &&
handwritingLogic.resultData.value!.pageNum < handwritingLogic.resultData.value!.pageCount) {
handwritingLogic.resultData.value!.pageNum <
handwritingLogic.resultData.value!.pageCount) {
return Positioned(
right: 3.w,
child: FloatingActionButton(
@ -290,9 +304,11 @@ class NextPageButton extends StatelessWidget {
params.pageNum = resultData.pageNum + 1;
params.templateId = null;
params.questionNo = null;
handwritingLogic.params.value = OriginalManuscriptHandwritingParams.fromJson(params.toJson());
handwritingLogic.params.value =
OriginalManuscriptHandwritingParams.fromJson(params.toJson());
}),
child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
child:
Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
),
);
}
@ -306,13 +322,15 @@ class NextPageButton extends StatelessWidget {
class HandwritingDrawBox extends StatefulWidget {
final double boxWidth;
final double boxHeight;
const HandwritingDrawBox({required this.boxWidth, required this.boxHeight, super.key});
const HandwritingDrawBox(
{required this.boxWidth, required this.boxHeight, super.key});
@override
State<HandwritingDrawBox> createState() => _HandwritingDrawBoxState();
}
class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMixin {
class _HandwritingDrawBoxState extends State<HandwritingDrawBox>
with EventBusMixin {
HandwritingLogic handwritingLogic = Get.find<HandwritingLogic>(); //
ImageStream? imageStream; //
@ -351,13 +369,16 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
});
_vnHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]);
_vnPrimaryHandWritings = ValueNotifier<List<GestureHandwritingRecording>>(_packagedHandwritingDataAll);
_vnPrimaryHandWritings = ValueNotifier<List<GestureHandwritingRecording>>(
_packagedHandwritingDataAll);
handwritingLogic.toolbar.initialization.listen((e) {
//
if (e) {
_packagedHandwritingDatas = handwritingLogic.packagedHandwritingDatas.value;
_packagedHandwritingDataAll = handwritingLogic.packagedHandwritingDataAll.value;
_packagedHandwritingDatas =
handwritingLogic.packagedHandwritingDatas.value;
_packagedHandwritingDataAll =
handwritingLogic.packagedHandwritingDataAll.value;
} else {
_packagedHandwritingDatas = [];
_packagedHandwritingDataAll = [];
@ -367,7 +388,9 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
try {
_vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll]; //
} catch (e) {
_vnPrimaryHandWritings = ValueNotifier<List<GestureHandwritingRecording>>(_packagedHandwritingDataAll);
_vnPrimaryHandWritings =
ValueNotifier<List<GestureHandwritingRecording>>(
_packagedHandwritingDataAll);
}
// eventFire(model: JobHandwritingPlaybarBus);
});
@ -421,7 +444,8 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
//
var _model = (e as PlaybackSpeedBus);
speed = _model.speed;
dragProgressBarInitData(handwritingDuration - handwritingTime, handwritingDuration);
dragProgressBarInitData(
handwritingDuration - handwritingTime, handwritingDuration);
break;
default:
}
@ -446,14 +470,18 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
});
timers = [];
// -=
if (recalculate && pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) {
if (recalculate &&
pendingData.isNotEmpty &&
handwritingTime > 0 &&
(handwritingDuration - handwritingTime > 0)) {
//
pendingData = pendingData.map((e) {
return GestureHandwritingRecording(
stroke: e.stroke,
data: e.data,
usageTime: e.usageTime,
intervalTime: e.intervalTime - (handwritingDuration - handwritingTime) * 1000,
intervalTime:
e.intervalTime - (handwritingDuration - handwritingTime) * 1000,
);
}).toList();
}
@ -473,7 +501,8 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
}
handwritingLogic.toolbar.showManuscript.value = false;
executableData.forEach((e) {
var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e));
var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed),
() => zhixinCall(e));
timers.add(ter);
});
} catch (e) {
@ -483,7 +512,8 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
Future<void> zhixinCall(GestureHandwritingRecording e) async {
if (mounted) {
List<GestureHandwritingRecording> trajectorys = handwritingLogic.toolbar.executionData.value..add(e);
List<GestureHandwritingRecording> trajectorys =
handwritingLogic.toolbar.executionData.value..add(e);
handwritingLogic.toolbar.executionData.value = List.from(trajectorys);
pendingData.remove(e); //
}
@ -539,20 +569,26 @@ class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMi
var paperPicture = handwritingLogic.resultData.value?.paperPicture;
if (paperPicture == null) return const SizedBox();
print('显示原稿:${handwritingLogic.toolbar.showManuscript.value} 数据:${_vnPrimaryHandWritings.value.length}');
print(
'显示原稿:${handwritingLogic.toolbar.showManuscript.value} 数据:${_vnPrimaryHandWritings.value.length}');
return RepaintBoundary(
child: CustomPaint(
foregroundPainter: HandWritingDrawingPainter(
ctrl: handwritingLogic.toolbar.showManuscript.value ? _vnPrimaryHandWritings : _vnHandWritings,
ctrl: handwritingLogic.toolbar.showManuscript.value
? _vnPrimaryHandWritings
: _vnHandWritings,
),
child: $TheCachedNetworkImage(
imageUrl: paperPicture,
(context, imageProvider) {
Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain);
Image imageWidget =
Image(image: imageProvider, fit: BoxFit.contain);
var imagInfoModel = handwritingLogic.imagInfoModel.value;
if (imagInfoModel == null || imagInfoModel.boxWidth != widget.boxWidth) {
if (imagInfoModel == null ||
imagInfoModel.boxWidth != widget.boxWidth) {
imageStream?.removeListener(theImageStreamListener);
imageStream = imageWidget.image.resolve(const ImageConfiguration());
imageStream =
imageWidget.image.resolve(const ImageConfiguration());
imageStream?.addListener(theImageStreamListener);
}
return imageWidget;
@ -590,7 +626,8 @@ class HandWritingDrawingPainter extends CustomPainter {
var _length = points.length;
for (int i = 0; i < _length; i++) {
GestureHandwritingRecording item = points[i];
GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null;
GestureHandwritingRecording? nextItem =
i + 1 < _length ? points[i + 1] : null;
Offset offsetData = item.data;
Offset? nextOffsetData = nextItem?.data;
@ -604,7 +641,8 @@ class HandWritingDrawingPainter extends CustomPainter {
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
if (oldDelegate is HandWritingDrawingPainter) {
var repaint = ctrl.value.length != oldDelegate.ctrl.value.length || oldDelegate.ctrl.value != ctrl.value;
var repaint = ctrl.value.length != oldDelegate.ctrl.value.length ||
oldDelegate.ctrl.value != ctrl.value;
print('调用是否绘制:$repaint');
return repaint;
}
@ -616,7 +654,8 @@ class HandWritingDrawingPainter extends CustomPainter {
class PageNumberBox extends StatelessWidget {
PageNumberBox({super.key});
final HandwritingLogic handwritingLogic = Get.find<HandwritingLogic>(); //
final HandwritingLogic handwritingLogic =
Get.find<HandwritingLogic>(); //
@override
Widget build(BuildContext context) {
@ -634,11 +673,20 @@ class PageNumberBox extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Obx(() {
return quickText('${handwritingLogic.resultData.value?.pageNum ?? 0}', color: Colors.white, size: 11.sp, align: TextAlign.end);
return quickText(
'${handwritingLogic.resultData.value?.pageNum ?? 0}',
color: Colors.white,
size: 11.sp,
align: TextAlign.end);
}),
quickText('/', color: Colors.white, size: 10.sp, align: TextAlign.end),
quickText('/',
color: Colors.white, size: 10.sp, align: TextAlign.end),
Obx(() {
return quickText('${handwritingLogic.resultData.value?.pageCount ?? 0}', color: Colors.white, size: 8.sp, align: TextAlign.end);
return quickText(
'${handwritingLogic.resultData.value?.pageCount ?? 0}',
color: Colors.white,
size: 8.sp,
align: TextAlign.end);
}),
],
)),
@ -647,7 +695,8 @@ class PageNumberBox extends StatelessWidget {
}
@hwidget
Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic handwritingLogic) {
Widget $bottomPlaybar(
BuildContext context, double barHeight, HandwritingLogic handwritingLogic) {
var timeConsuming = useState(0);
var handwritingInfo = useState<HandwritingInfo?>(null);
@ -665,8 +714,10 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value;
});
//
useValueChanged<PlaybackSpeed, void>(usePlaybar.constantFastSpeed.value, (_, __) {
usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed));
useValueChanged<PlaybackSpeed, void>(usePlaybar.constantFastSpeed.value,
(_, __) {
usePlaybar.eventFire(
model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed));
//
usePlaybar.playTimingSuspend();
usePlaybar.playTimingStarts();
@ -675,9 +726,12 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
useValueChanged<int, void>(usePlaybar.useTime.value, (_, __) {
var _runtime = usePlaybar.useTime.value;
if (_runtime <= 0 || usePlaybar.handwritingDuration.value == _runtime) {
Future.delayed(Duration.zero, () => (usePlaybar.playPause.value = false)); //
Future.delayed(
Duration.zero, () => (usePlaybar.playPause.value = false)); //
}
usePlaybar.eventFire(model: JobHandwritingRunTimeBus(_runtime, usePlaybar.handwritingDuration.value));
usePlaybar.eventFire(
model: JobHandwritingRunTimeBus(
_runtime, usePlaybar.handwritingDuration.value));
});
useEffect(() {
@ -708,7 +762,8 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
break;
case JobHandwritingGetReadyBus:
//
Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true));
Future.delayed(
Duration.zero, () => (usePlaybar.handWritingReady.value = true));
break;
default:
}
@ -737,13 +792,17 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
if (usePlaybar.handWritingReady.value)
InkWell(
onTap: () => easyThrottle('job_handwriting_play_pause', () {
if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹');
if (usePlaybar.handwritingDuration.value == 0)
return ToastUtils.showInfo('没有笔迹');
usePlaybar.playPause.value = !usePlaybar.playPause.value;
usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
usePlaybar.eventFire(
model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
}),
child: Icon(
!usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline,
!usePlaybar.playPause.value
? Icons.play_circle_outline
: Icons.pause_circle_outline,
color: Colors.white,
size: 28.r,
),
@ -755,28 +814,36 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
child: LayoutBuilder(builder: (context, constraints) {
final double containerWidth = constraints.maxWidth; //
var unitScale = containerWidth / timeConsuming.value; //
var pauseIntervalsLength = handwritingInfo.value?.pauseInterval.length ?? 0;
var pauseIntervalsLength =
handwritingInfo.value?.pauseInterval.length ?? 0;
List<Widget> pauseTickMarks = handwritingInfo.value?.pauseInterval.asMap().keys.map((e) {
bool isLast = e == pauseIntervalsLength - 1;
bool isFirst = e == 0;
var item = handwritingInfo.value!.pauseInterval[e];
return Positioned(
top: 0,
left: unitScale * item.startTime,
child: Container(
width: unitScale * (item.apart ?? 0),
height: 10.h,
decoration: BoxDecoration(
color: Color.fromRGBO(202, 201, 201, 1),
borderRadius: isFirst
? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r))
: (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null),
),
),
);
}).toList() ??
[];
List<Widget> pauseTickMarks =
handwritingInfo.value?.pauseInterval.asMap().keys.map((e) {
bool isLast = e == pauseIntervalsLength - 1;
bool isFirst = e == 0;
var item = handwritingInfo.value!.pauseInterval[e];
return Positioned(
top: 0,
left: unitScale * item.startTime,
child: Container(
width: unitScale * (item.apart ?? 0),
height: 10.h,
decoration: BoxDecoration(
color: Color.fromRGBO(202, 201, 201, 1),
borderRadius: isFirst
? BorderRadius.only(
topLeft: Radius.circular(8.r),
bottomLeft: Radius.circular(10.r))
: (isLast
? BorderRadius.only(
topRight: Radius.circular(8.r),
bottomRight: Radius.circular(10.r))
: null),
),
),
);
}).toList() ??
[];
return Column(
mainAxisSize: MainAxisSize.min,
@ -800,29 +867,42 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 10.h, //
trackShape: RoundedRectSliderTrackShape(), //
activeTrackColor: Theme.of(context).primaryColor, //
trackShape:
RoundedRectSliderTrackShape(), //
activeTrackColor:
Theme.of(context).primaryColor, //
inactiveTrackColor: Colors.transparent, //
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0),
thumbShape: RoundSliderThumbShape(
enabledThumbRadius: 0, disabledThumbRadius: 0),
thumbColor: Colors.white, //
overlayShape: RoundSliderOverlayShape(overlayRadius: 0),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 0),
overlayColor: Colors.black54, //
// valueIndicatorShape: PaddleSliderValueIndicatorShape(), //
),
child: Slider(
value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(),
value: (usePlaybar.handwritingDuration.value -
usePlaybar.useTime.value)
.toDouble(),
min: 0.0,
max: usePlaybar.handwritingDuration.value.toDouble(),
inactiveColor: Colors.transparent,
onChangeEnd: (value) {
if (!usePlaybar.handWritingReady.value) return;
usePlaybar.playTimingSuspend(); //
usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value));
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
usePlaybar.eventFire(
model: JobHandwritingDragProgressBarBus(
value.toInt(),
usePlaybar.handwritingDuration.value));
usePlaybar.useTime.value =
usePlaybar.handwritingDuration.value -
value.toInt();
},
onChanged: (double value) {
if (!usePlaybar.handWritingReady.value) return;
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
usePlaybar.useTime.value =
usePlaybar.handwritingDuration.value -
value.toInt();
},
),
),
@ -835,8 +915,16 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
quickText('累计停顿:${handwritingInfo.value?.pauseCount ?? 0}', color: Colors.white, size: 7.sp),
quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp),
quickText(
'累计停顿:${handwritingInfo.value?.pauseCount ?? 0}',
color: Colors.white,
size: 7.sp),
quickText(
convertSeconds(usePlaybar.useTime.value)
?.toString() ??
'',
color: Colors.white,
size: 7.sp),
],
),
)
@ -851,16 +939,20 @@ Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic h
children: [
InkWell(
onTap: () => easyThrottle('job_handwriting_speed', () {
var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
var theIndex = PlaybackSpeed.values
.indexOf(usePlaybar.constantFastSpeed.value);
if (theIndex == PlaybackSpeed.values.length - 1) {
theIndex = -1;
}
usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
usePlaybar.constantFastSpeed.value =
PlaybackSpeed.values[theIndex + 1];
}, duration: Duration(milliseconds: 500)),
child: Container(
// alignment: Alignment.,
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
decoration: BoxDecoration(
color: Color.fromRGBO(182, 197, 250, 1),
borderRadius: BorderRadius.circular(4.r)),
child: quickText(
'${usePlaybar.constantFastSpeed.value.name}',
color: Color.fromRGBO(79, 114, 244, 1),
@ -895,9 +987,12 @@ class StudentManuscriptBtn extends StatelessWidget {
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r),
color: handwritingLogic.toolbar.showManuscript.value ? Theme.of(context).primaryColor : Colors.grey,
color: handwritingLogic.toolbar.showManuscript.value
? Theme.of(context).primaryColor
: Colors.grey,
),
child: quickText('学生原稿', color: Colors.white, size: 8.sp, align: TextAlign.center),
child: quickText('学生原稿',
color: Colors.white, size: 8.sp, align: TextAlign.center),
),
);
});
@ -911,7 +1006,8 @@ class SysjTime extends StatefulWidget {
State<SysjTime> createState() => _SysjTimeState();
}
class _SysjTimeState extends State<SysjTime> with EventBusMixin<JobHandwritingRunTimeBus> {
class _SysjTimeState extends State<SysjTime>
with EventBusMixin<JobHandwritingRunTimeBus> {
int useTime = 0;
@override
void initState() {
@ -930,7 +1026,8 @@ class _SysjTimeState extends State<SysjTime> with EventBusMixin<JobHandwritingRu
@override
Widget build(BuildContext context) {
return quickText(convertSeconds(useTime)?.toString() ?? '', color: Colors.white, size: 7.sp);
return quickText(convertSeconds(useTime)?.toString() ?? '',
color: Colors.white, size: 7.sp);
}
}
@ -971,7 +1068,9 @@ class UseBottomPlaybar with EventBusMixin {
if (useTime.value > 0) {
timer.value?.cancel();
timer.value = Timer.periodic(Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), (theTime) {
timer.value = Timer.periodic(
Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed),
(theTime) {
useTime.value -= 1;
if (useTime.value < 0) {
theTime.cancel();

View File

@ -41,13 +41,15 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
//
Expanded(
flex: 7,
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
var maxWidth = constraints.maxWidth;
var maxHeight = constraints.maxHeight;
return Stack(
children: [
//
QuestionImageView(maxWidth, maxHeight, sateData, annotationState, logic),
QuestionImageView(
maxWidth, maxHeight, sateData, annotationState, logic),
//
// Positioned(right: 3.w, bottom: 4.h, child: const $ContinueToReview(isFloatingAction: true)),
//
@ -61,15 +63,19 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
heroTag: '点击前往上一题',
tooltip: '点击前往上一题',
focusColor: Theme.of(context).primaryColor,
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.05),
backgroundColor:
const Color.fromRGBO(24, 32, 32, 0.05),
elevation: 10.r,
onPressed: () => easyThrottle('TestQuestionSwitch', () {
onPressed: () =>
easyThrottle('TestQuestionSwitch', () {
var param = sateData.param.value;
param.studentId = lastPageVal.studentId;
param.templateId = lastPageVal.templateId;
sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson());
sateData.param.value =
DoPaperDetailsParam.fromJson(param.toJson());
}),
child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp),
child: Icon(Icons.arrow_back_ios,
color: Colors.white, size: 22.sp),
);
}),
),
@ -84,14 +90,18 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
heroTag: '点击前往下一题',
tooltip: '点击前往下一题',
elevation: 10.r,
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.05),
onPressed: () => easyThrottle('TestQuestionSwitch', () {
backgroundColor:
const Color.fromRGBO(24, 32, 32, 0.05),
onPressed: () =>
easyThrottle('TestQuestionSwitch', () {
var param = sateData.param.value;
param.studentId = nextPageVal.studentId;
param.templateId = nextPageVal.templateId;
sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson());
sateData.param.value =
DoPaperDetailsParam.fromJson(param.toJson());
}),
child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
child: Icon(Icons.arrow_forward_ios,
color: Colors.white, size: 22.sp),
);
}),
),
@ -112,7 +122,8 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
child: CupertinoButton(
color: Colors.grey[300],
onPressed: () => easyThrottle('home_work_reload_data', () {
sateData.param.value = DoPaperDetailsParam.fromJson(sateData.param.value.toJson());
sateData.param.value =
DoPaperDetailsParam.fromJson(sateData.param.value.toJson());
}),
child: quickText('重新请求', color: Colors.black38),
),
@ -125,7 +136,8 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
//
@swidget
Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData) {
Widget $totalSubmitCountView(
BuildContext context, HomeworkReviewState sateData) {
return Obx(() {
var data = sateData.data.value;
if (data == null) return Container();
@ -140,7 +152,10 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
context: context,
elevation: 10,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(10.r))),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.r),
topRight: Radius.circular(10.r))),
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w),
@ -158,7 +173,8 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
SizedBox(height: 10.h),
Expanded(
child: ListView(
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w),
padding: EdgeInsets.symmetric(
vertical: 8.h, horizontal: 4.w),
children: [
Wrap(
spacing: 7.2.w, // ()
@ -169,27 +185,40 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
alignment: const FractionalOffset(0.05, 0.09),
children: [
Container(
padding: EdgeInsets.only(top: 1.2.h, bottom: 1.5.h, left: 13.w, right: 5.w),
padding: EdgeInsets.only(
top: 1.2.h,
bottom: 1.5.h,
left: 13.w,
right: 5.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r),
color: const Color.fromRGBO(239, 242, 255, 1),
color: const Color.fromRGBO(
239, 242, 255, 1),
),
child: quickText(
e.name,
size: 12.sp,
wordSpacing: 2,
color: const Color.fromRGBO(80, 94, 110, 1),
color:
const Color.fromRGBO(80, 94, 110, 1),
),
),
Stack(
alignment: const FractionalOffset(0.52, 0.24),
alignment:
const FractionalOffset(0.52, 0.24),
children: [
Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"),
const IconData(0xe63d,
fontFamily: "AlibabaIcon"),
size: 12.sp,
color: e.isPriority ? const Color.fromRGBO(76, 199, 147, 1) : const Color.fromRGBO(164, 164, 164, 1),
color: e.isPriority
? const Color.fromRGBO(
76, 199, 147, 1)
: const Color.fromRGBO(
164, 164, 164, 1),
),
quickText('优先', size: 4.sp, color: Colors.white),
quickText('优先',
size: 4.sp, color: Colors.white),
],
),
],
@ -211,11 +240,17 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
children: [
Padding(
padding: EdgeInsets.only(bottom: 1.h),
child: quickText('已阅', color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
child: quickText('已阅',
color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
),
quickText(data.annotatedCount, color: const Color.fromRGBO(76, 199, 147, 1), size: 12.sp, fontWeight: FontWeight.bold),
quickText('/', color: const Color.fromRGBO(117, 117, 117, 1), size: 12.sp),
quickText(data.submitCount - data.annotatedCount, color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
quickText(data.annotatedCount,
color: const Color.fromRGBO(76, 199, 147, 1),
size: 12.sp,
fontWeight: FontWeight.bold),
quickText('/',
color: const Color.fromRGBO(117, 117, 117, 1), size: 12.sp),
quickText(data.submitCount - data.annotatedCount,
color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
],
),
),
@ -225,15 +260,18 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
//
@hwidget
Widget $questionNumberView(BuildContext context, HomeworkReviewLogic logic, HomeworkReviewState sateData) {
Widget $questionNumberView(BuildContext context, HomeworkReviewLogic logic,
HomeworkReviewState sateData) {
final scrollControllerNum = useScrollController(); //
useEffect(() {
scrollControllerNum.addListener(() {
if (sateData.panQuestView == false) sateData.slide.value = scrollControllerNum.offset;
if (sateData.panQuestView == false)
sateData.slide.value = scrollControllerNum.offset;
});
var listenVal = sateData.slide.listen((e) {
if (e != scrollControllerNum.offset && sateData.panQuestView == true) scrollControllerNum.jumpTo(e);
if (e != scrollControllerNum.offset && sateData.panQuestView == true)
scrollControllerNum.jumpTo(e);
});
return () {
@ -271,13 +309,20 @@ Widget $questionNumberView(BuildContext context, HomeworkReviewLogic logic, Home
return Container(
height: boxHeight > actualImgHeight ? boxHeight : actualImgHeight,
padding: EdgeInsets.only(top: imageVal.remainingHeight > 0 ? imageVal.remainingHeight / 2 : 0),
padding: EdgeInsets.only(
top: imageVal.remainingHeight > 0
? imageVal.remainingHeight / 2
: 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: studentQuestions
?.asMap()
.keys
.map((e) => $ScoringQuestionsView(logic, studentQuestions[e], imageVal.scaleRatio, studentQuestions))
.map((e) => $ScoringQuestionsView(
logic,
studentQuestions[e],
imageVal.scaleRatio,
studentQuestions))
.toList() ??
[],
),
@ -290,7 +335,11 @@ Widget $questionNumberView(BuildContext context, HomeworkReviewLogic logic, Home
//
@hwidget
Widget $scoringQuestionsView(
BuildContext context, HomeworkReviewLogic logic, StudentQuestions item, double scaleRatio, List<StudentQuestions>? studentQuestions) {
BuildContext context,
HomeworkReviewLogic logic,
StudentQuestions item,
double scaleRatio,
List<StudentQuestions>? studentQuestions) {
var studentScore = useState<int?>(item.studentScore);
useValueChanged<int?, void>(studentScore.value, (_, __) {
@ -299,7 +348,8 @@ Widget $scoringQuestionsView(
//
var annotateTime = logic.state.data.value?.annotateTime;
if (annotateTime == null) {
var noRatingGiven = studentQuestions!.firstWhereOrNull((e) => e.studentScore == null);
var noRatingGiven =
studentQuestions!.firstWhereOrNull((e) => e.studentScore == null);
if (noRatingGiven == null) logic.submit(context);
}
});
@ -312,7 +362,9 @@ Widget $scoringQuestionsView(
return () {};
}, []);
var padinVal = item.correctRate > 0 ? EdgeInsets.only(top: 6.4.h) : EdgeInsets.symmetric(vertical: 2.h);
var padinVal = item.correctRate > 0
? EdgeInsets.only(top: 6.4.h)
: EdgeInsets.symmetric(vertical: 2.h);
return Container(
height: item.height * scaleRatio,
padding: EdgeInsets.zero,
@ -328,20 +380,24 @@ Widget $scoringQuestionsView(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), //
backgroundColor:
const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 2 ? const Color.fromRGBO(255, 152, 0, 1) : const Color.fromRGBO(114, 114, 114, 1),
color: studentScore.value == 2
? const Color.fromRGBO(255, 152, 0, 1)
: const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62b, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 2 ? null : 2;
}),
}, duration: const Duration(milliseconds: 222)),
),
),
//
@ -350,20 +406,24 @@ Widget $scoringQuestionsView(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), //
backgroundColor:
const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 1 ? const Color.fromRGBO(255, 152, 0, 1) : const Color.fromRGBO(114, 114, 114, 1),
color: studentScore.value == 1
? const Color.fromRGBO(255, 152, 0, 1)
: const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62c, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 1 ? null : 1;
}),
}, duration: const Duration(milliseconds: 222)),
),
),
//
@ -372,20 +432,24 @@ Widget $scoringQuestionsView(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), //
backgroundColor:
const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 0 ? const Color.fromRGBO(255, 152, 0, 1) : const Color.fromRGBO(114, 114, 114, 1),
color: studentScore.value == 0
? const Color.fromRGBO(255, 152, 0, 1)
: const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62a, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 0 ? null : 0;
}),
}, duration: const Duration(milliseconds: 222)),
),
),
],
@ -396,8 +460,11 @@ Widget $scoringQuestionsView(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: 1.1.w),
quickText('${item.questionNo}', color: Theme.of(context).primaryColor.withOpacity(0.7), size: 8.sp),
if (item.correctRate > 0) quickText(' 正确率', color: Colors.grey, size: 5.sp),
quickText('${item.questionNo}',
color: Theme.of(context).primaryColor.withOpacity(0.7),
size: 8.sp),
if (item.correctRate > 0)
quickText(' 正确率', color: Colors.grey, size: 5.sp),
if (item.correctRate > 0)
Expanded(
child: LinearPercentIndicator(
@ -407,7 +474,10 @@ Widget $scoringQuestionsView(
alignment: MainAxisAlignment.center,
progressColor: const Color.fromRGBO(76, 199, 147, 0.6),
backgroundColor: const Color(0xFFB8C7CB).withOpacity(0.35),
center: quickText("${item.correctRate}%", size: 5.sp, align: TextAlign.center, color: Colors.white),
center: quickText("${item.correctRate}%",
size: 5.sp,
align: TextAlign.center,
color: Colors.white),
),
)
],
@ -419,13 +489,16 @@ Widget $scoringQuestionsView(
}
//
class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar> {
class QuestionImageView extends HookWidget
with EventBusMixin<BottomOperationBar> {
final double maxWidth;
final double maxHeight;
final HomeworkReviewLogic logic;
final HomeworkReviewState sateData;
final HomeworkReviewAnnotationsControlState annotationState;
QuestionImageView(this.maxWidth, this.maxHeight, this.sateData, this.annotationState, this.logic, {super.key});
QuestionImageView(this.maxWidth, this.maxHeight, this.sateData,
this.annotationState, this.logic,
{super.key});
///
int _findTargetIndex<T>(List<T> list, T target, [int reciprocal = 2]) {
@ -456,7 +529,8 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
}, []);
ImageStream? imageStream;
var imageStreamListener = useState<ImageStreamListener>(ImageStreamListener((ImageInfo info, bool _) {
var imageStreamListener = useState<ImageStreamListener>(
ImageStreamListener((ImageInfo info, bool _) {
WidgetsBinding.instance.addPostFrameCallback((_) {
sateData.imageScale.value = TestQuestionsImageInfo(
templateId: sateData.data.value?.templateId,
@ -479,10 +553,17 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
bool? res = await showDialog<bool>(
context: context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销全部批注痕迹?"), actions: <Widget>[
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)),
TextButton(child: quickText("确定", color: Theme.of(context).primaryColor), onPressed: () => Navigator.pop(context1, true))
]);
return AlertDialog(
content: quickText("是否撤销全部批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context).primaryColor),
onPressed: () => Navigator.pop(context1, true))
]);
},
);
if (res == true) vnHandWritings.value = [];
@ -492,17 +573,22 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
await showDialog<bool>(
context: context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹?"), actions: <Widget>[
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定", color: Theme.of(context).primaryColor),
onPressed: () {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
},
)
]);
return AlertDialog(
content: quickText("是否撤销上次批阅批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context).primaryColor),
onPressed: () {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
},
)
]);
},
);
}
@ -517,17 +603,22 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
await showDialog<bool>(
context: context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹?"), actions: <Widget>[
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定", color: Theme.of(context).primaryColor),
onPressed: () {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
},
)
]);
return AlertDialog(
content: quickText("是否撤销上次批阅批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context).primaryColor),
onPressed: () {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
},
)
]);
},
);
}
@ -548,7 +639,8 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
}); //
var listenVal = sateData.slide.listen((e) {
if (e != scrollControllerQuestion.offset && sateData.panQuestView == false) scrollControllerQuestion.jumpTo(e);
if (e != scrollControllerQuestion.offset &&
sateData.panQuestView == false) scrollControllerQuestion.jumpTo(e);
});
//
@ -572,12 +664,19 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
onPanDown: (_) => sateData.panQuestView = true,
child: SingleChildScrollView(
controller: scrollControllerQuestion,
physics: !annotationState.pen.value ? const BouncingScrollPhysics() : const NeverScrollableScrollPhysics(),
physics: !annotationState.pen.value
? const BouncingScrollPhysics()
: const NeverScrollableScrollPhysics(),
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical, //
child: Container(
decoration: BoxDecoration(
boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.2), offset: Offset(-6.r, 1.r), blurRadius: 10.r, spreadRadius: 8.r)]),
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
offset: Offset(-6.r, 1.r),
blurRadius: 10.r,
spreadRadius: 8.r)
]),
child: Listener(
behavior: HitTestBehavior.opaque,
onPointerDown: (PointerDownEvent event) {
@ -604,9 +703,11 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
if (imageScale == null || !annotationState.pen.value) return;
Offset localPosition = event.localPosition;
var dy = localPosition.dy;
if (dy > imageScale.actualImgHeight || dy < 0) return; //
if (dy > imageScale.actualImgHeight || dy < 0)
return; //
vnHandWritings.value = List.from(vnHandWritings.value)..add(localPosition);
vnHandWritings.value = List.from(vnHandWritings.value)
..add(localPosition);
sateData.handwritings = vnHandWritings.value;
},
child: Stack(
@ -614,9 +715,12 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
$TheCachedNetworkImage(
imageUrl: imageUrl,
(context, imageProvider) {
Image imageWidget = Image(image: imageProvider, fit: BoxFit.fitWidth);
Image imageWidget =
Image(image: imageProvider, fit: BoxFit.fitWidth);
imageStream?.removeListener(imageStreamListener.value);
imageStream = imageWidget.image.resolve(const ImageConfiguration())..addListener(imageStreamListener.value);
imageStream = imageWidget.image
.resolve(const ImageConfiguration())
..addListener(imageStreamListener.value);
return imageWidget;
},
),
@ -631,7 +735,8 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
child: showZgtAnnotate != null
? $TheCachedNetworkImage(
imageUrl: showZgtAnnotate,
(_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth),
(_, imageProvider) => Image(
image: imageProvider, fit: BoxFit.fitWidth),
)
: null,
),
@ -663,7 +768,8 @@ class DrawingPainter extends CustomPainter {
for (int i = 0; i < pointsLength; i++) {
Offset? offsetData = points[i];
Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1];
if (offsetData != null && nextOffsetData != null) canvas.drawLine(offsetData, nextOffsetData, paintBrush);
if (offsetData != null && nextOffsetData != null)
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
}
}

View File

@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui;
@ -16,7 +15,6 @@ import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dar
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/personnel_data_overview.dart';
//
class HomeworkReviewState {
@ -63,7 +61,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
late StreamSubscription<DoPaperDetailsParam> _paramListen;
late StreamSubscription<DoPaperDetailsResult?> _dataListen;
final HomeworkReviewState state = HomeworkReviewState();
final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState();
final HomeworkReviewAnnotationsControlState annotationState =
HomeworkReviewAnnotationsControlState();
@override
void onInit() {
@ -93,9 +92,11 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
}
void getData() async {
var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading());
var timerControl = Timer(
const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try {
DoPaperDetailsResult? data = await getClient().getDoPaperDetails(state.param.value);
DoPaperDetailsResult? data =
await getClient().getDoPaperDetails(state.param.value);
// var studentQuestions = data.studentQuestions;
// // 0
// for (var i = 0; i < studentQuestions.length; i++) {
@ -107,8 +108,6 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
state.data.value = data;
state.handwritings = [];
state.studentQuestions.value = data.studentQuestions;
} catch (e) {
print('获取数据报错了:$e');
ToastUtils.showError('获取试题数据出错,请重试');
@ -118,7 +117,6 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
ToastUtils.dismiss();
}
}
//
@ -170,12 +168,16 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
if (data == null) return null;
// OSS url
String imgKey = UploadOssImgUtils.getInstance().setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString());
String imgKey = UploadOssImgUtils.getInstance().setImgKey(
param.homeworkId,
data.studentId.toString(),
data.templateId.toString());
var resUrl = await getClient().getOssPresignedUri(imgKey);
if (resUrl == null) return null;
//
RenderRepaintBoundary? boundary = pictureOverviewKey.currentContext!.findRenderObject() as RenderRepaintBoundary?;
RenderRepaintBoundary? boundary = pictureOverviewKey.currentContext!
.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) return null;
// double dpr = MediaQuery.of(context).devicePixelRatio;
@ -187,16 +189,20 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
}
ui.Image image = await boundary.toImage(pixelRatio: pixelRatio);
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
ByteData? byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
if (byteData == null) return null;
Dio dio = Dio();
dio.options.contentType = null;
List<int> bytes = byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes);
List<int> bytes = byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes);
await dio.put(
resUrl,
data: Stream.fromIterable(bytes.map((e) => [e])),
options: Options(contentType: null, headers: {Headers.contentLengthHeader: bytes.length}),
options: Options(
contentType: null,
headers: {Headers.contentLengthHeader: bytes.length}),
);
return imgKey;
@ -218,7 +224,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
if (state.data.value?.studentQuestions.isEmpty ?? true) return;
var studentQuestions = state.data.value!.studentQuestions;
var noRatingElement = studentQuestions.firstWhereOrNull((e) => e.studentScore == null);
var noRatingElement =
studentQuestions.firstWhereOrNull((e) => e.studentScore == null);
if (noRatingElement != null) {
ToastUtils.showInfo('${noRatingElement.questionNo}题请评分');
return;
@ -247,7 +254,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
.then((e) async {
state.needRefresh = true;
var totalUnAnnotateCount = data.totalUnAnnotateCount;
if (data.annotateTime == null) totalUnAnnotateCount -= 1;
if (data.needAnnotate) totalUnAnnotateCount -= 1; //
if (totalUnAnnotateCount <= 0 && !state.lastQuestionPrompt) {
//
@ -256,7 +263,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
builder: (BuildContext context1) {
return AlertDialog(
title: quickText('批阅已完成'),
content: const Text('暂无更多批阅项'),
content: const Text('暂无更多批阅项'),
actions: <Widget>[
TextButton(
child: const Text('继续'),

View File

@ -1,13 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart';
import 'package:making_school_asignment_app/page/home_page/home_logic.dart';
import 'components/bottom_operation_bar.dart';
import 'components/button_floating_action.dart';
import 'components/dropdown_switch_students_type.dart';
import 'components/favorite_widget.dart';
import 'components/question_paper_view.dart';
@ -24,6 +23,7 @@ class _HomeworkReviewState extends State<HomeworkReview> {
final logic = Get.find<HomeworkReviewLogic>();
final sateData = Get.find<HomeworkReviewLogic>().state;
final AnnotateClassLogic _controller = Get.find<AnnotateClassLogic>();
final HomeLogic _homeLogicController = Get.find<HomeLogic>();
@override
void initState() {
@ -42,18 +42,27 @@ class _HomeworkReviewState extends State<HomeworkReview> {
return PopScope(
canPop: false,
onPopInvoked: (e) {
if (e && sateData.needRefresh) _controller.getList();
if (e && sateData.needRefresh) {
_controller.getList();
_homeLogicController.getList();
}
},
child: SafeArea(
child: Scaffold(
appBar: AppBar(
// titleSpacing: 0,
leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () => Get.back()),
iconTheme: const IconThemeData(color: Colors.black),
title: quickText(sateData.param.value.homeworkName),
backgroundColor: Colors.white,
elevation: 0,
actions: [const FavoriteWidget(), SizedBox(width: 5.w), const ReturnToHomepage()],
actions: [
const FavoriteWidget(),
SizedBox(width: 5.w),
const ReturnToHomepage()
],
),
body: SafeArea(
child: Column(

View File

@ -26,26 +26,31 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
barrierDismissible: false,
context: context1,
builder: (context) {
return AlertDialog(title: quickText("提示信息"), content: quickText("您确定要退出登录吗?"), actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () {
Navigator.pop(context, 'Cancle');
},
),
TextButton(
child: quickText("确定"),
onPressed: () {
/* ref.read(markingKeyboardProvider.notifier).clean();
ref.read(markingSubtopicSwitchingProvider.notifier).clean();
ref.read(userTokenProvider.notifier).clean();
ref.read(userProvider.notifier).clean();*/
StorageService.to.remove(AppStorageKey.token.value);
StorageService.to.remove(AppStorageKey.userInfo.value);
Navigator.pop(context, "Ok");
Get.offAllNamed(Routes.login);
})
]);
return AlertDialog(
title: quickText("提示信息"),
content: quickText("您确定要退出登录吗?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () {
Navigator.pop(context, 'Cancle');
},
),
TextButton(
child: quickText("确定"),
onPressed: () async {
try {
UserStore.to.erase();
await StorageService.to.erase();
StorageService.to
.write(AppStorageKey.privacyAgreement.value, true);
Navigator.pop(context, "Ok");
Get.offAllNamed(Routes.login);
} catch (e) {
print(e);
}
})
]);
});
}
@ -65,119 +70,121 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
fontSize: 13.sp,
);
return OrientationBuilder(builder: (BuildContext context, Orientation orientation) {
return AnnotatedRegion(
value: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.dark,
),
child: Stack(
children: [
SizedBox(
height: double.infinity,
child: Column(
children: [
Container(
height: 220.h,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/personal_bgi.png'),
fit: BoxFit.cover,
),
return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return Stack(
children: [
SizedBox(
height: double.infinity,
child: Column(
children: [
Container(
height: 220.h,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/personal_bgi.png'),
fit: BoxFit.cover,
),
),
Expanded(
child: Container(
color: const Color.fromRGBO(248, 248, 248, 1),
))
],
),
),
Expanded(
child: Container(
color: const Color.fromRGBO(248, 248, 248, 1),
))
],
),
SafeArea(
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
children: [
Stack(
alignment: const FractionalOffset(0.04, 0.1),
children: [
Container(
height: 180.h,
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 10.r,
),
Image.asset(
'assets/images/default_user_dead.png',
),
SizedBox(
height: 10.r,
),
InkWell(
onTap: () {
/*if (tokenState == '' || userState.id == '') {
),
SafeArea(
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
children: [
Stack(
alignment: const FractionalOffset(0.04, 0.1),
children: [
Container(
height: 180.h,
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: 10.r,
),
Image.asset(
'assets/images/default_user_dead.png',
),
SizedBox(
height: 10.r,
),
InkWell(
onTap: () {
/*if (tokenState == '' || userState.id == '') {
toLoginPage(context);
}*/
},
child: Container(
margin: EdgeInsets.only(top: 0.h),
child: Text(
userInfo.value?.name ?? '请前往登录',
style: TextStyle(fontSize: 13.sp, color: Colors.white),
),
},
child: Container(
margin: EdgeInsets.only(top: 0.h),
child: Text(
userInfo.value?.name ?? '请前往登录',
style: TextStyle(
fontSize: 13.sp, color: Colors.white),
),
),
],
),
),
],
),
/* InkWell(
),
/* InkWell(
onTap: () => Get.back(),
child: Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24.sp),
),*/
],
),
SizedBox(height: 14.h),
Container(
margin:
EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w),
padding:
EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w),
height: 180.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
SizedBox(height: 14.h),
Container(
margin: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w),
height: 180.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('账号', style: personalInfoTitleStly), Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)],
),
Container(
height: 1.w,
color: const Color.fromRGBO(240, 243, 255, 1),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('所在学校', style: personalInfoTitleStly),
Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)
],
),
/* Row(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('账号', style: personalInfoTitleStly),
Text(userInfo.value?.name ?? '请前往登录',
style: personalInfoValStly)
],
),
Container(
height: 1.w,
color: const Color.fromRGBO(240, 243, 255, 1),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('所在学校', style: personalInfoTitleStly),
Text(userInfo.value?.schoolName ?? '',
style: personalInfoValStly)
],
),
/* Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('担任职位', style: personalInfoTitleStly),
@ -209,87 +216,93 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
)
],
),*/
Container(height: 1.w, color: const Color.fromRGBO(240, 243, 255, 1)),
Padding(
padding: EdgeInsets.only(top: 10.h),
child: InkWell(
onTap: () {
Get.toNamed(Routes.otherPage);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('其他', style: personalInfoTitleStly),
Icon(
Icons.arrow_forward_ios,
color: const Color.fromRGBO(80, 87, 103, 1),
size: 13.sp,
Container(
height: 1.w,
color: const Color.fromRGBO(240, 243, 255, 1)),
Padding(
padding: EdgeInsets.only(top: 10.h),
child: InkWell(
onTap: () {
Get.toNamed(Routes.otherPage);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('其他', style: personalInfoTitleStly),
Icon(
Icons.arrow_forward_ios,
color: const Color.fromRGBO(80, 87, 103, 1),
size: 13.sp,
)
],
),
),
)
],
),
),
Expanded(
child: Column(
children: [
const Expanded(child: SizedBox()),
Container(
margin: EdgeInsets.only(bottom: 40.h),
alignment: Alignment.bottomCenter,
child: InkWell(
child: Container(
padding: EdgeInsets.symmetric(vertical: 14.h),
margin: EdgeInsets.only(right: 16.w, left: 16.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(6.w),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color:
const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(2.w, 2.h), //y轴偏移量
blurRadius: 14, //
spreadRadius: 0.5, //
)
],
),
),
)
],
),
),
Expanded(
child: Column(
children: [
const Expanded(child: SizedBox()),
Container(
margin: EdgeInsets.only(bottom: 40.h),
alignment: Alignment.bottomCenter,
child: InkWell(
child: Container(
padding: EdgeInsets.symmetric(vertical: 14.h),
margin: EdgeInsets.only(right: 16.w, left: 16.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(6.w),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.exit_to_app_outlined,
size: 13.sp,
color:
const Color.fromRGBO(148, 163, 182, 1),
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(2.w, 2.h), //y轴偏移量
blurRadius: 14, //
spreadRadius: 0.5, //
)
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.exit_to_app_outlined,
size: 13.sp,
color: const Color.fromRGBO(148, 163, 182, 1),
),
Container(
width: 6.w,
),
Text(
'退出登录',
style: TextStyle(color: const Color.fromRGBO(148, 163, 182, 1), fontSize: 13.sp),
),
],
),
Container(
width: 6.w,
),
Text(
'退出登录',
style: TextStyle(
color: const Color.fromRGBO(
148, 163, 182, 1),
fontSize: 13.sp),
),
],
),
onTap: () {
_showAlertDialog(context);
},
),
onTap: () {
_showAlertDialog(context);
},
),
],
),
),
],
),
],
),
),
],
),
),
],
),
),
],
);
});
}

View File

@ -27,9 +27,7 @@ class ReadOverPage extends StatefulWidget {
class _ReadOverPageState extends State<ReadOverPage> {
final logic = Get.find<ReadOverLogic>();
final state = Get
.find<ReadOverLogic>()
.state;
final state = Get.find<ReadOverLogic>().state;
@override
Widget build(BuildContext context) {
@ -39,7 +37,7 @@ class _ReadOverPageState extends State<ReadOverPage> {
systemNavigationBarDividerColor: null,
statusBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.light,
),
child: Scaffold(
@ -50,10 +48,7 @@ class _ReadOverPageState extends State<ReadOverPage> {
children: <Widget>[
Container(
color: Colors.white,
margin: EdgeInsets.only(top: MediaQuery
.of(context)
.padding
.top),
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
padding: EdgeInsets.only(bottom: 9.h, top: 4.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
@ -98,12 +93,10 @@ class _ReadOverPageState extends State<ReadOverPage> {
color: const Color(0xFF4CC793),
),
// labelColor: const Color.fromRGBO(45, 56, 76, 1),
indicator: const UnderlineTabIndicator(
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(
width: 0, // 0线
color: Colors.transparent
),
width: 0, // 0线
color: Colors.transparent),
),
onTap: (index) {
state.tabIndex.value = index;
@ -122,23 +115,14 @@ class _ReadOverPageState extends State<ReadOverPage> {
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 0
? const Color.fromRGBO(
255, 255, 255, 1)
: null,
borderRadius: BorderRadius.all(
Radius.circular(8.r)),
color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'待批阅',
size: 14.sp,
color: state.tabIndex.value == 0 ? Theme
.of(context)
.primaryColor : const Color.fromRGBO(
80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0
? FontWeight.bold
: null,
color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
),
);
}),
@ -151,23 +135,14 @@ class _ReadOverPageState extends State<ReadOverPage> {
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 1
? const Color.fromRGBO(
255, 255, 255, 1)
: null,
borderRadius: BorderRadius.all(
Radius.circular(8.r)),
color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'已批阅',
size: 14.sp,
color: state.tabIndex.value == 1 ? Theme
.of(context)
.primaryColor : const Color.fromRGBO(
80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1
? FontWeight.bold
: null,
color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
),
);
}),
@ -180,22 +155,22 @@ class _ReadOverPageState extends State<ReadOverPage> {
flex: 1,
child: InkWell(
onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage,
arguments: {'page': 'set'});
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
},
child: Icon(
const IconData(0xe63e, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(44, 48, 63, 1),
size: 24.sp),
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
),
),
],
),
),
Expanded(child: Obx(() {
return AnnotateList(tabIndex: state.tabIndex.value,assessType: 0,);
}),),
Expanded(
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 0,
);
}),
),
],
);
},

View File

@ -18,7 +18,7 @@ import 'home_logic.dart';
part 'home_view.g.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
@ -31,20 +31,20 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.dark,
systemStatusBarContrastEnforced: false,
));
}
@override
Widget build(BuildContext context) {
super.build(context);
var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 30);
return SafeArea(
child: AnnotatedRegion(
value: const SystemUiOverlayStyle(
systemNavigationBarColor: Color(0xFF000000),
systemNavigationBarDividerColor: null,
statusBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
),
child: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return EasyRefresh(
@ -78,7 +78,7 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
),
),
),*/
SizedBox(height: MediaQuery. of(context).padding.top / 2),
SizedBox(height: MediaQuery.of(context).padding.top / 2),
Obx(() {
return $TermRow([
EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: Routes.readOverPage),
@ -115,134 +115,138 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
Obx(() {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w),
child: state.workList.isNotEmpty?Column(
children: List.generate(state.workList.length, (index) {
Items item = state.workList[index];
return InkWell(
onTap: () {
Get.toNamed(Routes.annotateClassPage, arguments: {
'id': item.id,
'name': item.name,
'grade': item.grade,
'subject': item.subject,
});
},
child: Container(
margin: EdgeInsets.only(bottom: 15.h),
child: Column(
children: [
SizedBox(height: 4.h),
Container(
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 10.w),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.r),
color: const Color.fromRGBO(255, 255, 255, 1),
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(210, 216, 241, 1),
offset: Offset.zero, //y轴偏移量
blurRadius: 5.8, //
spreadRadius: 0, //
)
],
),
child: state.workList.isNotEmpty
? Column(
children: List.generate(state.workList.length, (index) {
Items item = state.workList[index];
return InkWell(
onTap: () {
Get.toNamed(Routes.annotateClassPage, arguments: {
'id': item.id,
'name': item.name,
'grade': item.grade,
'subject': item.subject,
});
},
child: Container(
margin: EdgeInsets.only(bottom: 15.h),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: Utils.isPad() ? 32.w : 38.w,
height: 18.h,
alignment: Alignment.center,
padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w),
decoration: BoxDecoration(
color: state.type == 1 ? const Color(0xFF4CC793) : const Color.fromRGBO(255, 175, 56, 1),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(14.r),
topRight: Radius.circular(3.r),
bottomLeft: Radius.circular(4.r),
bottomRight: Radius.circular(4.r),
),
SizedBox(height: 4.h),
Container(
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 10.w),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.r),
color: const Color.fromRGBO(255, 255, 255, 1),
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(210, 216, 241, 1),
offset: Offset.zero, //y轴偏移量
blurRadius: 5.8, //
spreadRadius: 0, //
)
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: Utils.isPad() ? 32.w : 38.w,
height: 18.h,
alignment: Alignment.center,
padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w),
decoration: BoxDecoration(
color: state.type == 1 ? const Color(0xFF4CC793) : const Color.fromRGBO(255, 175, 56, 1),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(14.r),
topRight: Radius.circular(3.r),
bottomLeft: Radius.circular(4.r),
bottomRight: Radius.circular(4.r),
),
),
margin: EdgeInsets.only(top: 3.h, right: 4.w),
child: quickText(state.type == 1 ? '作业' : '考试', color: Colors.white, size: 10.sp),
),
Expanded(
child: quickText(
item.name,
maxLines: 2,
size: Utils.isPad() ? 14.sp : 16.sp,
color: const Color.fromRGBO(70, 70, 70, 1),
fontWeight: FontWeight.bold,
),
)
],
),
margin: EdgeInsets.only(top:3.h,right: 4.w),
child: quickText(state.type == 1 ? '作业' : '考试', color: Colors.white, size: 10.sp),
),
Expanded(
child: quickText(
item.name,
maxLines: 2,
size: Utils.isPad() ? 14.sp : 16.sp,
color: const Color.fromRGBO(70, 70, 70, 1),
fontWeight: FontWeight.bold,
SizedBox(height: 10.h),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
quickText(
EnumUtils.formatSubject(item.subject),
color: const Color.fromRGBO(97, 97, 97, 1),
size: 12.sp,
),
quickText(' / ',
color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
quickText('题量:', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp),
quickText(
'${item.questionCount! - item.annotateCount!}',
color: const Color.fromRGBO(97, 97, 97, 1),
size: 13.sp,
),
],
),
quickText(' / ',
color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500),
quickText(DateTime.parse(item.publishTime).toString().substring(0, 10),
color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp),
],
),
)
],
),
SizedBox(height: 10.h),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
quickText(
EnumUtils.formatSubject(item.subject),
color: const Color.fromRGBO(97, 97, 97, 1),
size: 12.sp,
),
quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
quickText('题量:', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp),
quickText(
'${item.questionCount! - item.annotateCount!}',
color: const Color.fromRGBO(97, 97, 97, 1),
size: 13.sp,
),
],
),
quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500),
quickText(DateTime.parse(item.publishTime).toString().substring(0, 10),
color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp),
],
),
SizedBox(height: 10.h),
Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.r),
),
child: LinearPercentIndicator(
padding: EdgeInsets.zero,
animation: true,
lineHeight: 8.h,
animationDuration: 2500,
percent: item.annotateRate == null ? 0 : item.annotateRate! / 100,
progressColor: const Color(0xFF4CC793),
backgroundColor: const Color(0xFFE8E8E8),
barRadius: Radius.circular(10.r),
),
SizedBox(height: 10.h),
Row(
children: [
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.r),
),
child: LinearPercentIndicator(
padding: EdgeInsets.zero,
animation: true,
lineHeight: 8.h,
animationDuration: 2500,
percent: item.annotateRate == null ? 0 : item.annotateRate! / 100,
progressColor: const Color(0xFF4CC793),
backgroundColor: const Color(0xFFE8E8E8),
barRadius: Radius.circular(10.r),
),
),
),
SizedBox(
width: 10.r,
),
quickText('${item.annotateRate!.toStringAsFixed(0)}%', size: 10.sp, color: const Color(0xFF464646)),
],
),
),
SizedBox(
width: 10.r,
),
quickText('${item.annotateRate!.toStringAsFixed(0)}%', size: 10.sp, color: const Color(0xFF464646)),
],
// FavoriteButton(jobTaskItem.id, jobTaskItem.title),
],
),
),
// FavoriteButton(jobTaskItem.id, jobTaskItem.title),
],
),
),
],
),
),
);
}),
):const MyEmptyWidget(),
);
}),
)
: const MyEmptyWidget(),
);
}),
],
@ -250,7 +254,7 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
);
},
),
));
);
}
@override

View File

@ -0,0 +1,281 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/const_text.dart';
import 'package:making_school_asignment_app/common/job/user_register_params.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
///
class Register extends StatefulWidget {
const Register({super.key});
@override
State<Register> createState() => _RegisterState();
}
class _RegisterState extends State<Register> with RequestToolMixin {
late final FocusNode _theFocus;
late final FocusNode _pwdFocus; //
//
late final TextEditingController _userNameController;
late final TextEditingController _passwordController;
bool readAgreement = false; //
bool _isShowPwd = true;
bool canLogin = true;
@override
void initState() {
super.initState();
_userNameController = TextEditingController();
_passwordController = TextEditingController();
_pwdFocus = FocusNode();
_theFocus = FocusNode();
}
@override
void dispose() {
super.dispose();
_userNameController.dispose();
_passwordController.dispose();
_pwdFocus.dispose();
_theFocus.dispose();
}
void toRegister() async {
if (!canLogin) return;
setState(() => canLogin = false);
void toMsg(msg) {
Future.delayed(Duration.zero, () => ToastUtils.showError(msg));
setState(() => canLogin = true);
}
FocusScope.of(context).requestFocus(_theFocus);
try {
String userName = _userNameController.text.trim();
String userPwd = _passwordController.text.trim();
if (userName == '') return toMsg('请填写用户账号');
if (userPwd == '') return toMsg('请填写密码');
if (userPwd.length < 6) return toMsg('密码长度不得少于6位');
if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议');
EasyLoading.show(status: 'loading...');
var resultData = await getClient().toRegister(UserRegisterParams(account: userName, password: userPwd));
print(resultData);
// if (resultData.success) return toMsg(resultData.message ?? '注册失败,请重试');
ToastUtils.showSuccess('注册成功,请登录');
//
Future.delayed(Duration.zero, () => Get.back());
} catch (e) {
setState(() => canLogin = true);
} finally {
EasyLoading.dismiss();
}
}
void _showPassword() {
setState(() {
_isShowPwd = !_isShowPwd;
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
FocusScope.of(context).requestFocus(_theFocus);
},
child: AnnotatedRegion(
value: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.dark,
),
child: Scaffold(
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: false,
body: Stack(
children: [
Container(
width: double.infinity,
height: double.infinity,
alignment: Alignment.center,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/login_bg.png'),
fit: BoxFit.fill, //
),
),
child: SingleChildScrollView(
child: Column(
children: [
Container(
width: 86.w,
height: 86.w,
alignment: Alignment.center,
child: SizedBox(
height: 86.w,
width: 86.w,
child: Image.asset('assets/images/login_logo.png', fit: BoxFit.cover),
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h),
padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 1.w, color: Colors.white),
borderRadius: BorderRadius.all(Radius.circular(10.w)),
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 100, //
spreadRadius: 100, //
)
],
),
child: Column(children: [
TextField(
controller: _userNameController,
maxLines: 1,
maxLength: 20,
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(_pwdFocus);
},
style: TextStyle(
color: const Color.fromRGBO(80, 87, 103, 1),
fontSize: 15.sp,
),
decoration: InputDecoration(
hintText: "请输入账号",
hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)),
labelText: "账号",
labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
),
),
TextField(
focusNode: _pwdFocus,
controller: _passwordController,
keyboardType: TextInputType.number,
maxLines: 1,
obscureText: _isShowPwd, //
textInputAction: TextInputAction.go,
onSubmitted: (_) => toRegister(),
style: TextStyle(
color: const Color.fromRGBO(80, 87, 103, 1),
fontSize: 15.sp,
),
decoration: InputDecoration(
hintText: "请输入密码",
suffix: GestureDetector(
onTap: _showPassword,
child: Icon(
Icons.remove_red_eye,
color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey,
),
),
hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)),
labelText: "密码",
isDense: true,
labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)),
),
),
SizedBox(
height: 12.h,
),
InkWell(
onTap: toRegister,
child: Container(
margin: EdgeInsets.symmetric(vertical: 10.h),
decoration: BoxDecoration(
color: canLogin ? Theme.of(context).primaryColor : Colors.grey,
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(76, 199, 147, 0.5),
offset: Offset(4.w, 6.h), //y轴偏移量
blurRadius: 10, //
spreadRadius: 0.5, //
)
],
borderRadius: BorderRadius.all(
Radius.circular(8.w),
),
),
alignment: Alignment.center,
width: double.infinity,
height: 50.h,
child: Text(
'注 册',
style: TextStyle(fontSize: 16.sp, color: Colors.white),
),
),
),
Row(
children: [
Container(
width: 30.w,
padding: EdgeInsets.only(right: 10.w),
child: Checkbox(
activeColor: Colors.deepOrangeAccent,
checkColor: Colors.white,
value: readAgreement,
onChanged: (value) {
FocusScope.of(context).requestFocus(_pwdFocus);
FocusScope.of(context).requestFocus(_theFocus);
setState(() {
readAgreement = value ?? false;
});
},
),
),
InkWell(
onTap: () {
// RouterManager.router.navigateTo(
// context,
// '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}',
// transition: getTransition(),
// );
},
child: quickText('我已阅读', size: 11.sp),
),
InkWell(
onTap: () {
Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name});
},
child: quickText(
'《用户协议》',
size: 12.sp,
color: Colors.deepOrangeAccent,
),
),
],
),
]),
)
],
),
)),
Positioned(
top: MediaQuery.of(context).padding.top + 20.r,
left: 20.r,
child: InkWell(
onTap: () => Navigator.pop(context),
child: Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24.sp),
),
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,167 @@
import 'dart:io';
import 'package:get/get.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:making_school_asignment_app/common/const_text.dart';
import 'package:making_school_asignment_app/common/store/app_storage_key.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
class Protocol extends Dialog {
final BuildContext context;
const Protocol(this.context, {super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Container(
width: isPad() ? 200.w : 260.w,
height: 400.h,
padding: EdgeInsets.symmetric(vertical: 16.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
children: <Widget>[
quickText('用户协议与隐私政策',
size: 15.sp,
color: const Color.fromRGBO(37, 37, 37, 1),
fontWeight: FontWeight.bold),
Expanded(
child: ListView(
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.fromLTRB(16.w, 14.h, 16.w, 10.h),
children: [
Text.rich(TextSpan(children: [
TextSpan(
text:
'感谢您选择点智学APP ! 我们非常重视您的个人信息和隐私保护。为了更好地保障您的个人权益,在您使用我们的产品前,请务必审慎阅读',
style: TextStyle(
fontSize: 13.sp,
color: const Color.fromRGBO(51, 51, 51, 1)),
),
TextSpan(
text: '《隐私政策》',
style: TextStyle(
fontSize: 13.sp,
color: Theme.of(context).primaryColor),
recognizer: TapGestureRecognizer()
..onTap = () async {
Get.toNamed(Routes.agreementPage, arguments: {
"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name
});
// RouterManager.router.navigateTo(
// context,
// '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.PRIVACY_GREEMENT.name}',
// transition: getTransition(),
// );
},
),
TextSpan(
text: '',
style: TextStyle(
fontSize: 13.sp,
color: Color.fromRGBO(51, 51, 51, 1)),
),
TextSpan(
text: '《用户协议》',
style: TextStyle(
fontSize: 13.sp,
color: Theme.of(context).primaryColor),
recognizer: TapGestureRecognizer()
..onTap = () async {
Get.toNamed(Routes.agreementPage, arguments: {
"type": AGREEMENT_KEY.USER_AGREEMENT.name
});
// RouterManager.router.navigateTo(
// context,
// '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}',
// transition: getTransition(),
// );
},
),
TextSpan(
text:
'内的所有条款,尤其是:1.我们对您的个人信息的收集/保存/使用/对外提供/保护等规则条款,以及您的用户权利等条款;2.约定我们的限制责任、免责条款;3.其他以颜色或加粗进行标识的重要条款。如您对以上协议有任何疑问可通过发邮件至yuanxuanjiaoyu@gmail.com与我们联系。您点击"同意并继续”的行为即表示您已阅读完毕并同意以上协议的全部内容。如您同意以上协议内容,请点击"同意并继续”,开始使用我们的产品和服务!',
style: TextStyle(
fontSize: 13.sp,
color: const Color.fromRGBO(51, 51, 51, 1)),
),
])),
],
),
),
SizedBox(height: 10.h),
Row(
children: [
Expanded(
child: InkWell(
onTap: () {
exit(0);
},
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 15.h),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
width: 0.5.r,
color: const Color.fromRGBO(238, 238, 238, 1)),
right: BorderSide(
width: 0.5.r,
color: const Color.fromRGBO(238, 238, 238, 1)),
),
),
child: quickText('退出APP', size: 14.sp),
),
),
),
Expanded(
child: InkWell(
onTap: () {
StorageService.to
.write(AppStorageKey.privacyAgreement.value, true);
Navigator.of(context).pop(true);
},
child: Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 15.h),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
width: 0.5.r,
color: const Color.fromRGBO(238, 238, 238, 1)),
),
),
child: quickText('同意并继续',
color: Theme.of(context).primaryColor, size: 14.sp),
),
),
)
],
),
],
),
),
);
}
}
///
Future<void> sysProtocol(BuildContext context) async {
bool? sysProtocol =
StorageService.to.hasData(AppStorageKey.privacyAgreement.value);
if (!sysProtocol) {
return showDialog(
context: context,
barrierDismissible: false,
// useRootNavigator: false,
builder: (ctx) => Protocol(ctx),
);
}
}

View File

@ -7,8 +7,8 @@ import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/login_page/children/sys_protocol.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/store/app_storage_key.dart';
import 'login_state.dart';
@ -26,13 +26,13 @@ class LoginLogic extends GetxController with RequestToolMixin {
void onInit() {
super.onInit();
/* state.userNameController = TextEditingController()
/* state.userNameController = TextEditingController()
..addListener(userNameListener);
state.passwordController = TextEditingController();*/
String account = StorageService.to.read(AppStorageKey.account.value)?? '';
String account = StorageService.to.read(AppStorageKey.account.value) ?? '';
String pwd = StorageService.to.read(AppStorageKey.pwd.value) ?? '';
if (account != '' && pwd != '') {
if (account != '' && pwd != '') {
state.userNameController.text = account;
state.passwordController.text = pwd;
state.keepPwd.value = true;
@ -40,6 +40,7 @@ class LoginLogic extends GetxController with RequestToolMixin {
state.pwdFocus = FocusNode();
state.theFocus = FocusNode();
getShowUserAdditionalFeatures(); //
}
void userNameListener() {
@ -58,7 +59,7 @@ class LoginLogic extends GetxController with RequestToolMixin {
}
//
void toLogin() async {
void toLogin(BuildContext context) async {
if (!state.canLogin.value) return;
state.canLogin.value = false;
@ -161,4 +162,9 @@ class LoginLogic extends GetxController with RequestToolMixin {
state.pwdFocus.dispose();
state.theFocus.dispose();
}
///
Future<void> getShowUserAdditionalFeatures() async {
// state.showUserAdditionalFeatures.value = ;
}
}

View File

@ -15,5 +15,6 @@ class LoginState {
late RxBool isShowPwd = true.obs;
late RxBool keepPwd = false.obs;
late RxBool canLogin = true.obs;
late RxBool readAgreement = true.obs;
late RxBool readAgreement = false.obs;
late RxBool showUserAdditionalFeatures = false.obs;
}

View File

@ -1,17 +1,18 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/const_text.dart';
import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'children/sys_protocol.dart';
import 'login_logic.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
@ -24,7 +25,10 @@ class _LoginPageState extends State<LoginPage> {
@override
void initState() {
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.light));
Future.delayed(Duration.zero, () => upgradeLogic.getAppUpgrade(context));
Future.delayed(Duration.zero, () => sysProtocol(context));
super.initState();
}
@ -36,6 +40,8 @@ class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.light));
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
@ -72,12 +78,15 @@ class _LoginPageState extends State<LoginPage> {
child: SizedBox(
height: 86.w,
width: 86.w,
child: Image.asset('assets/images/login_logo.png', fit: BoxFit.cover),
child: Image.asset('assets/images/login_logo.png',
fit: BoxFit.cover),
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h),
padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w),
margin: EdgeInsets.symmetric(
horizontal: 32.w, vertical: 24.h),
padding: EdgeInsets.only(
top: 34.h, bottom: 16.h, left: 22.w, right: 22.w),
color: Colors.transparent,
/* decoration: BoxDecoration(
color: Colors.transparent,
@ -97,8 +106,10 @@ class _LoginPageState extends State<LoginPage> {
padding: EdgeInsets.symmetric(horizontal: 20.h),
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(width: 1.w, color: const Color(0xFFFFFFFF)),
borderRadius: BorderRadius.all(Radius.circular(17.w)),
border: Border.all(
width: 1.w, color: const Color(0xFFFFFFFF)),
borderRadius:
BorderRadius.all(Radius.circular(17.w)),
),
child: TextField(
controller: state.userNameController,
@ -127,8 +138,8 @@ class _LoginPageState extends State<LoginPage> {
border: InputBorder.none,
isDense: true,
prefixIconConstraints: BoxConstraints(
minHeight:10.w,
minWidth: 10.h,
minHeight: 10.w,
minWidth: 10.h,
),
prefixIcon: Padding(
padding: EdgeInsets.only(right: 5.r),
@ -149,8 +160,10 @@ class _LoginPageState extends State<LoginPage> {
padding: EdgeInsets.symmetric(horizontal: 20.h),
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(width: 1.w, color: const Color(0xFFFFFFFF)),
borderRadius: BorderRadius.all(Radius.circular(17.w)),
border: Border.all(
width: 1.w, color: const Color(0xFFFFFFFF)),
borderRadius:
BorderRadius.all(Radius.circular(17.w)),
),
child: TextField(
focusNode: state.pwdFocus,
@ -168,7 +181,7 @@ class _LoginPageState extends State<LoginPage> {
decoration: InputDecoration(
hintText: "请输入密码",
prefixIconConstraints: BoxConstraints(
minHeight:10.w,
minHeight: 10.w,
minWidth: 10.h,
),
prefixIcon: Padding(
@ -180,17 +193,20 @@ class _LoginPageState extends State<LoginPage> {
),
),
suffixIconConstraints: BoxConstraints(
minHeight:10.w,
minHeight: 10.w,
minWidth: 10.h,
),
suffixIcon: InkWell(
onTap: (){
state.isShowPwd.value = !state.isShowPwd.value;
onTap: () {
state.isShowPwd.value =
!state.isShowPwd.value;
},
child: Padding(
padding: EdgeInsets.only(right: 5.r),
child: Image.asset(
state.isShowPwd.value ? 'assets/images/eye_default.png':'assets/images/eye_active.png',
state.isShowPwd.value
? 'assets/images/eye_default.png'
: 'assets/images/eye_active.png',
width: 15.r,
height: 15.r,
),
@ -211,67 +227,99 @@ class _LoginPageState extends State<LoginPage> {
),
);
}),
SizedBox(
height: 22.h,
),
Row(
SizedBox(height: 10.h),
Row(
children: [
Container(
width: 25.w,
padding: EdgeInsets.only(right: 0.w),
child: Obx(() {
return Transform.scale(
scale: 1.2,
child: Checkbox(
activeColor: Theme.of(context).primaryColor,
checkColor: Colors.white,
value: state.keepPwd.value,
onChanged: (value) {
// Get.focusScope?.nextFocus();
FocusScope.of(context).requestFocus(
state.pwdFocus);
FocusScope.of(context).requestFocus(
state.theFocus);
state.keepPwd.value = value ?? false;
},
Expanded(
child: Row(
children: [
Container(
width: 25.w,
padding: EdgeInsets.only(right: 0.w),
child: Obx(() {
return Transform.scale(
scale: 1.2,
child: Checkbox(
// activeColor: Colors.transparent, //
activeColor:
Theme.of(context).primaryColor,
// checkColor: Colors.white,
value: state.keepPwd.value,
onChanged: (value) {
// Get.focusScope?.nextFocus();
FocusScope.of(context)
.requestFocus(state.pwdFocus);
FocusScope.of(context)
.requestFocus(state.theFocus);
state.keepPwd.value =
value ?? false;
},
side: WidgetStateBorderSide
.resolveWith(
(Set<WidgetState> states) {
if (states.contains(
WidgetState.selected)) {
//
return BorderSide(
width: 1.5.r,
color: Theme.of(context)
.primaryColor);
}
//绿
return BorderSide(
width: 1.5.r,
color: Colors.white);
},
)),
);
}),
),
);
}),
),
InkWell(
onTap: () {
Utils.hideKeyboard();
Get.focusScope?.nextFocus();
Get.focusScope?.nextFocus();
FocusScope.of(context).requestFocus(
state.pwdFocus);
FocusScope.of(context).requestFocus(
state.theFocus);
state.keepPwd.value = !state.keepPwd.value;
},
child: Text(
'记住密码',
style: TextStyle(
fontSize: 11.sp,
color: Colors.white,
),
InkWell(
onTap: () {
Utils.hideKeyboard();
Get.focusScope?.nextFocus();
Get.focusScope?.nextFocus();
FocusScope.of(context)
.requestFocus(state.pwdFocus);
FocusScope.of(context)
.requestFocus(state.theFocus);
state.keepPwd.value =
!state.keepPwd.value;
},
child: Text(
'记住密码',
style: TextStyle(
fontSize: 12.sp,
color: Colors.white,
),
),
),
],
),
),
InkWell(
onTap: () => Get.toNamed(Routes.register),
child: quickText('账号注册', color: Colors.white),
)
],
),
InkWell(
onTap: () {
logic.toLogin();
logic.toLogin(context);
// Get.toNamed(Routes.home);
},
child: Obx(() {
return Container(
margin: EdgeInsets.symmetric(vertical: 10.h),
decoration: BoxDecoration(
color: state.canLogin.value ? const Color(0xFF4CC793) : const Color(0xFFdddddd),
color: state.canLogin.value
? const Color(0xFF4CC793)
: const Color(0xFFdddddd),
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(76, 199, 147, 0.5),
color:
const Color.fromRGBO(76, 199, 147, 0.5),
offset: Offset(6.w, 10.h), //y轴偏移量
blurRadius: 14, //
spreadRadius: 0.5, //
@ -284,10 +332,9 @@ class _LoginPageState extends State<LoginPage> {
alignment: Alignment.center,
width: double.infinity,
height: 50.h,
child: Text(
'登 录',
style: TextStyle(fontSize: 16.sp, color: Colors.white),
),
child: Text('登 录',
style: TextStyle(
fontSize: 16.sp, color: Colors.white)),
);
}),
),
@ -309,25 +356,50 @@ class _LoginPageState extends State<LoginPage> {
state.pwdFocus);
FocusScope.of(context).requestFocus(
state.theFocus);*/
state.readAgreement.value = value ?? false;
state.readAgreement.value =
value ?? false;
},
side: WidgetStateBorderSide.resolveWith(
(Set<WidgetState> states) {
if (states
.contains(WidgetState.selected)) {
//
return BorderSide(
width: 1.5.r,
color: Theme.of(context)
.primaryColor);
}
//绿
return BorderSide(
width: 1.5.r, color: Colors.white);
},
),
),
);
}),
),
InkWell(
onTap: () {
Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name});
Get.toNamed(Routes.agreementPage, arguments: {
"type": AGREEMENT_KEY.USER_AGREEMENT.name
});
},
child: quickText('请仔细阅读', size: 11.sp,),
child: quickText(
'请仔细阅读',
size: 11.sp,
),
),
InkWell(
onTap: () {
Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name});
Get.toNamed(Routes.agreementPage, arguments: {
"type": AGREEMENT_KEY.USER_AGREEMENT.name
});
},
child: Text(
'《用户协议》',
style: TextStyle(fontSize: 12.r, color: Colors.deepOrangeAccent),
style: TextStyle(
fontSize: 12.r,
color: Theme.of(context).primaryColor),
),
),
],

View File

@ -27,139 +27,140 @@ class _WorkPageState extends State<WorkPage> with AutomaticKeepAliveClientMixin
@override
bool get wantKeepAlive => true;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
super.build(context);
return AnnotatedRegion(
value: const SystemUiOverlayStyle(
systemNavigationBarColor: Color(0xFF000000),
systemNavigationBarDividerColor: null,
statusBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: const Color.fromRGBO(244, 244, 244, 1),
body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return Column(
children: <Widget>[
Container(
color: Colors.white,
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
padding: EdgeInsets.only(bottom: 9.h, top: 4.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 10.w),
)),
Expanded(
flex: 4,
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(243, 243, 243, 1),
borderRadius: BorderRadius.circular(8.r),
),
child: TabBar(
padding: EdgeInsets.zero,
indicatorPadding: EdgeInsets.zero,
indicatorWeight: 0,
labelPadding: EdgeInsets.symmetric(horizontal: 2.w),
controller: logic.tabController,
unselectedLabelStyle: TextStyle(
fontSize: 14.sp,
color: const Color.fromRGBO(69, 83, 100, 1),
),
labelStyle: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF4CC793),
),
// labelColor: const Color.fromRGBO(45, 56, 76, 1),
indicator: const BoxDecoration(),
onTap: (index) {
state.tabIndex.value = index;
if (index == 1 && state.completedToRefresh) {
//
// _refreshController2.callRefresh();
state.completedToRefresh = false;
}
},
tabs: <Widget>[
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'待批阅',
size: 14.sp,
color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
),
);
}),
),
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'已批阅',
size: 14.sp,
color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
),
);
}),
),
],
),
),
),
Expanded(
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.dark,
systemStatusBarContrastEnforced: false,
));
return Scaffold(
backgroundColor: const Color.fromRGBO(244, 244, 244, 1),
body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return Column(
children: <Widget>[
Container(
color: Colors.white,
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
padding: EdgeInsets.only(bottom: 9.h, top: 4.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: InkWell(
onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 10.w),
)),
Expanded(
flex: 4,
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(243, 243, 243, 1),
borderRadius: BorderRadius.circular(8.r),
),
child: TabBar(
padding: EdgeInsets.zero,
indicatorPadding: EdgeInsets.zero,
indicatorWeight: 0,
labelPadding: EdgeInsets.symmetric(horizontal: 2.w),
controller: logic.tabController,
unselectedLabelStyle: TextStyle(
fontSize: 14.sp,
color: const Color.fromRGBO(69, 83, 100, 1),
),
labelStyle: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF4CC793),
),
// labelColor: const Color.fromRGBO(45, 56, 76, 1),
indicator: const BoxDecoration(),
onTap: (index) {
state.tabIndex.value = index;
if (index == 1 && state.completedToRefresh) {
//
// _refreshController2.callRefresh();
state.completedToRefresh = false;
}
},
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
tabs: <Widget>[
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'待批阅',
size: 14.sp,
color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
),
);
}),
),
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'已批阅',
size: 14.sp,
color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
),
);
}),
),
],
),
),
],
),
),
Expanded(
flex: 1,
child: InkWell(
onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
},
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
),
),
],
),
Expanded(
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 1,
);
}),
),
],
);
},
),
),
Expanded(
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 1,
);
}),
),
],
);
},
),
);
}

View File

@ -35,6 +35,7 @@ import 'package:making_school_asignment_app/page/home_page/children/student_work
import 'package:making_school_asignment_app/page/home_page/home_binding.dart';
import 'package:making_school_asignment_app/page/home_page/home_view.dart';
import 'package:making_school_asignment_app/page/login_page/children/agreement_page.dart';
import 'package:making_school_asignment_app/page/login_page/children/register.dart';
import 'package:making_school_asignment_app/page/login_page/login_binding.dart';
import 'package:making_school_asignment_app/page/login_page/login_view.dart';
import 'package:making_school_asignment_app/page/work_page/work_binding.dart';
@ -44,6 +45,7 @@ part 'app_routes.dart';
abstract class AppPages {
static final pages = [
GetPage(name: Routes.login, page: () => const LoginPage(), binding: LoginBinding(), transition: Transition.noTransition),
GetPage(name: Routes.register, page: () => const Register(), transition: getTransition()),
GetPage(name: Routes.agreementPage, page: () => const AgreementPage(), binding: LoginBinding(), transition: Transition.noTransition),
GetPage(name: Routes.home, page: () => const HomePage(), binding: HomeBinding(), transition: Transition.noTransition),
GetPage(name: Routes.startPage, page: () => const StartPage(), binding: StartPageIndexBinding(), transition: Transition.noTransition),
@ -85,14 +87,20 @@ abstract class AppPages {
page: () => const KnowledgePointsGraspDetailPage(),
binding: KnowledgePointsGraspDetailBinding(),
transition: Transition.noTransition),
GetPage(name: Routes.answerTrajectoryPage, page: () => const AnswerTrajectoryPage(), binding: AnswerTrajectoryBinding(), transition: Transition.noTransition),
GetPage(name: Routes.answerTrajectoryDetailPage, page: () => const AnswerTrajectoryDetailPage(), binding: AnswerTrajectoryDetailBinding(), transition: Transition.noTransition),
GetPage(
name: Routes.answerTrajectoryPage,
page: () => const AnswerTrajectoryPage(),
binding: AnswerTrajectoryBinding(),
transition: Transition.noTransition),
GetPage(
name: Routes.answerTrajectoryDetailPage,
page: () => const AnswerTrajectoryDetailPage(),
binding: AnswerTrajectoryDetailBinding(),
transition: Transition.noTransition),
//
GetPage(name: Routes.reviewHomework, page: () => const HomeworkReview(), binding: HomeworkReviewBinding(), transition: getTransition()),
GetPage(name: Routes.reviewExam, page: () => const HomeworkReview(), binding: HomeworkReviewBinding(), transition: getTransition()),
GetPage(name: Routes.favStudentPage, page: () => const FavStudentPage(), binding: FavStudentBinding(), transition: Transition.noTransition),
];
}

View File

@ -2,6 +2,7 @@ part of 'app_pages.dart';
abstract class Routes {
static const login = '/login';
static const register = '/register';
static const agreementPage = '/agreementPage';
static const home = '/home';
static const startPage = '/startPage';
@ -24,5 +25,4 @@ abstract class Routes {
static const reviewHomework = '/review/reviewHomework'; //
static const reviewExam = '/review/reviewExam'; //
static const favStudentPage = '/favStudentPage'; //
}
}

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
version: 1.0.1+2
environment:
sdk: '>=3.4.1 <4.0.0'
@ -91,9 +91,12 @@ dependencies:
url_launcher: ^6.1.11
app_installer: ^1.1.0
auto_updater: ^0.2.1
permission_handler: ^11.0.1
permission_handler: ^11.3.1
flutter_distributor: ^0.4.5
flutter_native_splash: ^2.4.1
icons_launcher: ^2.1.7
app_settings: ^5.1.1
dev_dependencies:
flutter_test:
@ -160,3 +163,11 @@ flutter:
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
icons_launcher:
platforms:
android:
enable: false
ios:
enable: true
image_path: "assets/images/logo_splash.png"

View File

@ -120,6 +120,43 @@
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
@ -149,9 +186,8 @@
body {
margin: 0;
min-height: 100%;
background-color: #ffffff;
background-image: url("splash/img/light-background.png");
background-size: 100% 100%;
background-color: #eeeeee;
background-size: 100% 100%;
}
.center {
@ -207,13 +243,18 @@
document.body.style.background = "transparent";
}
</script>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
</head>
<body>
<script src="flutter_bootstrap.js" async=""></script>