@ -0,0 +1,321 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Java template
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
medicine-server/src/main/resources/application.yml
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
### C++ template
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### C template
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Linker output
|
||||||
|
*.ilk
|
||||||
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Kernel Module Compile Results
|
||||||
|
*.mod*
|
||||||
|
*.cmd
|
||||||
|
.tmp_versions/
|
||||||
|
modules.order
|
||||||
|
Module.symvers
|
||||||
|
Mkfile.old
|
||||||
|
dkms.conf
|
||||||
|
|
||||||
|
### Python template
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
**/.gradle
|
||||||
|
**/node_modules
|
||||||
|
|
||||||
|
medicine-server/src/main/java/cn/xiaohaoo/admin/service/MedicinePredictionService.java
|
||||||
|
medicine-server/src/main/resources/onnx/medicine_model.onnx
|
||||||
|
|
@ -0,0 +1,46 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Web related
|
||||||
|
lib/generated_plugin_registrant.dart
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/debug
|
||||||
|
/android/app/profile
|
||||||
|
/android/app/release
|
@ -0,0 +1,3 @@
|
|||||||
|
# 中药识别APP端
|
||||||
|
使用Flutter开发
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# Remember to never publicly share your keystore.
|
||||||
|
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||||
|
key.properties
|
@ -0,0 +1,59 @@
|
|||||||
|
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 {
|
||||||
|
compileSdkVersion 30
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
|
applicationId 'cn.xiaohao.medicine'
|
||||||
|
minSdkVersion 19
|
||||||
|
targetSdkVersion 30
|
||||||
|
versionCode flutterVersionCode.toInteger()
|
||||||
|
versionName flutterVersionName
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
// TODO: Add your own signing config for the release build.
|
||||||
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
|
signingConfig signingConfigs.debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flutter {
|
||||||
|
source '../..'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.xiaohao.flutter_demo01">
|
||||||
|
<!-- Flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
@ -0,0 +1,44 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.xiaohao.flutter_demo01">
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<application
|
||||||
|
android:label="中药识别"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
the Android process has started. This theme is visible to the user
|
||||||
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
|
to determine the Window background behind the Flutter UI. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
|
android:resource="@style/NormalTheme"
|
||||||
|
/>
|
||||||
|
<!-- Displays an Android View that continues showing the launch screen
|
||||||
|
Drawable until Flutter paints its first frame, then this splash
|
||||||
|
screen fades out. A splash screen is useful to avoid any visual
|
||||||
|
gap between the end of Android's launch screen and the painting of
|
||||||
|
Flutter's first frame. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||||
|
android:resource="@drawable/launch_background"
|
||||||
|
/>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!-- Don't delete the meta-data below.
|
||||||
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
<meta-data
|
||||||
|
android:name="flutterEmbedding"
|
||||||
|
android:value="2" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.xiaohao.flutter_demo01
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity() {
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
<item
|
||||||
|
android:layout_height="200dp">
|
||||||
|
<bitmap
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:height="200dp"
|
||||||
|
android:src="@drawable/launcher" />
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
|
||||||
|
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@android:color/white" />
|
||||||
|
<item
|
||||||
|
android:layout_height="500dp">
|
||||||
|
<bitmap
|
||||||
|
|
||||||
|
android:src="@drawable/launcher" />
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowFullscreen">true</item>
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.com.xiaohao.flutter_demo01">
|
||||||
|
<!-- Flutter needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
@ -0,0 +1,29 @@
|
|||||||
|
buildscript {
|
||||||
|
ext.kotlin_version = '1.3.50'
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.buildDir = '../build'
|
||||||
|
subprojects {
|
||||||
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
|
project.evaluationDependsOn(':app')
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
@ -0,0 +1,6 @@
|
|||||||
|
#Fri Jun 23 08:50:38 CEST 2017
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
@ -0,0 +1,11 @@
|
|||||||
|
include ':app'
|
||||||
|
|
||||||
|
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||||
|
def properties = new Properties()
|
||||||
|
|
||||||
|
assert localPropertiesFile.exists()
|
||||||
|
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||||
|
|
||||||
|
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
|
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||||
|
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
@ -0,0 +1 @@
|
|||||||
|
include ':app'
|
@ -0,0 +1,199 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:medicine_app/request_util.dart';
|
||||||
|
import 'package:medicine_app/search_page.dart';
|
||||||
|
import 'package:medicine_app/slide_page_route.dart';
|
||||||
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||||
|
|
||||||
|
import 'medicine_detail_page.dart';
|
||||||
|
|
||||||
|
class HomePage extends StatefulWidget {
|
||||||
|
HomePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_HomePageState createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<HomePage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).accentColor,
|
||||||
|
elevation: 2,
|
||||||
|
shadowColor: Theme.of(context).shadowColor,
|
||||||
|
toolbarHeight: 50,
|
||||||
|
title: TextButton(
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.search_sharp,
|
||||||
|
size: 17,
|
||||||
|
),
|
||||||
|
Text('搜索')
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor: MaterialStateProperty.all(Colors.grey.shade500),
|
||||||
|
shadowColor: MaterialStateProperty.all(Colors.transparent),
|
||||||
|
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||||||
|
minimumSize: MaterialStateProperty.all(Size.fromHeight(32)),
|
||||||
|
backgroundColor: MaterialStateProperty.all(Colors.white24.withOpacity(0.80)),
|
||||||
|
textStyle: MaterialStateProperty.all(TextStyle(fontSize: 13, letterSpacing: 2)),
|
||||||
|
shape: MaterialStateProperty.all(
|
||||||
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.of(context).push(SlidePageRoute(builder: SearchMedicinePage())),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(future: Future.sync(() {
|
||||||
|
return Request.getDio().get('/medicine/outlines');
|
||||||
|
}), builder: (BuildContext context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map data = json.decode(snapshot.data.toString());
|
||||||
|
final List<dynamic> medicineList = data['data'];
|
||||||
|
return ListView.builder(
|
||||||
|
cacheExtent: 10,
|
||||||
|
padding: EdgeInsets.only(bottom: 30),
|
||||||
|
itemCount: medicineList.length + 1,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
if (index < medicineList.length) {
|
||||||
|
final Map medicine = medicineList[index];
|
||||||
|
final List<dynamic> medicineDetails = medicine['details'];
|
||||||
|
return Card(
|
||||||
|
color: Colors.grey[10],
|
||||||
|
shadowColor: Colors.grey[50],
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
borderOnForeground: false,
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||||
|
// 外边距
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
|
||||||
|
height: 250,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(
|
||||||
|
"${medicine['name']}",
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: Builder(builder: (context) {
|
||||||
|
final int pageCount = (medicineDetails.length / 6).ceil();
|
||||||
|
final int maxPageCount = medicineDetails.length;
|
||||||
|
final controller = PageController();
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 3),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
children: [
|
||||||
|
SmoothPageIndicator(
|
||||||
|
controller: controller, // PageController
|
||||||
|
count: pageCount,
|
||||||
|
effect: WormEffect(dotWidth: 7, dotHeight: 7)),
|
||||||
|
PageView(
|
||||||
|
children: List.generate(pageCount, (index) {
|
||||||
|
return GridView.count(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
crossAxisCount: 3,
|
||||||
|
mainAxisSpacing: 20,
|
||||||
|
crossAxisSpacing: 35,
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 30,
|
||||||
|
),
|
||||||
|
children: medicineDetails
|
||||||
|
.sublist(index * 6, min((index + 1) * 6, maxPageCount))
|
||||||
|
.map((e) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(SlidePageRoute(
|
||||||
|
builder: MedicineDetailPage(name: "${e['text']}"),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: null != e['icon']
|
||||||
|
? CircleAvatar(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).secondaryHeaderColor,
|
||||||
|
backgroundImage: Image.network(
|
||||||
|
e['icon'],
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
loadingBuilder: (context, child, loadingProgress) {
|
||||||
|
if (loadingProgress == null) {
|
||||||
|
return child;
|
||||||
|
} else {
|
||||||
|
return Icon(Icons.downloading_outlined);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
).image,
|
||||||
|
radius: 50,
|
||||||
|
)
|
||||||
|
: CircleAvatar(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).secondaryHeaderColor,
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Text(
|
||||||
|
'${e['text']}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black.withAlpha(170)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList());
|
||||||
|
}).toList(),
|
||||||
|
controller: controller,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Text(
|
||||||
|
'- 没有更多了 -',
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: SpinKitFadingCircle(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
size: 32,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,173 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'package:medicine_app/mine_page.dart';
|
||||||
|
import 'package:medicine_app/prediction_list_page.dart';
|
||||||
|
import 'package:medicine_app/request_util.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'package:medicine_app/slide_page_route.dart';
|
||||||
|
import 'home_page.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
Request.initialize();
|
||||||
|
runApp(MedicineApp());
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MedicineApp extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<MedicineApp> createState() => _MedicineAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MedicineAppState extends State<MedicineApp> {
|
||||||
|
final _pageList = [
|
||||||
|
HomePage(),
|
||||||
|
MinePage(),
|
||||||
|
];
|
||||||
|
|
||||||
|
final _pageViewController = PageController();
|
||||||
|
int _currentPageIndex = 0;
|
||||||
|
|
||||||
|
void _bottomAppBarTap(index) {
|
||||||
|
setState(() {
|
||||||
|
_currentPageIndex = index;
|
||||||
|
});
|
||||||
|
_pageViewController.animateToPage(index, duration: Duration(milliseconds: 300), curve: Curves.ease);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color _bottomAppBarItemColor(int index, BuildContext context) {
|
||||||
|
return _currentPageIndex == index ? Theme.of(context).selectedRowColor : Theme.of(context).unselectedWidgetColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
title: '中药识别',
|
||||||
|
home: Scaffold(
|
||||||
|
body: PageView(
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
children: _pageList,
|
||||||
|
controller: _pageViewController,
|
||||||
|
),
|
||||||
|
floatingActionButton: Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
backgroundColor: Theme.of(context).selectedRowColor,
|
||||||
|
onPressed: () async {
|
||||||
|
final ImagePicker _picker = ImagePicker();
|
||||||
|
final XFile? picture =
|
||||||
|
await _picker.pickImage(source: ImageSource.camera, maxHeight: 299, maxWidth: 299);
|
||||||
|
if (picture != null) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
SlidePageRoute(
|
||||||
|
builder: PredictionListPage(path: picture.path),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "取消上传",
|
||||||
|
toastLength: Toast.LENGTH_SHORT,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
timeInSecForIosWeb: 1,
|
||||||
|
backgroundColor: Theme.of(context).unselectedWidgetColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 13,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.photo_camera,
|
||||||
|
color: Colors.white70,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||||
|
bottomNavigationBar: Container(
|
||||||
|
height: 55,
|
||||||
|
child: BottomAppBar(
|
||||||
|
color: Colors.grey.shade50,
|
||||||
|
elevation: 6,
|
||||||
|
shape: CircularNotchedRectangle(),
|
||||||
|
child: Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => _bottomAppBarTap(0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
_currentPageIndex == 0 ? Icons.home_rounded : Icons.home_outlined,
|
||||||
|
color: _bottomAppBarItemColor(0, context),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"首页",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: _bottomAppBarItemColor(0, context)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Expanded(flex: 1, child: Container()),
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => _bottomAppBarTap(1),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
_currentPageIndex == 1 ? Icons.person_rounded : Icons.person_outline_rounded,
|
||||||
|
color: _bottomAppBarItemColor(1, context),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"我的",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10, fontWeight: FontWeight.w500, color: _bottomAppBarItemColor(1, context)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
theme: Theme.of(context).copyWith(
|
||||||
|
splashColor: Colors.transparent,
|
||||||
|
highlightColor: Colors.transparent,
|
||||||
|
primaryColor: Colors.deepOrange,
|
||||||
|
primaryColorLight: Colors.white,
|
||||||
|
primaryColorDark: Colors.black87,
|
||||||
|
accentColor: Colors.deepOrange[400]?.withAlpha(224),
|
||||||
|
selectedRowColor: Colors.deepOrangeAccent[700]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDebug() {
|
||||||
|
return kDebugMode;
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:medicine_app/request_util.dart';
|
||||||
|
|
||||||
|
class MedicineDetailPage extends StatefulWidget {
|
||||||
|
final String _name;
|
||||||
|
|
||||||
|
MedicineDetailPage({Key? key, required String name})
|
||||||
|
: _name = name,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MedicineDetailPageState createState() => _MedicineDetailPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MedicineDetailPageState extends State<MedicineDetailPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
color: Colors.black,
|
||||||
|
icon: Icon(Icons.arrow_back_ios),
|
||||||
|
iconSize: 18,
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
centerTitle: true,
|
||||||
|
elevation: 0.4,
|
||||||
|
toolbarHeight: 55,
|
||||||
|
title: Text(
|
||||||
|
widget._name,
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: Future.sync(() async {
|
||||||
|
final response = await Request.getDio().get('/medicine/details', queryParameters: {'name': widget._name});
|
||||||
|
return response.data['data'] as Map<String, dynamic>;
|
||||||
|
}),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
|
||||||
|
final entries =
|
||||||
|
snapshot.data?.entries.where((element) => element.key != '_id' && element.key != 'img').toList();
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
final maxLength = entries?.length ?? 0;
|
||||||
|
return ListView.separated(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 15, horizontal: 25),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
if (index == 0 && snapshot.data?['img'] != null) {
|
||||||
|
return FractionallySizedBox(
|
||||||
|
widthFactor: 0.9,
|
||||||
|
child: ClipRRect(child: Image.network(snapshot.data?['img'])),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (index < maxLength) {
|
||||||
|
return Container(
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 10),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.workspaces_filled,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
size: 12,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.only(left: 5),
|
||||||
|
child: Text(
|
||||||
|
entries?[index].key ?? '',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
RichText(
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
text: TextSpan(
|
||||||
|
text: entries?[index].value.toString() ?? '',
|
||||||
|
style: TextStyle(color: Colors.black87, fontSize: 14, height: 3))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
'- 没有更多了 -',
|
||||||
|
style: TextStyle(color: Colors.grey, height: 2.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
separatorBuilder: (_, int index) {
|
||||||
|
if (index == 0 || index == maxLength - 1) {
|
||||||
|
return SizedBox.shrink();
|
||||||
|
} else {
|
||||||
|
return Divider(
|
||||||
|
height: 0.8, color: Theme.of(context).primaryColor.withAlpha(120));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemCount: maxLength + 1);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: SpinKitFadingCircle(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
size: 35,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
|
||||||
|
class MinePage extends StatefulWidget {
|
||||||
|
MinePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MinePageState createState() => _MinePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MinePageState extends State<MinePage> {
|
||||||
|
Container _menuListItem(String title, IconData iconData, Function? callback) {
|
||||||
|
final _textStyle =
|
||||||
|
TextStyle(color: Theme.of(context).primaryColorDark.withAlpha(160), fontSize: 15, fontWeight: FontWeight.w500);
|
||||||
|
return Container(
|
||||||
|
height: 55,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => Fluttertoast.showToast(
|
||||||
|
msg: "开发ing",
|
||||||
|
toastLength: Toast.LENGTH_SHORT,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
backgroundColor: Theme.of(context).unselectedWidgetColor,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Icon(
|
||||||
|
iconData,
|
||||||
|
size: 20,
|
||||||
|
color: Theme.of(context).accentColor,
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: _textStyle,
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Icon(
|
||||||
|
Icons.chevron_right,
|
||||||
|
color: Colors.grey.shade400,
|
||||||
|
size: 18,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).accentColor,
|
||||||
|
centerTitle: true,
|
||||||
|
elevation: 0,
|
||||||
|
toolbarHeight: 55,
|
||||||
|
title: Text(
|
||||||
|
"个人中心",
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 150,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
color: Theme.of(context).accentColor,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.account_circle_sharp,
|
||||||
|
size: 50,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => {},
|
||||||
|
child: Text(
|
||||||
|
'点击登录',
|
||||||
|
style: TextStyle(color: Colors.black87),
|
||||||
|
),
|
||||||
|
style: ButtonStyle(overlayColor: MaterialStateProperty.all(Colors.transparent)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListView.separated(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return _menuListItem('历史记录', Icons.timelapse_outlined, null);
|
||||||
|
case 1:
|
||||||
|
return _menuListItem('中药问答', Icons.question_answer, null);
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return _menuListItem('方剂智能推荐', Icons.account_tree_rounded, null);
|
||||||
|
case 3:
|
||||||
|
return _menuListItem('收藏', Icons.add_to_photos, null);
|
||||||
|
case 4:
|
||||||
|
return _menuListItem('关于', Icons.info, null);
|
||||||
|
case 5:
|
||||||
|
return _menuListItem('分享', Icons.share, null);
|
||||||
|
default:
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return Divider(
|
||||||
|
indent: 10, endIndent: 10, height: 0.5, color: Theme.of(context).accentColor.withAlpha(80));
|
||||||
|
},
|
||||||
|
itemCount: 6),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:medicine_app/medicine_detail_page.dart';
|
||||||
|
import 'package:medicine_app/request_util.dart';
|
||||||
|
import 'package:medicine_app/slide_page_route.dart';
|
||||||
|
|
||||||
|
class PredictionListPage extends StatefulWidget {
|
||||||
|
final String _path;
|
||||||
|
|
||||||
|
PredictionListPage({Key? key, required String path})
|
||||||
|
: _path = path,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_PredictionListPageState createState() => _PredictionListPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PredictionListPageState extends State<PredictionListPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
color: Colors.black,
|
||||||
|
icon: Icon(Icons.arrow_back_ios),
|
||||||
|
iconSize: 18,
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
centerTitle: true,
|
||||||
|
elevation: 0.4,
|
||||||
|
toolbarHeight: 55,
|
||||||
|
title: Text(
|
||||||
|
"预测",
|
||||||
|
style: TextStyle(color: Colors.black, fontSize: 17),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: Future.sync(() async {
|
||||||
|
final FormData formData = FormData.fromMap({"picture": await MultipartFile.fromFile(widget._path)});
|
||||||
|
final response = await Request.getDio().post('/medicine/prediction', data: formData);
|
||||||
|
return response.data['data'] as Map<String, dynamic>;
|
||||||
|
}),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
final entries = snapshot.data?.entries.toList().sublist(0, 14);
|
||||||
|
final maxLength = entries?.length ?? 0;
|
||||||
|
return ListView.separated(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
if (index < maxLength) {
|
||||||
|
return InkWell(
|
||||||
|
splashColor: Colors.grey.shade300,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(SlidePageRoute(
|
||||||
|
builder: MedicineDetailPage(name: "${entries?[index].key}"),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 65,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: Icon(
|
||||||
|
Icons.wallpaper_rounded,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: Text(
|
||||||
|
'${entries?[index].key}',
|
||||||
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
||||||
|
)),
|
||||||
|
Expanded(flex: 3, child: Text('置信度:${((entries?[index].value) * 100).toStringAsFixed(2)}%')),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Icon(
|
||||||
|
Icons.chevron_right,
|
||||||
|
size: 18,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
'- 没有更多了 -',
|
||||||
|
style: TextStyle(color: Colors.grey, height: 2.5),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemCount: maxLength + 1,
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return Divider(
|
||||||
|
indent: 25, endIndent: 20, height: 0.5, color: Theme.of(context).primaryColor.withAlpha(80));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: SpinKitFadingCircle(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
size: 35,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
import 'main.dart';
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
static late final Dio _dio;
|
||||||
|
|
||||||
|
static Dio getDio() {
|
||||||
|
return _dio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initialize() {
|
||||||
|
final options;
|
||||||
|
if (isDebug()) {
|
||||||
|
options = BaseOptions(
|
||||||
|
baseUrl: 'http://10.10.11.253:1433',
|
||||||
|
// baseUrl: 'http://210.16.189.8:21433',
|
||||||
|
connectTimeout: 5000,
|
||||||
|
receiveTimeout: 3000,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
options = BaseOptions(
|
||||||
|
baseUrl: 'http://210.16.189.8:21433',
|
||||||
|
connectTimeout: 5000,
|
||||||
|
receiveTimeout: 3000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_dio = Dio(options);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:medicine_app/request_util.dart';
|
||||||
|
import 'package:medicine_app/slide_page_route.dart';
|
||||||
|
|
||||||
|
import 'medicine_detail_page.dart';
|
||||||
|
|
||||||
|
class SearchMedicinePage extends StatefulWidget {
|
||||||
|
SearchMedicinePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SearchMedicinePageState createState() => _SearchMedicinePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SearchMedicinePageState extends State<SearchMedicinePage> {
|
||||||
|
Future? _responseFuture = Future.value();
|
||||||
|
final _textEditingController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
color: Colors.black,
|
||||||
|
icon: Icon(Icons.arrow_back_ios),
|
||||||
|
iconSize: 18,
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
elevation: 0.4,
|
||||||
|
titleSpacing: 0,
|
||||||
|
toolbarHeight: 55,
|
||||||
|
title: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
height: 32,
|
||||||
|
child: TextField(
|
||||||
|
autofocus: false,
|
||||||
|
controller: _textEditingController,
|
||||||
|
style: TextStyle(fontSize: 15),
|
||||||
|
cursorColor: Theme.of(context).primaryColor,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: Icon(Icons.close_rounded, size: 17),
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
onPressed: () => _textEditingController.clear(),
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
focusColor: Theme.of(context).primaryColor,
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
width: 1,
|
||||||
|
)),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
width: 1,
|
||||||
|
)),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
width: 1,
|
||||||
|
)),
|
||||||
|
prefixIcon: Icon(
|
||||||
|
Icons.search_rounded,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
hintText: "请输入中药名",
|
||||||
|
hintStyle: TextStyle(fontSize: 14, color: Colors.grey.shade500),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
flex: 5,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
var response = await Request.getDio()
|
||||||
|
.get('/medicine/details', queryParameters: {'keyword': _textEditingController.text});
|
||||||
|
var data = response.data['data'] as List<dynamic>;
|
||||||
|
setState(() {
|
||||||
|
_responseFuture = Future.value(data);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text('搜索'),
|
||||||
|
style: ButtonStyle(
|
||||||
|
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||||||
|
foregroundColor: MaterialStateProperty.all(Theme.of(context).primaryColor)),
|
||||||
|
),
|
||||||
|
flex: 1,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: _responseFuture ?? null,
|
||||||
|
builder: (BuildContext context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
List? data = snapshot.data as List?;
|
||||||
|
if (data == null || data.length == 0) {
|
||||||
|
return Center(
|
||||||
|
child: Text('暂无结果'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.separated(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
var item = data[index];
|
||||||
|
var medicineItem =
|
||||||
|
item.entries.where((element) => (element.key != 'name' && element.key != 'nameSource')).toList();
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push(SlidePageRoute(
|
||||||
|
builder: MedicineDetailPage(name: "${item['nameSource']}"),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
child: Html(
|
||||||
|
data: '''<div>
|
||||||
|
<h4>${item['nameSource']}</h4>
|
||||||
|
<ul>
|
||||||
|
${medicineItem.map((e) {
|
||||||
|
return "<li><p>${e.key}</p><p>${e.value}</p></li>";
|
||||||
|
}).join()}
|
||||||
|
</ul>
|
||||||
|
<!--You can pretty much put any html in here!-->
|
||||||
|
</div>''',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (BuildContext context, int index) {
|
||||||
|
return Divider(
|
||||||
|
indent: 10, endIndent: 10, height: 0.8, color: Theme.of(context).primaryColor.withAlpha(80));
|
||||||
|
},
|
||||||
|
itemCount: data.length,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return SpinKitFadingCircle(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
size: 32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SlidePageRoute extends PageRouteBuilder {
|
||||||
|
SlidePageRoute({required builder})
|
||||||
|
: super(
|
||||||
|
pageBuilder: (BuildContext context,
|
||||||
|
Animation<double> animation,
|
||||||
|
Animation<double> secondaryAnimation,) {
|
||||||
|
return builder;
|
||||||
|
},
|
||||||
|
transitionsBuilder: (BuildContext context,
|
||||||
|
Animation<double> animation,
|
||||||
|
Animation<double> secondaryAnimation,
|
||||||
|
Widget child,) {
|
||||||
|
return SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(1, 0),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(animation),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
name: medicine_app
|
||||||
|
description: 中药识别APP
|
||||||
|
|
||||||
|
# The following line prevents the package from being accidentally published to
|
||||||
|
# pub.dev using `pub publish`. This is preferred for private packages.
|
||||||
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
|
# The following defines the version and build number for your application.
|
||||||
|
# A version number is three numbers separated by dots, like 1.2.43
|
||||||
|
# followed by an optional build number separated by a +.
|
||||||
|
# Both the version and the builder number may be overridden in flutter
|
||||||
|
# build by specifying --build-name and --build-number, respectively.
|
||||||
|
# In Android, build-name is used as versionName while build-number used as versionCode.
|
||||||
|
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
||||||
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
|
# Read more about iOS versioning at
|
||||||
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
|
version: 1.0.0+1
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
image_picker:
|
||||||
|
dio:
|
||||||
|
|
||||||
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
cupertino_icons: ^1.0.2
|
||||||
|
|
||||||
|
smooth_page_indicator: ^0.3.0-nullsafety.0
|
||||||
|
flutter_spinkit: ^5.0.0
|
||||||
|
fluttertoast: ^8.0.7
|
||||||
|
flutter_html: ^2.1.1
|
||||||
|
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# The following line ensures that the Material Icons font is
|
||||||
|
# included with your application, so that you can use the icons in
|
||||||
|
# the material Icons class.
|
||||||
|
uses-material-design: true
|
||||||
|
|
||||||
|
# To add assets to your application, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||||
|
|
||||||
|
# For details regarding adding assets from package dependencies, see
|
||||||
|
# https://flutter.dev/assets-and-images/#from-packages
|
||||||
|
|
||||||
|
# To add custom fonts to your application, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts from package dependencies,
|
||||||
|
# see https://flutter.dev/custom-fonts/#from-packages
|
@ -0,0 +1,30 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility that Flutter provides. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:medicine_app/main.dart';
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(MedicineApp());
|
||||||
|
|
||||||
|
// Verify that our counter starts at 0.
|
||||||
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
expect(find.text('1'), findsNothing);
|
||||||
|
|
||||||
|
// Tap the '+' icon and trigger a frame.
|
||||||
|
await tester.tap(find.byIcon(Icons.add));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that our counter has incremented.
|
||||||
|
expect(find.text('0'), findsNothing);
|
||||||
|
expect(find.text('1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 15 KiB |