提交 dfd85037 authored 作者: yueweilu's avatar yueweilu

add

上级 a4b68652
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
- platform: android
create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
- platform: ios
create_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
base_revision: 84a1e904f44f9b0e9c4510138010edcc653163f8
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
# flutter_book
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
namespace "com.zijin.book.flutter_book"
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.zijin.book.flutter_book"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
package com.zijin.book.flutter_book;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends FlutterActivity {
}
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>11.0</string>
</dict>
</plist>
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
PODS:
- Flutter (1.0.0)
- flutter_tts (0.0.1):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_tts (from `.symlinks/plugins/flutter_tts/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_tts:
:path: ".symlinks/plugins/flutter_tts/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
PODFILE CHECKSUM: 02caaa843f6501172c0d470d80e72f61175c8b93
COCOAPODS: 1.11.2
差异被折叠。
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80F0294D02FB00263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?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>PreviewsEnabled</key>
<false/>
</dict>
</plist>
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
<?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">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<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"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Flutter Book</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>flutter_book</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
@interface RunnerTests : XCTestCase
@end
@implementation RunnerTests
- (void)testExample {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
@end
part of apis;
abstract class AccountAPI {
static Future <UserModel> login({
required String phone,
required String password,
required String type,
}) async {
final result = await HttpService.to.post(
'/v1/members/login/login',
excludeToken: true,
showLoading: true,
params: {
'phone': phone,
'password': password,
'type': type
},
);
if (result.data is! Map) return UserModel();
return UserModel.fromJson(result.data);
}
}
\ No newline at end of file
library apis;
import 'dart:io';
import '../models/user_model.dart';
import '../services/index.dart';
part 'account.dart';
\ No newline at end of file
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_book/services/index.dart';
import 'package:flutter_book/store/index.dart';
import 'package:get/get.dart';
class Global {
static Future<void> init() async {
// 确保 Flutter 绑定已经初始化
WidgetsFlutterBinding.ensureInitialized();
// 设置应用程序的首选屏幕方向
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
await Future.wait([
// 配置存储
Get.putAsync<StorageService>(() => StorageService().init()),
]).whenComplete(() {
// 网络
Get.put<HttpService>(HttpService());
//配置基本设置
Get.put<ConfigStore>(ConfigStore());
//
Get.put<UserStore>(UserStore());
});
}
}
\ No newline at end of file
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/routes/index.dart';
import 'package:flutter_book/store/index.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'global.dart';
void main() {
Global.init().then((_) => runApp(const MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}): super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(428, 926),
builder: (context, child) => RefreshConfiguration(
headerBuilder: () => const ClassicHeader(
refreshingIcon: CupertinoActivityIndicator(),
),
footerBuilder: () => const ClassicFooter(
loadingIcon: CupertinoActivityIndicator(),
),
hideFooterWhenNotFull: true,
child: GetBuilder<ConfigStore>(
builder: (config) => MaterialApp.router(
debugShowCheckedModeBanner: false,
title: '紫荆云书',
theme: AppTheme.light,
darkTheme: AppTheme.dark,
themeMode: AppTheme.mode,
routerConfig: Routes.config,
builder: CustomToast.init(
context: context,
builder: (context, child) {
return ScrollConfiguration(
behavior: _NoShadowScrollBehavior(),
child: child ?? const Material(),
);
},
),
// localizationsDelegates: const [
// GlobalMaterialLocalizations.delegate,
// GlobalWidgetsLocalizations.delegate,
// GlobalCupertinoLocalizations.delegate,
// // S.delegate,
// ],
// locale: config.locale,
// supportedLocales: S.delegate.supportedLocales,
),
),
)
);
}
}
class _NoShadowScrollBehavior extends ScrollBehavior {
@override
Widget buildOverscrollIndicator(
BuildContext context,
Widget child,
ScrollableDetails details,
) {
switch (getPlatform(context)) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return child;
case TargetPlatform.android:
return GlowingOverscrollIndicator(
showLeading: false,
showTrailing: false,
axisDirection: details.direction,
color: Theme.of(context).colorScheme.primary,
child: child,
);
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return GlowingOverscrollIndicator(
showLeading: false,
showTrailing: false,
axisDirection: details.direction,
color: Theme.of(context).colorScheme.primary,
child: child,
);
}
}
}
library models;
part 'response.dart';
\ No newline at end of file
part of models;
class ResponseModel {
ResponseModel({
this.code,
this.msg,
this.data,
});
ResponseModel.fromJson(dynamic json) {
code = int.tryParse(json['code'].toString());
msg = json['msg']?.toString();
data = json['data'];
}
int? code;
String? msg;
dynamic data;
ResponseModel copyWith({
int? code,
String? msg,
dynamic data,
}) =>
ResponseModel(
code: code ?? this.code,
msg: msg ?? this.msg,
data: data ?? this.data,
);
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['code'] = code;
map['msg'] = msg;
map['data'] = data;
return map;
}
}
/// members_id : 1
/// name : "555555"
/// password : "637641045c830d80190da7b94f69c2cd"
/// head_img : "http://192.168.11.67:9090/static/images/20210820182011.png"
/// sex : 1
/// birthday : "2020-01-01"
/// phone : "13532236565"
/// grade_id : 1
/// badge_id : 1
/// token : "e8410f5092b809a80956b5f01de75035"
/// access_token : "members_access_token:be48312274defc9ee894c088b7a3be74"
/// grade_name : "等级1"
class UserModel {
UserModel({
this.membersId,
this.name,
this.password,
this.headImg,
this.sex,
this.birthday,
this.phone,
this.gradeId,
this.badgeId,
this.token,
this.accessToken,
this.gradeName,});
num? membersId;
String? name;
String? password;
String? headImg;
num? sex;
String? birthday;
String? phone;
num? gradeId;
num? badgeId;
String? token;
String? accessToken;
String? gradeName;
UserModel.fromJson(dynamic json) {
membersId = json['members_id'];
name = json['name'];
password = json['password'];
headImg = json['head_img'];
sex = json['sex'];
birthday = json['birthday'];
phone = json['phone'];
gradeId = json['grade_id'];
badgeId = json['badge_id'];
token = json['token'];
accessToken = json['access_token'];
gradeName = json['grade_name'];
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['members_id'] = membersId;
map['name'] = name;
map['password'] = password;
map['head_img'] = headImg;
map['sex'] = sex;
map['birthday'] = birthday;
map['phone'] = phone;
map['grade_id'] = gradeId;
map['badge_id'] = badgeId;
map['token'] = token;
map['access_token'] = accessToken;
map['grade_name'] = gradeName;
return map;
}
}
\ No newline at end of file
part of home;
\ No newline at end of file
library home;
import 'package:flutter/material.dart';
part 'view.dart';
part 'controller.dart';
\ No newline at end of file
part of home;
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.cyan,
),
);
}
}
part of main;
class MainController extends GetxController {
late final PageController pageController;
//默认显示
int currentPage = 0;
@override
void onInit() {
super.onInit();
pageController = PageController(initialPage: currentPage);
}
@override
void onClose() {
pageController.dispose();
super.onClose();
}
void onPageChanged(int page) {
currentPage = page;
update(['navigation']);
}
}
\ No newline at end of file
library main;
import 'package:flutter/material.dart';
import 'package:flutter_book/pages/home/index.dart';
import 'package:flutter_book/theme.dart';
import 'package:get/get.dart';
import 'package:get/get_state_manager/src/simple/get_controllers.dart';
import 'package:ionicons/ionicons.dart';
import '../test_tts.dart';
part 'view.dart';
part 'controller.dart';
\ No newline at end of file
part of main;
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> with WidgetsBindingObserver{
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangePlatformBrightness() {
super.didChangePlatformBrightness();
AppTheme.setSystemStyle();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return GetBuilder<MainController>(
init: MainController(),
builder: (controller) => Scaffold(
body: PageView(
physics: const NeverScrollableScrollPhysics(),
controller: controller.pageController,
onPageChanged: controller.onPageChanged,
children: const [
HomePage(),
TestTTSPage(),
HomePage(),
HomePage(),
],
),
bottomNavigationBar: GetBuilder<MainController>(
id: 'navigation',
builder: (controller) => BottomNavigationBar(
currentIndex:controller.currentPage ,
onTap: (page){
controller.pageController.jumpToPage(page);
},
items: const [
BottomNavigationBarItem(
icon: Icon(Ionicons.home_outline),
activeIcon:Icon(Ionicons.home),
label: '首页',
),
BottomNavigationBarItem(
icon: Icon(Ionicons.apps_outline),
activeIcon:Icon(Ionicons.apps),
label: '图书馆',
),
BottomNavigationBarItem(
icon: Icon(Ionicons.chatbubbles_outline),
activeIcon:Icon(Ionicons.chatbubbles),
label: '购物车',
),
BottomNavigationBarItem(
icon: Icon(Ionicons.person_outline),
activeIcon:Icon(Ionicons.person),
label: '我的',
)
]
),
),
)
);
}
}
library splash_page;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:go_router/go_router.dart';
import '../../routes/index.dart';
import '../../utils/index.dart';
part 'view.dart';
\ No newline at end of file
part of splash_page;
class SplashPage extends StatefulWidget {
const SplashPage({Key? key}) : super(key: key);
@override
State<SplashPage> createState() => _SplashPageState();
}
class _SplashPageState extends State<SplashPage> {
@override
void initState() {
super.initState();
Future.wait([
Future.delayed(const Duration(seconds: 1))
]).whenComplete(() async {
// final userModel = await AccountAPI.login(phone: '18337678567', password: '013790d7eb52197bead4c757ebfae7cf', type: '1');
// Console.log('++++++++++++++++');
// Console.log(userModel.name);
context.goNamed(Routes.main);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(),
body: const Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 5,
child: Center(
child: CustomEmpty(
icon: CustomImage.asset(
url: 'assets/images/logo.png',
fit: BoxFit.contain,
),
title: Text('云书'),
),
)
),
Expanded(
flex: 2,
child: Center(child: CupertinoActivityIndicator(),),
)
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:flutter_book/utils/index.dart';
class TestTTSPage extends StatefulWidget {
const TestTTSPage({Key? key}) : super(key: key);
@override
State<TestTTSPage> createState() => _TestTTSPageState();
}
class _TestTTSPageState extends State<TestTTSPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('测试语音'),
centerTitle: true,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.yellow,
height: 150,
width: double.infinity,
// padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: const Text('你好我是小助手',textAlign: TextAlign.start,style: TextStyle(
color: Colors.black,
fontSize: 18
),),
),
GestureDetector(
onTap: (){
Console.log('你好');
},
child: Container(
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(20),
color: Colors.red,
child: const Text('播放'),
),
)
],
),
);
}
}
library routes;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_book/pages/main/index.dart';
import 'package:flutter_book/pages/splash/index.dart';
import 'package:go_router/go_router.dart';
part 'observers.dart';
part 'routes.dart';
\ No newline at end of file
part of routes;
class RouteObservers<R extends Route<dynamic>> extends RouteObserver<R> {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPush(route, previousRoute);
final name = route.settings.name ?? '';
if (name.isNotEmpty) Routes.history.add(name);
if (kDebugMode) {
print('didPush');
print(Routes.history);
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPop(route, previousRoute);
Routes.history.remove(route.settings.name);
if (kDebugMode) {
print('didPop');
print(Routes.history);
}
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (newRoute != null) {
final index = Routes.history.indexWhere((element) {
return element == oldRoute?.settings.name;
});
final name = newRoute.settings.name ?? '';
if (name.isNotEmpty) {
if (index > -1) {
Routes.history[index] = name;
} else {
Routes.history.add(name);
}
}
}
if (kDebugMode) {
print('didReplace');
print(Routes.history);
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didRemove(route, previousRoute);
Routes.history.remove(route.settings.name);
if (kDebugMode) {
print('didRemove');
print(Routes.history);
}
}
}
part of routes;
abstract class Routes {
static final RouteObserver<Route> observer = RouteObservers();
static List<String> history = [];
static const splash = 'splash';
static const main = 'main';
static final GoRouter config = GoRouter(
initialLocation: '/$splash',
observers: [observer],
routes: [
GoRoute(
path: '/$splash',
name: splash,
pageBuilder: (context, state) =>CupertinoPage(
name: state.uri.toString(),
key: state.pageKey,
child: const SplashPage(),
),
),
GoRoute(
path: '/',
name: main,
pageBuilder: (context, state) =>CupertinoPage(
name: state.uri.toString(),
key: state.pageKey,
child: const MainPage()
)
)
]
);
}
\ No newline at end of file
part of services;
class HttpService extends GetxService {
static HttpService get to => Get.find();
late final Dio _dio;
@override
void onInit() {
super.onInit();
final options = BaseOptions(
baseUrl: kServerUrl,
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds:10),
headers: {},
contentType: Headers.jsonContentType,
responseType: ResponseType.json
);
_dio = Dio(options);
_dio.interceptors.add(_RequestInterceptor());
}
/// 组织 headers 参数
Map<String,dynamic>? _getHeaders({bool excludeToken = false,Map<String,dynamic>? params,String? url}) {
final headers = <String, dynamic>{};
if (Get.isRegistered<UserStore>() &&
UserStore.to.hasToken && !excludeToken) {
// headers['Token'] = UserStore.to.token;
headers['token'] = UserStore.to.token;
if (params != null) {
params.addAll(headers);
}
headers['Sign'] = SignTool.createSign(params!);
} else{
headers['appId'] = AppConfig.AppID;
headers['appSecret'] = AppConfig.AppSecret;
headers['timestamp'] = (DateTime.now().millisecondsSinceEpoch~/1000).toString();
headers['url'] = kServerUrl + url.toString();
headers['token'] = '';
if (params != null) {
params.addAll(headers);
}
headers['Sign'] = SignTool.createSign(params!);
}
return headers;
}
/// get
Future<ResponseModel> get(
String url,{
Map<String, dynamic>? params,
Options? options,
CancelToken? cancelToken,
bool excludeToken = false,
bool showLoading = false,
}) async {
if (showLoading) CustomToast.loading();
try {
final requestOptions = options ?? Options();
requestOptions.headers = _getHeaders(excludeToken: excludeToken,params: params,url: url);
final response = await _dio.get(
url,
queryParameters: params,
options: requestOptions,
cancelToken: cancelToken,
);
if (showLoading) CustomToast.dismiss();
return ResponseModel.fromJson(response.data);
} catch (error){
if (error is! DioException) CustomToast.dismiss();
rethrow;
}
}
/// post
Future<ResponseModel> post(
String url,{
Map<String,dynamic>? params,
Options? options,
CancelToken? cancelToken,
bool excludeToken = false,
bool showLoading = false,
}) async{
if (showLoading) CustomToast.loading();
try {
final requestOptions = options ?? Options();
requestOptions.headers = _getHeaders(excludeToken: excludeToken,params: params,url: url);
final response = await _dio.post(
url,
data: params,
options: requestOptions,
cancelToken: cancelToken,
);
if (showLoading) CustomToast.dismiss();
return ResponseModel.fromJson(response.data);
} catch (error){
if (error is! DioException) CustomToast.dismiss();
rethrow;
}
}
/// upload
Future<ResponseModel> upload(
String url, {
required String path,
Options? options,
CancelToken? cancelToken,
bool excludeToken = false,
ProgressCallback? onSendProgress,
})async {
final requestOptions = options ?? Options();
requestOptions.headers = _getHeaders(excludeToken: excludeToken,url:url);
final name = path.substring(path.lastIndexOf('/') + 1,path.length);
final image = await MultipartFile.fromFile(path, filename: name);
final formData = FormData.fromMap({'file':image});
final response = await _dio.post(
url,
data:formData,
options:requestOptions,
cancelToken: cancelToken,
onSendProgress: onSendProgress,
);
return ResponseModel.fromJson(response.data);
}
/// download
Future<void> download(
String url,{
required String savePath,
Options? options,
CancelToken? cancelToken,
bool excludeToken = false,
ProgressCallback? onReceiveProgress,
}) async {
try{
final requestOptions = options ?? Options();
requestOptions.headers = _getHeaders(excludeToken: excludeToken,url: url);
await _dio.download(
url,
savePath,
options: requestOptions,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress
);
Console.log('Download completed:$savePath');
}catch(e){
Console.log(e);
rethrow;
}
}
}
class _RequestInterceptor extends Interceptor {
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
Console.log('--------------------------------');
if (response.data['code'] != 200) {
handler.reject(
DioException(
requestOptions: response.requestOptions,
response: response,
type: DioExceptionType.badResponse,
),
true,
);
} else {
super.onResponse(response, handler);
}
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
Console.log(err.type);
switch (err.type) {
case DioExceptionType.connectionTimeout:
CustomToast.fail('网络连接超时');
break;
case DioExceptionType.sendTimeout:
CustomToast.fail('发送超时');
break;
case DioExceptionType.receiveTimeout:
CustomToast.fail('接收超时');
break;
case DioExceptionType.badCertificate:
CustomToast.fail('证书错误');
break;
case DioExceptionType.badResponse:
final response = err.response;
final statusCode = response?.statusCode;
// Console.log(response?.data);
final code = int.tryParse(response?.data['code']?.toString() ?? '');
var msg = '服务器错误';
switch (statusCode) {
case 401:
msg = '$statusCode - Unauthorized';
break;
case 404:
msg = '$statusCode - Server not found';
break;
case 500:
msg = '$statusCode - Server error';
break;
case 502:
msg = '$statusCode - Bad gateway';
break;
default:
if (code == 901) UserStore.to.logout();
msg = response?.data?['msg']?.toString() ?? msg;
break;
}
CustomToast.fail(msg);
break;
case DioExceptionType.cancel:
Console.log('请求取消');
break;
case DioExceptionType.connectionError:
CustomToast.fail('网络连接失败');
break;
case DioExceptionType.unknown:
CustomToast.fail('请求发生未知错误');
break;
}
super.onError(err, handler);
}
}
library services;
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter_book/store/index.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:get/get.dart' hide Response, FormData, MultipartFile;
import 'package:shared_preferences/shared_preferences.dart';
import '../models/index.dart';
export 'package:dio/dio.dart';
part 'storage.dart';
part 'http.dart';
part 'interceptor.dart';
\ No newline at end of file
part of services;
class AuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final token = UserStore.to.token;
super.onRequest(options, handler);
}
}
part of services;
class StorageService extends GetxService {
static StorageService get to => Get.find();
late final SharedPreferences _prefs;
///初始化 StorageService
Future<StorageService> init() async {
_prefs = await SharedPreferences.getInstance();
// 返回 StorageService 实例
return this;
}
///存储字符串
Future<bool> setString(String key, String value) async {
return await _prefs.setString(key, value);
}
///存储bool类型
Future<bool> setBool(String key, bool value) async {
return await _prefs.setBool(key, value);
}
///存储list类型
Future<bool> setList(String key, List<String> value) async{
return await _prefs.setStringList(key, value);
}
///获取字符串
String getString(String key) {
return _prefs.getString(key) ?? '';
}
///获取bool
bool getBool(String key) {
return _prefs.getBool(key) ?? false;
}
///获取list
List<String> getList(String key) {
return _prefs.getStringList(key) ?? [];
}
///移除key
Future<bool> remove(String key) async {
return await _prefs.remove(key);
}
}
\ No newline at end of file
part of store;
class ConfigStore extends GetxController {
static ConfigStore get to => Get.find();
@override
void onInit() {
super.onInit();
_initThemeMode();
}
/// 主题模式
void _initThemeMode() {
final theme = StorageService.to.getString(C.localThemeMode);
switch (theme) {
case C.themeLight:
AppTheme.mode = ThemeMode.light;
break;
case C.themeDark:
AppTheme.mode = ThemeMode.dark;
break;
default:
AppTheme.mode = ThemeMode.system;
break;
}
AppTheme.setSystemStyle();
}
}
\ No newline at end of file
library store;
import 'package:flutter/material.dart';
import 'package:flutter_book/services/index.dart';
import 'package:flutter_book/theme.dart';
import 'package:get/get.dart';
import '../utils/index.dart';
part 'config.dart';
part 'user.dart';
\ No newline at end of file
part of store;
class UserStore extends GetxController {
// 获取 UserStore 实例
static UserStore get to => Get.find();
// 是否登录
bool _isLogin = false;
String _token = '';
String get token => _token;
bool get isLogin=> _isLogin;
bool get hasToken => _token.isNotEmpty;
@override
void onInit() {
super.onInit();
_token = StorageService.to.getString(kLocalToken);
}
Future<void> setToken(String value) async {
await StorageService.to.setString(kLocalToken, value);
_token = value;
}
// 登出
Future<void> logout() async {
await StorageService.to.remove(kLocalToken);
_token = '';
_isLogin = false;
}
}
\ No newline at end of file
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
abstract class AppTheme {
// 应用程序默认边距
static const margin = 16.0;
// 主要/主题颜色的常量
static const primary = Color(0xFF2972FE);
// 成功状态的颜色
static const success = Color(0xFF23A757);
// 警告状态的颜色
static const warning = Color(0xFFFF1843);
// 错误状态的颜色
static const error = Color(0xFFDA1414);
// 信息/提示状态的颜色
static const info = Color(0xFF2E5AAC);
static ThemeMode mode = ThemeMode.system;
// 系统主题
static SystemUiOverlayStyle get systemStyle => const SystemUiOverlayStyle(
// 状态栏(位于屏幕顶部的区域)的颜色
statusBarColor: Colors.transparent,
// 设置状态栏中元素(如文字、图标)的亮度
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarDividerColor: Colors.transparent,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark
);
// 亮色主题
static SystemUiOverlayStyle get systemStyleLight => systemStyle.copyWith(
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarIconBrightness: Brightness.dark
);
// 暗色主题
static SystemUiOverlayStyle get systemStyleDark => systemStyle.copyWith(
statusBarBrightness: Brightness.dark,
statusBarIconBrightness: Brightness.light,
systemNavigationBarColor: const Color(0xFF0D0D0D),
systemNavigationBarIconBrightness: Brightness.light
);
/// 设置主题
static void setSystemStyle() {
switch (mode) {
case ThemeMode.system:
if (Screen.mediaQuery.platformBrightness == Brightness.dark) {
SystemChrome.setSystemUIOverlayStyle(systemStyleDark);
} else {
SystemChrome.setSystemUIOverlayStyle(systemStyleLight);
}
break;
case ThemeMode.light:
SystemChrome.setSystemUIOverlayStyle(systemStyleLight);
break;
case ThemeMode.dark:
SystemChrome.setSystemUIOverlayStyle(systemStyleDark);
break;
}
}
static ThemeData get light {
var scheme = ColorScheme.light(
background: Colors.white,
onBackground: const Color(0xFF333333),
surface: Colors.white,
onSurface: const Color(0xFF333333),
primary: primary,
onPrimary: Colors.white,
secondary: const Color(0xFFFFB800),
onSecondary: Colors.white,
tertiary: const Color(0xFFF4F6F9),
outline: const Color(0xFFF4F6F9),
shadow: const Color(0xFF5A6CEA).withOpacity(0.08),
error: error,
onError: Colors.white,
);
return _getTheme(scheme);
}
static ThemeData get dark {
var scheme = ColorScheme.dark(
background: const Color(0xFF0D0D0D),
onBackground: Colors.white,
surface: const Color(0xFF252525),
onSurface: Colors.white,
primary: primary,
onPrimary: Colors.white,
secondary: const Color(0xFFFFB800),
onSecondary: Colors.white,
tertiary: const Color(0xFF141414),
outline: const Color(0xFF252525),
shadow: const Color(0xFF777777).withOpacity(0.08),
error: error,
onError: Colors.white,
);
return _getTheme(scheme);
}
static ThemeData _getTheme(ColorScheme scheme) {
return ThemeData(
useMaterial3: false,
colorScheme: scheme,
scaffoldBackgroundColor: scheme.background,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
dialogTheme: DialogTheme(
elevation: 0,
titleTextStyle: TextStyle(
fontSize: 22.w,
fontWeight: FontWeight.w600,
),
contentTextStyle: TextStyle(fontSize: 20.w),
backgroundColor: scheme.brightness == Brightness.light
? scheme.surface
: scheme.tertiary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.w),
),
),
bottomSheetTheme: BottomSheetThemeData(
elevation: 0,
backgroundColor: scheme.brightness == Brightness.light
? scheme.surface
: scheme.tertiary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.w),
topRight: Radius.circular(30.w),
),
),
),
appBarTheme: AppBarTheme(
backgroundColor: scheme.background,
scrolledUnderElevation: 0,
elevation: 0,
centerTitle: true,
toolbarHeight: 56.w,
iconTheme: IconThemeData(
color: scheme.onBackground,
size: 22.w,
),
titleTextStyle: TextStyle(
color: scheme.onBackground,
fontSize: 24.w,
fontWeight: FontWeight.w600,
height: 1.2,
),
toolbarTextStyle: TextStyle(
color: scheme.onBackground,
fontSize: 22.w,
fontWeight: FontWeight.w600,
height: 1.2,
),
),
textTheme: TextTheme(
bodyMedium: TextStyle(
fontSize: 16.w,
color: scheme.onBackground,
),
labelLarge: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16.w,
height: 1.2,
color: scheme.onBackground,
),
),
bottomAppBarTheme: BottomAppBarTheme(
elevation: 0,
color: scheme.background,
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: scheme.background,
unselectedItemColor: scheme.onBackground.withOpacity(0.5),
selectedItemColor: scheme.primary,
unselectedLabelStyle: TextStyle(fontSize: 13.w, height: 1.6),
selectedLabelStyle: TextStyle(fontSize: 13.w, height: 1.6),
unselectedIconTheme: IconThemeData(
size: 24.w,
color: scheme.onBackground.withOpacity(0.5),
),
selectedIconTheme: IconThemeData(
size: 24.w,
color: scheme.primary,
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: ButtonStyle(
elevation: MaterialStateProperty.all(0),
minimumSize: MaterialStateProperty.all(Size.zero),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
overlayColor: MaterialStateProperty.all(Colors.transparent),
),
),
inputDecorationTheme: InputDecorationTheme(
isCollapsed: true,
isDense: true,
filled: true,
fillColor: scheme.surface,
labelStyle: TextStyle(
fontSize: 16.w,
color: scheme.onBackground,
fontWeight: FontWeight.w600,
),
helperStyle: TextStyle(
fontSize: 14.w,
color: scheme.onBackground.withOpacity(0.7),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 20.w,
vertical: 14.w,
),
border: OutlineInputBorder(
borderSide: BorderSide(color: scheme.outline, width: 2.w),
borderRadius: BorderRadius.all(Radius.circular(25.w)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: scheme.outline, width: 2.w),
borderRadius: BorderRadius.all(Radius.circular(25.w)),
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: scheme.outline, width: 2.w),
borderRadius: BorderRadius.all(Radius.circular(25.w)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: scheme.primary, width: 2.w),
borderRadius: BorderRadius.all(Radius.circular(25.w)),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: error, width: 2.w),
borderRadius: BorderRadius.all(Radius.circular(25.w)),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: error, width: 2.w),
borderRadius: BorderRadius.all(Radius.circular(100.w)),
),
),
tabBarTheme: TabBarTheme(
labelColor: scheme.primary,
unselectedLabelColor: scheme.background,
labelStyle: TextStyle(
color: scheme.onPrimary,
fontSize: 16.w,
fontWeight: FontWeight.w600,
),
unselectedLabelStyle: TextStyle(
color: scheme.primary,
fontSize: 16.w,
fontWeight: FontWeight.w600,
),
labelPadding: EdgeInsets.symmetric(horizontal: 6.w),
),
dividerTheme: DividerThemeData(
thickness: 1.w,
color: scheme.onBackground.withOpacity(0.08),
),
);
}
}
\ No newline at end of file
part of utils;
class AppConfig{
//app在服务端注册的id,由后端直接提供
static const String AppID = 'ZTxGRWl6F6erl330';
//app在服务端的秘钥串,由后端直接提供
static const String AppSecret = '0a6521b67cbd5397ce641f791f284bb7';
//签名时使用的加密串,由后端直接提供
static const String AppEncodeKey = 'J2h8a9zK0z%a-k2z';
}
part of utils;
abstract class Console {
static final _log = Logger(filter: _LogFilter());
static void log(dynamic message) => _log.d(message);
}
class _LogFilter extends LogFilter {
@override
bool shouldLog(LogEvent event) => !kReleaseMode;
}
part of utils;
// 服务器地址
const String kServerUrl = 'https://app.vning.com';
const String kLocalToken = 'local_token';
const String kLocalAccount = 'local_account';
const String kLocalPassword = 'local_password';
abstract class C {
static const String localAccount = 'storage_account';
static const String localThemeMode = 'storage_theme_mode';
static const String localLanguage = 'storage_lang';
/// 自动主题
static const String themeSystem = '0';
/// 亮色主题
static const String themeLight = '1';
/// 暗色主题
static const String themeDark = '2';
}
\ No newline at end of file
part of utils;
class EncryptUtil {
/// md5 加密
static String encodeMd5(String data) {
var content = Utf8Encoder().convert(data);
var digest = md5.convert(content);
return hex.encode(digest.bytes);
}
}
\ No newline at end of file
library utils;
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
import 'package:crypto/crypto.dart';
import 'package:convert/convert.dart';
part 'constants.dart';
part 'screen.dart';
part 'console.dart';
part 'app_config.dart';
part 'sign.dart';
part 'encrypt_util.dart';
\ No newline at end of file
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论