diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6ae89b --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/linux/ +/windows/ +# 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 diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..9c0232e --- /dev/null +++ b/.metadata @@ -0,0 +1,36 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "b0850beeb25f6d5b10426284f506557f66181b36" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: b0850beeb25f6d5b10426284f506557f66181b36 + base_revision: b0850beeb25f6d5b10426284f506557f66181b36 + - platform: android + create_revision: b0850beeb25f6d5b10426284f506557f66181b36 + base_revision: b0850beeb25f6d5b10426284f506557f66181b36 + - platform: linux + create_revision: b0850beeb25f6d5b10426284f506557f66181b36 + base_revision: b0850beeb25f6d5b10426284f506557f66181b36 + - platform: windows + create_revision: b0850beeb25f6d5b10426284f506557f66181b36 + base_revision: b0850beeb25f6d5b10426284f506557f66181b36 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/.vs/CMakeWorkspaceSettings.json b/.vs/CMakeWorkspaceSettings.json new file mode 100644 index 0000000..d3e1057 --- /dev/null +++ b/.vs/CMakeWorkspaceSettings.json @@ -0,0 +1,3 @@ +{ + "enableCMake": false +} \ No newline at end of file diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..6b61141 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,6 @@ +{ + "ExpandedNodes": [ + "" + ], + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/cpnav/FileContentIndex/7799ca13-2a7a-49c4-8d88-22a4a0c5fbe5.vsidx b/.vs/cpnav/FileContentIndex/7799ca13-2a7a-49c4-8d88-22a4a0c5fbe5.vsidx new file mode 100644 index 0000000..0812968 Binary files /dev/null and b/.vs/cpnav/FileContentIndex/7799ca13-2a7a-49c4-8d88-22a4a0c5fbe5.vsidx differ diff --git a/.vs/cpnav/v17/.wsuo b/.vs/cpnav/v17/.wsuo new file mode 100644 index 0000000..ecc08aa Binary files /dev/null and b/.vs/cpnav/v17/.wsuo differ diff --git a/.vs/cpnav/v17/Browse.VC.db b/.vs/cpnav/v17/Browse.VC.db new file mode 100644 index 0000000..f12b81e Binary files /dev/null and b/.vs/cpnav/v17/Browse.VC.db differ diff --git a/.vs/cpnav/v17/DocumentLayout.json b/.vs/cpnav/v17/DocumentLayout.json new file mode 100644 index 0000000..df10507 --- /dev/null +++ b/.vs/cpnav/v17/DocumentLayout.json @@ -0,0 +1,23 @@ +{ + "Version": 1, + "WorkspaceRootPath": "D:\\Android\\2\\cpnav\\", + "Documents": [], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [ + { + "DockedWidth": 200, + "SelectedChildIndex": -1, + "Children": [ + { + "$type": "Bookmark", + "Name": "ST:0:0:{cce594b6-0c39-4442-ba28-10c64ac7e89f}" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..d1f9079 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,28 @@ +# 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.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..09c3c8e --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,58 @@ +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file("local.properties") +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader("UTF-8") { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty("flutter.versionCode") +if (flutterVersionCode == null) { + flutterVersionCode = "1" +} + +def flutterVersionName = localProperties.getProperty("flutter.versionName") +if (flutterVersionName == null) { + flutterVersionName = "1.0" +} + +android { + namespace = "cn.mcxa.cpnav" + compileSdk = 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 = "cn.mcxa.cpnav" + // 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. + minSdk = flutter.minSdkVersion + targetSdk = 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 = "../.." +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..87ff801 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,59 @@ + + + + + + + + + +\ + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/java/io/flutter/plugins/BootCompleteReceiver.java b/android/app/src/main/java/io/flutter/plugins/BootCompleteReceiver.java new file mode 100644 index 0000000..1f4dc71 --- /dev/null +++ b/android/app/src/main/java/io/flutter/plugins/BootCompleteReceiver.java @@ -0,0 +1,19 @@ +package cn.mcxa.cpnav; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class BootCompleteReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())){ + Intent thisIntent = new Intent(context, MainActivity.class); + thisIntent.setAction("android.intent.action.MAIN"); + thisIntent.addCategory("android.intent.category.LAUNCHER"); + thisIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(thisIntent); + } + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/cn/mcxa/cpnav/MainActivity.kt b/android/app/src/main/kotlin/cn/mcxa/cpnav/MainActivity.kt new file mode 100644 index 0000000..4f03b03 --- /dev/null +++ b/android/app/src/main/kotlin/cn/mcxa/cpnav/MainActivity.kt @@ -0,0 +1,5 @@ +package cn.mcxa.cpnav + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..d2ffbff --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = "../build" +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..3b5b324 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e1ca574 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..536165d --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/images/navi_pointer.png b/images/navi_pointer.png new file mode 100644 index 0000000..2906654 Binary files /dev/null and b/images/navi_pointer.png differ diff --git a/images/pilerCar.png b/images/pilerCar.png new file mode 100644 index 0000000..799a54a Binary files /dev/null and b/images/pilerCar.png differ diff --git a/images/satellite.png b/images/satellite.png new file mode 100644 index 0000000..6dc2ab4 Binary files /dev/null and b/images/satellite.png differ diff --git a/lib/appbar.dart b/lib/appbar.dart new file mode 100644 index 0000000..c4e0b3b --- /dev/null +++ b/lib/appbar.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +// import '../login_in/connect/bluetooth_page.dart'; +// import '../login_in/connect/connect_type.dart'; +// import '../login_in/getx/real_data.dart'; +// import 'main.dart'; + +// final RealController controller1 = Get.find(); + +class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { + final double appBarHeight; + final RxInt _currentIndex; + final isDarkMode = false.obs; + final isCardVisible = false.obs; + final isDataVisible = false.obs; + CustomAppBar({required this.appBarHeight, required RxInt currentIndex}) + : _currentIndex = currentIndex; + + @override + Widget build(BuildContext context) { + const textStyle = TextStyle(fontSize: 16); + return AppBar( + toolbarHeight: 40, + centerTitle: true, // 标题居中 + title: Obx(() { + if (_currentIndex.value == 0) { + return const Text("桩点:", style: textStyle); + } else if (_currentIndex.value == 1) { + return const Text("设备:", style: textStyle); + } else { + return const Text("系统:", style: textStyle); + } + }), + // title: _currentIndex.value == 0 + // ? Obx(() => Text("桩点:${realController.pileId.value}", + // style: textStyle)) + // : const Text("设备:", style: textStyle), + // // const Center( + // // child: Obx(() => Text("设备:", style: textStyle)), + // // ), + // title: Obx(() { + // if (_currentIndex.value == 1) { + // return const Text("设备:", style: textStyle); + // } else if (_currentIndex.value == 0) { + // return Text("桩点:${realController.pileId.value}", + // style: textStyle); + // } else { + // return const Text("系统:", style: textStyle); + // } + // }), + + actions: [ + InkWell( + onTap: () { + isDarkMode.value = !isDarkMode.value; + }, + child: Icon( + isDarkMode.value ? Icons.dark_mode : Icons.sunny, + size: 35, + ), + ), + const SizedBox( + width: 10, + ), + InkWell( + onTap: () { + // Navigator.push(context, + // MaterialPageRoute(builder: (context) => const ScenceMap())), + }, + child: Image( + image: const AssetImage('images/satellite.png'), + // width: 40, + color: isDarkMode.value + ? Colors.white70 + : const Color.fromARGB(200, 29, 28, 28), + height: 40, + ), + ), + const SizedBox( + width: 10, + ), + _currentIndex.value == 1 + ? Row( + children: [ + Obx( + () => InkWell( + onTap: () { + // 点击图标时显示对点卡片 + // sight.isCardVisible.value = + // !sight.isCardVisible.value; // 确保控制器已定义 + }, + child: Icon( + Icons.my_location_sharp, + size: 35, + color: isCardVisible.value + ? Colors.blue + // : const Color.fromARGB(200, 29, 28, 28), + : (isDarkMode.value + ? Colors.white70 + : const Color.fromARGB(200, 29, 28, 28)), + ), // 新增图标 + ), + ), + const SizedBox( + width: 10, + ), + Obx( + () => InkWell( + onTap: () { + // final RealController controller1 = Get.find(); // 获取控制器 + // controller1.isDataVisible.value = + // !controller1.isDataVisible.value; // 更新控制器中的值 + }, + child: Icon( + Icons.date_range_rounded, + size: 35, + color: isDataVisible.value + ? Colors.blue + : (isDarkMode.value + ? Colors.white70 + : const Color.fromARGB(200, 29, 28, 28)), + ), // 新增图标 + ), + ), + const SizedBox( + width: 10, + ), + UnconstrainedBox( + child: SizedBox( + height: 30, + child: Builder( + builder: (context) => InkWell( + child: Icon( + Icons.settings_outlined, + size: 35, + color: isDarkMode.value + ? Colors.white70 + : const Color.fromARGB(200, 29, 28, 28), + ), + onTap: () => Scaffold.of(context).openEndDrawer(), + ), + ), + ), + ) + ], + ) + : const Text(""), + // Obx(() => Icon( + // blueToothController.connectedType.value == ConnectType.wifi + // ? Icons.wifi + // : (blueToothController.connectedType.value == + // ConnectType.bluetooth + // ? Icons.bluetooth + // : Icons.close), + // color: Colors.green, + // size: 30, + // )) + ], + ); + } + + @override + Size get preferredSize => Size.fromHeight(appBarHeight); +} diff --git a/lib/constants.dart b/lib/constants.dart new file mode 100644 index 0000000..107fa7a --- /dev/null +++ b/lib/constants.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +enum Themes { device, light, dark, oled } + +enum DayType { clear, check, fail, skip } + +class HaboColors { + static const Color primary = Color(0xFF09BF30); + static const Color red = Color(0xFFF44336); + static const Color skip = Color(0xFFFBC02D); + static const Color orange = Color(0xFFFF9800); +} diff --git a/lib/helpers.dart b/lib/helpers.dart new file mode 100644 index 0000000..0eada58 --- /dev/null +++ b/lib/helpers.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +TimeOfDay parseTimeOfDay(String? value) { + if (value != null) { + var times = value.split(':'); + if (times.length == 2) { + return TimeOfDay(hour: int.parse(times[0]), minute: int.parse(times[1])); + } + } + + return const TimeOfDay(hour: 12, minute: 0); +} + +DateTime transformDate(DateTime date) { + return DateTime.utc( + date.year, + date.month, + date.day, + 12, + ); +} diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9733d20 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,336 @@ +import 'package:cpnav/appbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; +import 'pages/pass_track/view.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //设置全屏 + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // TRY THIS: Try running your application with "flutter run". You'll see + // the application has a purple toolbar. Then, without quitting the app, + // try changing the seedColor in the colorScheme below to Colors.green + // and then invoke "hot reload" (save your changes or press the "hot + // reload" button in a Flutter-supported IDE, or press "r" if you used + // the command line to start the app). + // + // Notice that the counter didn't reset back to zero; the application + // state is not lost during the reload. To reset the state, use hot + // restart instead. + // + // This works for code too, not just values: Most code changes can be + // tested with just a hot reload. + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + home: const MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + late bool isPortrait; + late double appBarHeight = 34.0; + + final _currentIndex = 0.obs; + final List _pages = [ + PassTrack(), + Container( + color: Colors.green, + ), + Container( + color: Colors.blue, + ), + Container( + color: Colors.yellow, + ), + Container( + color: Colors.purple, + ), + ]; + @override + Widget build(BuildContext context) { + // This method is rerun every time setState is called, for instance as done + // by the _incrementCounter method above. + // + // The Flutter framework has been optimized to make rerunning build methods + // fast, so that you can just rebuild anything that needs updating rather + // than having to individually change instances of widgets. + return Scaffold( + appBar: PreferredSize( + // TRY THIS: Try changing the color here to a specific color (to + // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar + // change color while the other colors stay the same. + // backgroundColor: Theme.of(context).colorScheme.inversePrimary, + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + preferredSize: Size.fromHeight(appBarHeight), + child: CustomAppBar(appBarHeight: 56, currentIndex: _currentIndex), + ), + body: OrientationBuilder( + builder: (context, orientation) { + // final size = MediaQuery.of(context).size; + appBarHeight = Orientation.portrait == orientation ? 56.0 : 34.0; + isPortrait = Orientation.portrait == orientation ? true : false; + appBarHeight = Orientation.portrait == orientation ? 56.0 : 34.0; + if (!isPortrait) { + return Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: _pages[_currentIndex.value], + ), + const VerticalDivider( + width: 1, // 设置高度为1 + thickness: 1, + ), + SizedBox( + width: 48, + child: SafeArea( + child: LayoutBuilder(builder: (context, constraints) { + // 根据屏幕宽度判断横屏或竖屏 + // if (!isPortrait) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Column( + children: [ + IconButton( + onPressed: () { + setState(() { + _currentIndex.value = 0; + }); + }, + icon: + const Icon(Icons.date_range_rounded), + color: _currentIndex.value == 0 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + Align( + alignment: Alignment.center, + child: Text( + '实时', + style: TextStyle( + fontSize: 12, + color: _currentIndex.value == 0 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + ), + ), + ], + ), + const Divider( + height: 1, // 设置高度为1 + thickness: 1, + ), + // + Column( + children: [ + IconButton( + onPressed: () { + setState(() { + _currentIndex.value = 1; + }); + }, + icon: const Icon(Icons.map_outlined), + color: _currentIndex.value == 1 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + Align( + alignment: Alignment.center, + child: Text( + '桩点', + style: TextStyle( + fontSize: 12, + color: _currentIndex.value == 1 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + ), + ), + ], + ), + const Divider(), + Column( + children: [ + IconButton( + onPressed: () { + setState(() { + _currentIndex.value = 2; + }); + }, + icon: const Icon(Icons.my_location_sharp), + color: _currentIndex.value == 2 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + Align( + alignment: Alignment.center, + child: Text( + '任务', + style: TextStyle( + fontSize: 12, + color: _currentIndex.value == 2 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + ), + ), + ], + ), + const Divider(), + Column( + children: [ + IconButton( + onPressed: () { + setState(() { + _currentIndex.value = 3; + }); + }, + icon: const Icon( + Icons.table_chart_outlined), + color: _currentIndex.value == 3 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + Align( + alignment: Alignment.center, + child: Text( + '历史', + style: TextStyle( + fontSize: 12, + color: _currentIndex.value == 3 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + ), + ), + ], + ), + const Divider(), + Column( + children: [ + IconButton( + onPressed: () { + setState(() { + _currentIndex.value = 4; + }); + }, + icon: const Icon(Icons.settings), + color: _currentIndex.value == 4 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + Align( + alignment: Alignment.center, + child: Text( + '设置', + style: TextStyle( + fontSize: 12, + color: _currentIndex.value == 4 + ? const Color.fromARGB( + 255, 60, 95, 123) + : Colors.grey, + ), + ), + ), + ], + ) + ]); + // + }), + ), + ) + ]); + } // + + else { + // 竖屏布局,保持原有底部导航栏样式 + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + flex: 12, + child: _pages[_currentIndex.value], + ), + // VerticalDivider(), + Expanded( + flex: 1, + child: SizedBox( + height: 48, + child: BottomNavigationBar( + type: BottomNavigationBarType.fixed, + currentIndex: _currentIndex.value, + onTap: (index) { + setState(() { + _currentIndex.value = index; + }); + }, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.date_range_rounded), + label: "实时"), + BottomNavigationBarItem( + icon: Icon(Icons.map_outlined), label: "计划"), + BottomNavigationBarItem( + icon: Icon(Icons.my_location_sharp), + label: "对点"), + BottomNavigationBarItem( + icon: Icon(Icons.table_chart_outlined), + label: "历史"), + BottomNavigationBarItem( + icon: Icon(Icons.settings), label: "设置"), + ]), + ), + ) + ]); + } + }, + )); + } +} diff --git a/lib/models/coord_trans.dart b/lib/models/coord_trans.dart new file mode 100644 index 0000000..8921f90 --- /dev/null +++ b/lib/models/coord_trans.dart @@ -0,0 +1,63 @@ +class CoordTrans { + int id; + // ignore: non_constant_identifier_names + double L0; + String belt; + String? calibs; + String dstEllipsoid; + double dx; + double dy; + double dz; + double wx; + double wy; + double wz; + double k; + double elevation; + int isMain; + String name; + double rota; + String srcEllipsoid; + CoordTrans({ + required this.name, + // ignore: non_constant_identifier_names + required this.L0, + required this.belt, + this.calibs, + required this.dstEllipsoid, + required this.dx, + required this.dy, + required this.dz, + required this.id, + required this.wx, + required this.wy, + required this.wz, + required this.k, + required this.elevation, + required this.isMain, + required this.rota, + required this.srcEllipsoid, + }); + factory CoordTrans.fromJson(Map data) { + return CoordTrans( + name: data['name'], + id: data['id'], + L0: data['L0'].toDouble(), + belt: data['belt'], + calibs: data['calibs'], + dstEllipsoid: data['dstEllipsoid'], + dx: data['dx'].toDouble(), + dy: data['dy'].toDouble(), + dz: data['dz'].toDouble(), + wx: data['wx'].toDouble(), + wy: data['wy'].toDouble(), + wz: data['wz'].toDouble(), + rota: data['rota'].toDouble(), + k: data['k'].toDouble(), + isMain: data['is_main'], + elevation: data['elevation'].toDouble(), + srcEllipsoid: data['srcEllipsoid'], + ); + } + + void forEach(Null Function(dynamic key, dynamic value) param0) {} +} diff --git a/lib/models/login.dart b/lib/models/login.dart new file mode 100644 index 0000000..6a33920 --- /dev/null +++ b/lib/models/login.dart @@ -0,0 +1,75 @@ +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; + +import 'package:cpnav/models/user.dart'; + +class LoginPrefs extends GetxController { + static const String expireStr = "expire"; //用户名 + static const String tokenStr = "token"; //token + static const String phoneStr = "phone"; + final box = GetStorage(); // 实例化 GetStorage + + Future init() async { + await GetStorage.init(); // 初始化 GetStorage + return 'ok'; + } + + void saveExpire(int expire) { + box.write(expireStr, expire); + update(); + } + + int getExpire() { + return box.read(expireStr) ?? 0; + } + + void saveToken(String token) { + box.write(tokenStr, token); + update(); + } + + String getToken() { + return box.read(tokenStr) ?? ""; + } + + void removeExpire() { + box.remove(expireStr); + update(); + } + + void removeToken() { + box.remove(tokenStr); + update(); + } + + void savePhone(String phone) { + box.write(phoneStr, phone); + update(); + } + + String getPhone() { + return box.read(phoneStr) ?? ""; + } + + void clearLogin() { + box.erase(); // 清除所有数据 + update(); + } +} + +class UserController extends GetxController { + final box = GetStorage(); // 实例化 GetStorage + + UserModel? getUser() { + final userMap = box.read('user'); + if (userMap != null) { + return UserModel.fromJson(userMap); + } + return null; + } + + void setUser(Map user) { + box.write('user', user); + update(); + } +} diff --git a/lib/models/user.dart b/lib/models/user.dart new file mode 100644 index 0000000..5d94f09 --- /dev/null +++ b/lib/models/user.dart @@ -0,0 +1,53 @@ +class UserModel { + int id; + String updateTime; + String departmentId; + String name; + int passwordV; + String nickName; + String headImg; + String phone; + String email; + int status; + String remark; + String orgCode; + String title; + String titleImg; + String username; + UserModel({ + required this.name, + required this.departmentId, + required this.email, + required this.headImg, + required this.nickName, + required this.phone, + required this.title, + required this.titleImg, + required this.id, + required this.updateTime, + required this.orgCode, + required this.status, + required this.passwordV, + required this.remark, + required this.username, + }); + factory UserModel.fromJson(Map data) { + return UserModel( + name: data['name'], + departmentId: data['departmentId'], + email: data['email'] ?? "", + headImg: data['headImg'] ?? "", + nickName: data['nickName'] ?? "", + passwordV: data['passwordV'], + phone: data['phone'] ?? "", + title: data['title'] ?? "", + titleImg: data['title_img'] ?? "", + id: data['id'], + updateTime: data['updateTime'], + orgCode: data['org_code'], + status: data['status'], + remark: data['remark'] ?? "", + username: data['username'], + ); + } +} diff --git a/lib/pages/login/login_page.dart b/lib/pages/login/login_page.dart new file mode 100644 index 0000000..d54d404 --- /dev/null +++ b/lib/pages/login/login_page.dart @@ -0,0 +1,392 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:cpnav/pages/login/loginprefs.dart'; +import 'package:cpnav/service/base.dart'; + +class Login extends StatefulWidget { + const Login({super.key}); + + @override + State createState() => _LoginState(); +} + +class _LoginState extends State with SingleTickerProviderStateMixin { + //with SingleTickerProviderStateMixin 使this 不报错 + late TabController _tabController; + //初始化实例 + @override + void initState() { + _tabController = TabController(length: 2, vsync: this); + super.initState(); + } + + @override + void dispose() { + _tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('欢迎登录'), + ), + body: Column( + children: [ + TabBar( + labelColor: Colors.black, // 设置选中标签的字体颜色为黑色 + unselectedLabelColor: Colors.grey, // 设置未选中标签的字体颜色为灰色 + labelStyle: const TextStyle(color: Colors.black), // 设置选中标签的字体颜色为黑色 + unselectedLabelStyle: + const TextStyle(color: Colors.grey), // 设置未选中标签的字体颜色为灰色 + controller: _tabController, + tabs: const [ + Tab(text: '手机号登录', icon: Icon(Icons.phone_android)), + Tab(text: '账号登录', icon: Icon(Icons.account_box_outlined)), + ], + ), + Expanded( + child: TabBarView( + controller: _tabController, + children: const [ + PhoneLoginPage(), + AccountLoginPage(), + ], + ), + ), + ], + ), + ); + } +} + +class AccountLoginPage extends StatefulWidget { + const AccountLoginPage({super.key}); + + @override + State createState() => _AccountLoginPageState(); +} + +class _AccountLoginPageState extends State { + //初始化FormState + final _formKey = GlobalKey(); + String username = ""; + String password = ""; + String verifyCode = ""; + String svgString = ""; + String captchaId = ""; + @override + void initState() { + super.initState(); + SchedulerBinding.instance.addPostFrameCallback((_) async { + await changeCaptcha(); + }); + } + + changeCaptcha() async { + var captcha = await GetServices().getCaptcha(); + setState(() { + svgString = captcha['data']; + captchaId = captcha['captchaId']; + }); + } + + showErrorSnackbar(BuildContext context, String text) { + final snackBar = SnackBar( + content: Text(text), + backgroundColor: Colors.red, + ); + + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + LoginPrefs loginPrefs = LoginPrefs(); + bool _obscureText = false; + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Form( + key: _formKey, + child: Column( + children: [ + // 账号输入框 + TextFormField( + decoration: const InputDecoration( + labelText: '用户名:', + ), + onSaved: (String? value) => username = value!, + validator: (String? value) { + String str = ""; + + RegExp regex = RegExp(r'^[a-zA-Z0-9]+$'); + if (value!.isEmpty) { + str = '用户名不能为空'; + } else if (!regex.hasMatch(value)) { + str = '请输入有效的账号'; + } + + return str == "" ? null : str; + }, + ), + const SizedBox(height: 16.0), + + // 密码输入框 + TextFormField( + decoration: InputDecoration( + labelText: '密码:', + suffixIcon: IconButton( + icon: Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; // 切换密码可见状态 + }); + }), + ), + obscureText: _obscureText, + onSaved: (String? value) => password = value!, + validator: (String? value) { + String str = ""; + RegExp regex = RegExp(r'^[a-zA-Z0-9@#$]+$'); + + if (value!.isEmpty) { + str = '密码不能为空'; + } else if (!regex.hasMatch(value)) { + str = '请输入有效的密码'; + } + + return str == "" ? null : str; + }, + ), + const SizedBox(height: 24.0), + Row( + children: [ + Expanded( + child: TextFormField( + decoration: const InputDecoration( + labelText: '验证码:', + ), + keyboardType: TextInputType.phone, + validator: (String? value) { + String str = ""; + + if (value!.isEmpty) { + str = '验证码不能为空'; + } + + return str == "" ? null : str; + }, + onSaved: (String? value) => verifyCode = value!, + ), + ), + ElevatedButton( + onPressed: () async { + changeCaptcha(); + }, + child: svgString.isNotEmpty + ? SvgPicture.string( + svgString, + width: 70, // 设置宽度 + height: 40, // 设置高度 + color: Colors.black, + ) + : const Text("")) + ], + ), + // 登录按钮 + ElevatedButton( + onPressed: () async { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); //必须 + var res = await GetServices().getAccountLogin( + captchaId, password, username, verifyCode); + setState(() { + if (res['code'] != 1000) { + changeCaptcha(); + showErrorSnackbar(context, res["message"]); + } else { + loginPrefs.saveExpire((res["data"]["expire"])); + loginPrefs.saveToken((res["data"]["token"])); + Navigator.pushNamed(context, 'home'); //跳转至首页 + } + }); + } + }, + child: const Text('登录'), + ), + ], + )) + ], + ), + ), + ); + } +} + +class PhoneLoginPage extends StatefulWidget { + const PhoneLoginPage({super.key}); + + @override + State createState() => _PhoneLoginPageState(); +} + +class _PhoneLoginPageState extends State { + String phoneNumber = ""; + String smsCode = ""; + bool issmsCode = false; + String smsText = "获取验证码"; + int _seconds = 60; + late Timer _timer; + //初始化FormState + final _formKey = GlobalKey(); + LoginPrefs loginPrefs = LoginPrefs(); + @override + void initState() { + super.initState(); + + phoneNumber = loginPrefs.getPhone(); + } + + void startTimer() { + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (_seconds > 0) { + _seconds -= 1; + smsText = "重新获取(${_seconds}s)"; + } else { + _timer.cancel(); // 到0时关闭定时器 + smsText = "获取验证码"; + } + }); + } + + showErrorSnackbar(BuildContext context, String text) { + final snackBar = SnackBar( + content: Text(text), + backgroundColor: Colors.red, + ); + + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) { + return Container( + key: _scaffoldKey, + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Column( + children: [ + Form( + key: _formKey, + child: + // 手机号输入框 + Column( + children: [ + TextFormField( + maxLength: 11, + initialValue: phoneNumber, + decoration: const InputDecoration( + labelText: '手机号', + ), + keyboardType: TextInputType.phone, + validator: (String? value) { + String str = ""; + final RegExp phoneRegex = RegExp(r'^[1-9]\d{10}$'); + if (value!.isEmpty) { + str = '手机号不能为空'; + } else if (!phoneRegex.hasMatch(value)) { + str = '请输入有效的手机号'; + } + + return str == "" ? null : str; + }, + onSaved: (String? value) => phoneNumber = value!, + ), + Row( + children: [ + Expanded( + child: TextFormField( + maxLength: 6, + decoration: const InputDecoration( + labelText: '验证码', + ), + keyboardType: TextInputType.phone, + validator: (String? value) { + String str = ""; + if (value!.isEmpty) { + str = '验证码不能为空'; + } + + if (issmsCode) { + return null; + } + return str == "" ? null : str; + }, + onSaved: (val) => smsCode = val!, + ), + ), + // 获取验证码按钮 + ElevatedButton( + onPressed: () async { + issmsCode = true; + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + // 收回键盘 + FocusScope.of(context).unfocus(); + await GetServices().getsmsCode(phoneNumber); + startTimer(); // 开始定时器 + } + }, + child: Text(smsText), + ), + ], + ), + const SizedBox(height: 16.0), + + // 登录按钮 + ElevatedButton( + onPressed: () async { + issmsCode = false; + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + // 表单校验通过,执行提交逻辑... + // 收回键盘 + FocusScope.of(context).unfocus(); + var res = await GetServices() + .phoneLogin(phoneNumber, smsCode); + setState(() { + if (res['code'] != 1000) { + showErrorSnackbar( + _scaffoldKey.currentContext!, res["message"]); + } else { + loginPrefs.savePhone(phoneNumber); + loginPrefs.saveExpire(res["data"]["expire"]); + loginPrefs.saveToken(res["data"]["token"]); + Navigator.pushNamed( + _scaffoldKey.currentContext!, 'home'); //跳转至首页 + } + }); + } + }, + child: const Text('登录'), + ), + ], + )), + ], + ), + ), + ); + } +} diff --git a/lib/pages/login/loginprefs.dart b/lib/pages/login/loginprefs.dart new file mode 100644 index 0000000..6a33920 --- /dev/null +++ b/lib/pages/login/loginprefs.dart @@ -0,0 +1,75 @@ +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; + +import 'package:cpnav/models/user.dart'; + +class LoginPrefs extends GetxController { + static const String expireStr = "expire"; //用户名 + static const String tokenStr = "token"; //token + static const String phoneStr = "phone"; + final box = GetStorage(); // 实例化 GetStorage + + Future init() async { + await GetStorage.init(); // 初始化 GetStorage + return 'ok'; + } + + void saveExpire(int expire) { + box.write(expireStr, expire); + update(); + } + + int getExpire() { + return box.read(expireStr) ?? 0; + } + + void saveToken(String token) { + box.write(tokenStr, token); + update(); + } + + String getToken() { + return box.read(tokenStr) ?? ""; + } + + void removeExpire() { + box.remove(expireStr); + update(); + } + + void removeToken() { + box.remove(tokenStr); + update(); + } + + void savePhone(String phone) { + box.write(phoneStr, phone); + update(); + } + + String getPhone() { + return box.read(phoneStr) ?? ""; + } + + void clearLogin() { + box.erase(); // 清除所有数据 + update(); + } +} + +class UserController extends GetxController { + final box = GetStorage(); // 实例化 GetStorage + + UserModel? getUser() { + final userMap = box.read('user'); + if (userMap != null) { + return UserModel.fromJson(userMap); + } + return null; + } + + void setUser(Map user) { + box.write('user', user); + update(); + } +} diff --git a/lib/pages/pass_track/controller.dart b/lib/pages/pass_track/controller.dart new file mode 100644 index 0000000..63081f6 --- /dev/null +++ b/lib/pages/pass_track/controller.dart @@ -0,0 +1,74 @@ +import 'dart:ui'; + +import 'package:get/get.dart'; +import 'package:scence_map/controller.dart'; +import 'package:cpnav/service/base.dart'; + +class PassTrackController extends GetxController { + final mapController = Get.put(ScenceMapController()); + + String projCode; + String projType; + late final GetServices service; + + PassTrackController(this.projCode, this.projType); + + @override + void onInit() { + super.onInit(); + service = GetServices(projCode: projCode, projType: projType); + loadProject(); + loadSideLine(); + loadBindDevice(); + } + + loadBindDevice() async { + var binddevices = await service.getDeviceBind(); + for (var device in binddevices) { + var dev = DeviceItem.fromJson(device); + mapController.deviceList[dev.TID] = dev; + } + } + + loadCoorTrans() async {} + + loadProject() async {} + + loadSideLine() async { + var data = await service.getSideLine(); + double maxX = -double.infinity; + double maxY = -double.infinity; + double minX = double.infinity; + double minY = double.infinity; + var sideLineData = data as Map; + sideLineData.forEach((group, items) { + for (var item in items) { + SideLineItem sideLineItem = SideLineItem.fromJson(item); + var sideLineList = mapController.sideLinListeMap[group]; + if (sideLineList == null) { + sideLineList = []; + mapController.sideLinListeMap[group] = sideLineList; + } + sideLineList.add(sideLineItem); + if (sideLineItem.x > maxX) { + maxX = sideLineItem.x; + } + if (sideLineItem.y > maxY) { + maxY = sideLineItem.y; + } + if (sideLineItem.x < minX) { + minX = sideLineItem.x; + } + if (sideLineItem.y < minY) { + minY = sideLineItem.y; + } + } + }); + if (maxX != -double.infinity && + maxY != -double.infinity && + minX != double.infinity && + minY != double.infinity) { + mapController.centerXY = Offset((maxX + minX) / 2, (maxY + minY) / 2); + } + } +} diff --git a/lib/pages/pass_track/view.dart b/lib/pages/pass_track/view.dart new file mode 100644 index 0000000..b76c775 --- /dev/null +++ b/lib/pages/pass_track/view.dart @@ -0,0 +1,30 @@ +//字体 +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:scence_map/scence_map.dart'; +import "controller.dart"; +// import '../login_in/connect/bluetooth_page.dart'; +// import '../login_in/connect/config.dart'; +// import '../login_in/connect/connect_type.dart'; +// import '../login_in/getx/blue_tooth.dart'; +// import '../setting/antenna_setting.dart'; +// import '../setting/person_details.dart'; +// import '../setting/wifi_page.dart'; +// import '../setting/xy_change.dart'; + +class PassTrack extends StatelessWidget { + final controller = Get.put(PassTrackController("WXLMB", "cp_orad")); + + PassTrack(); + + @override + Widget build(BuildContext context) { + return ScenceMapView( + children: [], + onUpdate: (Offset center, double scale, double rotation) { + print("center:$center scale:$scale rotation:$rotation"); + }, + ); + } +} diff --git a/lib/service/base.dart b/lib/service/base.dart new file mode 100644 index 0000000..5e16114 --- /dev/null +++ b/lib/service/base.dart @@ -0,0 +1,198 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:http/http.dart' as http; +import 'loginprefs.dart'; + +LoginPrefs loginPrefs = LoginPrefs(); + +class BaseService { + //创建client实例 + final _client = http.Client(); + final String token = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc1IiOjAsInJvbGVJZHMiOlsiMSIsIjI0Il0sInVzZXJuYW1lIjoiYWRtaW4iLCJ1c2VySWQiOjEsIlBWIjo1LCJvcmciOiJhIiwiaWF0IjoxNzIyODY1MTE0LCJleHAiOjE3MjQxNjExMTR9.zuY366ldKkbtd1TTfcYIZfvhrovMlXLzzRk3j65Ua7o"; + + // String baseUrl = "http://192.168.1.189:8001";//本地 + String baseUrl = "http://1.82.251.83:8001"; //线上 + String loginstatus = "登录失效"; + //发送GET请求 + getClient(String url, [bool useBaseUrl = true]) async { + try { + http.Response response = await _client + .get(Uri.parse(useBaseUrl ? baseUrl + url : url), headers: { + HttpHeaders.contentTypeHeader: "application/json", + HttpHeaders.authorizationHeader: token, + }); + var res = json.decode(response.body); + if (res['message'].contains(loginstatus)) { + loginPrefs.clearLogin(); + return; + } + return res; + } catch (e) { + print(e); + return {}; + } + } + + //发送POST请求 + postClient(String url, body) async { + try { + var data = json.encode(body); + http.Response response = await _client.post(Uri.parse(baseUrl + url), + headers: { + HttpHeaders.contentTypeHeader: "application/json", + HttpHeaders.authorizationHeader: token, + }, + body: data); + var res = json.decode(response.body); + if (res['message'].contains(loginstatus)) { + loginPrefs.clearLogin(); + return; + } + return res; + } catch (e) { + print(e); + return {}; + } + } +} + +class GetServices { + BaseService service = BaseService(); + // String projCode = 'CJGKJEBYYB'; + // int tid = 109; + String projType; + String projCode; + GetServices({this.projCode = "", this.projType = ""}); + // int tid = 1000; + // String projType = "pile_cm"; +// 道路边线 + Future getSideLine() async { + try { + Map res = await service.getClient( + '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType'); + return res['data']; + } catch (e) { + return {}; + } + } + +// 设备绑定 --- 获取设备 + Future getDeviceBind() async { + Map res = await service.getClient( + '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode'); + if (res['code'] == 1000) { + return res['data']; + } else { + return []; + } + } + + // 项目列表 + getproject() async { + Map res = await service + .getClient('/api/sys/project/list?org_code=a&proj_type=$projType'); + return res['data']; + } + + // 液压夯 + getRcordData(int page, int size, String date, + [String sort = "desc", String order = "tp_id"]) async { + Map res = await service.getClient( + "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&date=$date&sort=$sort&order=$order"); + return res['data']; + } + + //获取水泥搅拌桩点数据 + // getRcordData(int page, int size, String date, + // [String sort = "desc", String order = "pile_id"]) async { + // Map res = await service.getClient( + // "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order"); + // return res['data']; + // } + + // getRcordList(String date, String? dateEnd) async { + // dateEnd ??= date; + // Map res = await service.getClient( + // "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd"); + // return res['data']; + // } + getRcordList(String date, [String? dateEnd]) async { + dateEnd ??= date; + Map res = await service.getClient( + "/api/$projType/record/list?org_code=a&proj_code=$projCode&date=$date&dateEnd=$dateEnd"); + if (res['code'] == 1000) { + return res['data']; + } else { + return []; + } + } + + //获取施工记录的日期 + getworkDateData() async { + Map res = await service.getClient( + "/api/$projType/record/work_date?org_code=a&proj_code=$projCode"); + if (res['code'] == 1000) { + return res['data'] ?? []; + } else { + return []; + } + } + + //施工详细记录 + getProcessData(int pileId) async { + Map res = await service.getClient( + "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode"); + return res['data']; + } + + // 验证码 + getsmsCode(String phone) async { + Map res = + await service.postClient("/admin/base/open/smsCode", {"phone": phone}); + return res; + } + + // 手机号登录 + phoneLogin(String phone, String smsCode) async { + Map res = await service.postClient( + "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode}); + return res; + } + + // 获取用户信息 + getPerson() async { + Map res = await service.getClient("/admin/base/comm/person"); + return res['data']; + } + + // 验证码 + getCaptcha() async { + Map res = + await service.getClient("/admin/base/open/captcha?height=40&width=150"); + return res['data']; + } + + getAccountLogin(String captchaId, String password, String username, + String verifyCode) async { + Map res = await service.postClient("/admin/base/open/login", { + "captchaId": captchaId, + "password": password, + "username": username, + "verifyCode": verifyCode + }); + return res; + } + + getRtuLast() async { + Map res = await service.getClient( + "/api/t2n/rtu/rtu_last?proj_type=$projType&proj_code=$projCode"); + return res['data']; + } + + getCoordTrans() async { + Map res = await service.getClient( + "/api/comm/coord_trans/list?proj_type=$projType&proj_code=$projCode"); + return res['data']; + } +} diff --git a/lib/service/cp_road.dart b/lib/service/cp_road.dart new file mode 100644 index 0000000..33ee69b --- /dev/null +++ b/lib/service/cp_road.dart @@ -0,0 +1,244 @@ +import 'package:get/get.dart'; +import 'base.dart'; + +// String projCode = 'CJGKJEBYYB'; +// String tid = "109"; +// String projType = "hydraulic_tamping"; +String projCode = 'TEST'; +String tid = "1000"; +String projType = "pile_cm"; +BaseService service = BaseService(); + +class ProjController extends GetxController { + ProjController(); +// 道路边线 + Future getSideLine() async { + Map res = await service.getClient( + '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType'); + return res['data']; + } + +// 设备绑定 --- 获取设备 + Future getDeviceBind() async { + Map res = await service.getClient( + '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode'); + return res['data']; + } + + // 项目列表 + getproject() async { + Map res = await service.getClient( + '/api/sys/project/list?org_code=a&proj_type=$projType&proj_code=$projCode'); + return res['data']; + } +} + +class LoginController { + // 验证码 + getsmsCode(String phone) async { + Map res = + await service.postClient("/admin/base/open/smsCode", {"phone": phone}); + return res; + } + + // 手机号登录 + phoneLogin(String phone, String smsCode) async { + Map res = await service.postClient( + "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode}); + return res; + } + + // 获取用户信息 + getPerson() async { + Map res = await service.getClient("/admin/base/comm/person"); + return res['data']; + } + + // 验证码 + getCaptcha() async { + Map res = + await service.getClient("/admin/base/open/captcha?height=40&width=150"); + return res['data']; + } + + getAccountLogin(String captchaId, String password, String username, + String verifyCode) async { + Map res = await service.postClient("/admin/base/open/login", { + "captchaId": captchaId, + "password": password, + "username": username, + "verifyCode": verifyCode + }); + return res; + } +} + +class PileCmController { + //获取水泥搅拌桩点数据 + getRcordData(int page, int size, String date, + [String sort = "desc", String order = "pile_id"]) async { + Map res = await service.getClient( + "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order"); + return res['data']; + } + + getRcordList(String date, String? dateEnd) async { + dateEnd ??= date; + Map res = await service.getClient( + "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd"); + return res['data']; + } + + //获取施工记录的日期 + getworkDateData() async { + Map res = await service.getClient( + "/api/$projType/record/work_date?org_code=a&proj_code=$projCode&tid=$tid"); + if (res['code'] == 1000) { + return res['data'] ?? []; + } else { + return []; + } + } + + //施工详细记录 + getProcessData(int pileId) async { + Map res = await service.getClient( + "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode&tid=$tid"); + return res['data']; + } +} + +class GetServices { + BaseService service = BaseService(); + // String projCode = 'CJGKJEBYYB'; + // int tid = 109; + // String projType = "hydraulic_tamping"; + String projCode = 'TEST'; + int tid = 1000; + String projType = "pile_cm"; +// 道路边线 + Future getSideLine() async { + try { + Map res = await service.getClient( + '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType'); + return res['data']; + } catch (e) { + return {}; + } + } + +// 设备绑定 --- 获取设备 + Future getDeviceBind() async { + Map res = await service.getClient( + '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode'); + return res['data']; + } + + // 项目列表 + getproject() async { + Map res = await service + .getClient('/api/sys/project/list?org_code=a&proj_type=$projType'); + return res['data']; + } + + // 液压夯 + getRcordData(int page, int size, String date, + [String sort = "desc", String order = "tp_id"]) async { + Map res = await service.getClient( + "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order"); + return res['data']; + } + + //获取水泥搅拌桩点数据 + // getRcordData(int page, int size, String date, + // [String sort = "desc", String order = "pile_id"]) async { + // Map res = await service.getClient( + // "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order"); + // return res['data']; + // } + + // getRcordList(String date, String? dateEnd) async { + // dateEnd ??= date; + // Map res = await service.getClient( + // "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd"); + // return res['data']; + // } + getRcordList(String date, [String? dateEnd]) async { + dateEnd ??= date; + Map res = await service.getClient( + "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd"); + if (res['code'] == 1000) { + return res['data']; + } else { + return []; + } + } + + //获取施工记录的日期 + getworkDateData() async { + Map res = await service.getClient( + "/api/$projType/record/work_date?org_code=a&proj_code=$projCode&tid=$tid"); + if (res['code'] == 1000) { + return res['data'] ?? []; + } else { + return []; + } + } + + //施工详细记录 + getProcessData(int pileId) async { + Map res = await service.getClient( + "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode&tid=$tid"); + return res['data']; + } + + // 验证码 + getsmsCode(String phone) async { + Map res = + await service.postClient("/admin/base/open/smsCode", {"phone": phone}); + return res; + } + + // 手机号登录 + phoneLogin(String phone, String smsCode) async { + Map res = await service.postClient( + "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode}); + return res; + } + + // 获取用户信息 + getPerson() async { + Map res = await service.getClient("/admin/base/comm/person"); + return res['data']; + } + + // 验证码 + getCaptcha() async { + Map res = + await service.getClient("/admin/base/open/captcha?height=40&width=150"); + return res['data']; + } + + getAccountLogin(String captchaId, String password, String username, + String verifyCode) async { + Map res = await service.postClient("/admin/base/open/login", { + "captchaId": captchaId, + "password": password, + "username": username, + "verifyCode": verifyCode + }); + return res; + } + + getRtuLast() async { + Map res = await service.getClient( + "/api/t2n/rtu/rtu_last?proj_type=$projType&proj_code=$projCode"); + return res['data']; + } + + getCoordTrans() async { + Map res = await service.getClient( + "/api/comm/coord_trans/list?proj_type=$projType&proj_code=$projCode"); + return res['data']; + } +} diff --git a/lib/service/loginprefs.dart b/lib/service/loginprefs.dart new file mode 100644 index 0000000..6516904 --- /dev/null +++ b/lib/service/loginprefs.dart @@ -0,0 +1,74 @@ +import 'package:get_storage/get_storage.dart'; + +import 'package:cpnav/models/user.dart'; + +class LoginPrefs { + static const String expireStr = "expire"; //用户名 + static const String tokenStr = "token"; //token + static const String phoneStr = "phone"; + final box = GetStorage(); // 实例化 GetStorage + + Future init() async { + await GetStorage.init(); // 初始化 GetStorage + return 'ok'; + } + + void saveExpire(int expire) { + box.write(expireStr, expire); + // update(); + } + + int getExpire() { + return box.read(expireStr) ?? 0; + } + + void saveToken(String token) { + box.write(tokenStr, token); + // update(); + } + + String getToken() { + return box.read(tokenStr) ?? ""; + } + + void removeExpire() { + box.remove(expireStr); + // update(); + } + + void removeToken() { + box.remove(tokenStr); + // update(); + } + + void savePhone(String phone) { + box.write(phoneStr, phone); + // update(); + } + + String getPhone() { + return box.read(phoneStr) ?? ""; + } + + void clearLogin() { + box.erase(); // 清除所有数据 + // update(); + } +} + +class UserController { + final box = GetStorage(); // 实例化 GetStorage + + UserModel? getUser() { + final userMap = box.read('user'); + if (userMap != null) { + return UserModel.fromJson(userMap); + } + return null; + } + + void setUser(Map user) { + box.write('user', user); + // update(); + } +} diff --git a/lib/service/pile_cm.dart b/lib/service/pile_cm.dart new file mode 100644 index 0000000..1b79eb8 --- /dev/null +++ b/lib/service/pile_cm.dart @@ -0,0 +1,109 @@ +import 'package:get/get.dart'; +import 'base.dart'; + +// String projCode = 'CJGKJEBYYB'; +// String tid = "109"; +// String projType = "hydraulic_tamping"; +String projCode = 'TEST'; +String tid = "1000"; +String projType = "pile_cm"; +BaseService service = BaseService(); + +class ProjController extends GetxController { + ProjController(); +// 道路边线 + Future getSideLine() async { + Map res = await service.getClient( + '/api/comm/side_line/list?proj_code=$projCode&proj_type=$projType'); + return res['data']; + } + +// 设备绑定 --- 获取设备 + Future getDeviceBind() async { + Map res = await service.getClient( + '/api/sys/device_bind/list?proj_type=$projType&proj_code=$projCode'); + return res['data']; + } + + // 项目列表 + getproject() async { + Map res = await service.getClient( + '/api/sys/project/list?org_code=a&proj_type=$projType&proj_code=$projCode'); + return res['data']; + } +} + +class LoginController { + // 验证码 + getsmsCode(String phone) async { + Map res = + await service.postClient("/admin/base/open/smsCode", {"phone": phone}); + return res; + } + + // 手机号登录 + phoneLogin(String phone, String smsCode) async { + Map res = await service.postClient( + "/admin/base/open/phone", {"phone": phone, "smsCode": smsCode}); + return res; + } + + // 获取用户信息 + getPerson() async { + Map res = await service.getClient("/admin/base/comm/person"); + return res['data']; + } + + // 验证码 + getCaptcha() async { + Map res = + await service.getClient("/admin/base/open/captcha?height=40&width=150"); + return res['data']; + } + + getAccountLogin(String captchaId, String password, String username, + String verifyCode) async { + Map res = await service.postClient("/admin/base/open/login", { + "captchaId": captchaId, + "password": password, + "username": username, + "verifyCode": verifyCode + }); + return res; + } +} + +class PileCmController { + //获取水泥搅拌桩点数据 + getRcordData(int page, int size, String date, + [String sort = "desc", String order = "pile_id"]) async { + Map res = await service.getClient( + "/api/$projType/record/page?page=$page&size=$size&org_code=a&proj_code=$projCode&tid=$tid&date=$date&sort=$sort&order=$order"); + return res['data']; + } + + getRcordList(String date, String? dateEnd) async { + dateEnd ??= date; + Map res = await service.getClient( + "/api/$projType/record/list?org_code=a&proj_code=$projCode&tid=$tid&date=$date&dateEnd=$dateEnd"); + return res['data']; + } + + //获取施工记录的日期 + getworkDateData() async { + Map res = await service.getClient( + "/api/$projType/record/work_date?org_code=a&proj_code=$projCode&tid=$tid"); + if (res['code'] == 1000) { + return res['data'] ?? []; + } else { + return []; + } + } + + //施工详细记录 + getProcessData(int pileId) async { + Map res = await service.getClient( + "/api/$projType/process/list?pile_id=$pileId&proj_code=$projCode&tid=$tid"); + return res['data']; + } +} diff --git a/lib/service/user/loginprefs.dart b/lib/service/user/loginprefs.dart new file mode 100644 index 0000000..6a33920 --- /dev/null +++ b/lib/service/user/loginprefs.dart @@ -0,0 +1,75 @@ +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; + +import 'package:cpnav/models/user.dart'; + +class LoginPrefs extends GetxController { + static const String expireStr = "expire"; //用户名 + static const String tokenStr = "token"; //token + static const String phoneStr = "phone"; + final box = GetStorage(); // 实例化 GetStorage + + Future init() async { + await GetStorage.init(); // 初始化 GetStorage + return 'ok'; + } + + void saveExpire(int expire) { + box.write(expireStr, expire); + update(); + } + + int getExpire() { + return box.read(expireStr) ?? 0; + } + + void saveToken(String token) { + box.write(tokenStr, token); + update(); + } + + String getToken() { + return box.read(tokenStr) ?? ""; + } + + void removeExpire() { + box.remove(expireStr); + update(); + } + + void removeToken() { + box.remove(tokenStr); + update(); + } + + void savePhone(String phone) { + box.write(phoneStr, phone); + update(); + } + + String getPhone() { + return box.read(phoneStr) ?? ""; + } + + void clearLogin() { + box.erase(); // 清除所有数据 + update(); + } +} + +class UserController extends GetxController { + final box = GetStorage(); // 实例化 GetStorage + + UserModel? getUser() { + final userMap = box.read('user'); + if (userMap != null) { + return UserModel.fromJson(userMap); + } + return null; + } + + void setUser(Map user) { + box.write('user', user); + update(); + } +} diff --git a/lib/themes.dart b/lib/themes.dart new file mode 100644 index 0000000..6788cf6 --- /dev/null +++ b/lib/themes.dart @@ -0,0 +1,158 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'constants.dart'; + +class HaboTheme { + static ThemeData get lightTheme { + return ThemeData( + useMaterial3: true, + scaffoldBackgroundColor: const Color(0xFFFAFAFA), + dialogTheme: const DialogTheme(surfaceTintColor: Colors.white), + brightness: Brightness.light, + primaryColor: const Color(0xFF09BF30), + timePickerTheme: TimePickerThemeData( + hourMinuteColor: Colors.grey[100], + dialBackgroundColor: Colors.grey[100], + ), + colorScheme: ColorScheme.light( + primaryContainer: Colors.white, + secondaryContainer: Colors.grey[100], + tertiaryContainer: HaboColors.primary, + onPrimaryContainer: HaboColors.primary, + primary: HaboColors.primary, + outline: const Color(0xFF505050), + ), + fontFamily: GoogleFonts.nunito().fontFamily, + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: Color(0xFF09BF30), + ), + appBarTheme: const AppBarTheme( + elevation: 0, + systemOverlayStyle: SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.dark, + statusBarBrightness: Brightness.light, + systemNavigationBarColor: Color(0xFFFAFAFA), + systemNavigationBarDividerColor: Color(0xFFFAFAFA), + systemNavigationBarIconBrightness: Brightness.dark, + ), + ), + ); + } + + static ThemeData get darkTheme { + return ThemeData( + useMaterial3: true, + scaffoldBackgroundColor: const Color(0xFF303030), + dialogTheme: const DialogTheme( + backgroundColor: Color(0xFF505050), + surfaceTintColor: Colors.transparent, + ), + primaryColor: Colors.grey, + fontFamily: GoogleFonts.nunito().fontFamily, + switchTheme: SwitchThemeData( + thumbColor: WidgetStateProperty.resolveWith(getSwitchColorThumb), + trackColor: WidgetStateProperty.resolveWith(getSwitchTrackColor), + ), + timePickerTheme: const TimePickerThemeData( + dayPeriodTextColor: Colors.white, + hourMinuteColor: Color(0xFF353535), + dialBackgroundColor: Color(0xFF353535), + dialTextColor: Colors.white, + backgroundColor: Color(0xFF505050), + ), + colorScheme: const ColorScheme.dark( + primaryContainer: Color(0xFF505050), + secondaryContainer: Color(0xFF353535), + onPrimary: HaboColors.primary, + tertiaryContainer: HaboColors.primary, + primary: HaboColors.primary, + outline: Colors.grey, + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: Color(0xFF09BF30), + ), + appBarTheme: const AppBarTheme( + elevation: 0, + systemOverlayStyle: SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + systemNavigationBarColor: Color(0xFF303030), + systemNavigationBarDividerColor: Color(0xFF303030), + systemNavigationBarIconBrightness: Brightness.light, + ), + ), + ); + } + + static ThemeData get oledTheme { + return ThemeData( + useMaterial3: true, + scaffoldBackgroundColor: Colors.black, + dialogTheme: const DialogTheme( + backgroundColor: Color(0xFF282828), + surfaceTintColor: Colors.transparent, + ), + primaryColor: Colors.grey, + fontFamily: GoogleFonts.nunito().fontFamily, + switchTheme: SwitchThemeData( + thumbColor: WidgetStateProperty.resolveWith(getSwitchColorThumb), + trackColor: WidgetStateProperty.resolveWith(getSwitchTrackColor), + ), + timePickerTheme: const TimePickerThemeData( + dayPeriodTextColor: Colors.white, + hourMinuteColor: Color(0xFF191919), + dialBackgroundColor: Color(0xFF191919), + dialTextColor: Colors.white, + backgroundColor: Color(0xFF282828), + ), + colorScheme: const ColorScheme.dark( + primaryContainer: Color(0xFF282828), + secondaryContainer: Color(0xFF191919), + tertiaryContainer: HaboColors.primary, + onPrimary: HaboColors.primary, + primary: HaboColors.primary, + outline: Colors.grey, + ), + floatingActionButtonTheme: const FloatingActionButtonThemeData( + backgroundColor: Color(0xFF09BF30), + ), + appBarTheme: const AppBarTheme( + elevation: 0, + systemOverlayStyle: SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + systemNavigationBarColor: Colors.black, + systemNavigationBarDividerColor: Colors.black, + systemNavigationBarIconBrightness: Brightness.light, + ), + ), + ); + } +} + +Color getSwitchColorThumb(Set states) { + if (states.contains(WidgetState.selected)) { + return const Color(0xFF303030); + } + + return Colors.grey; +} + +Color getSwitchTrackColor(Set states) { + const Set interactiveStates = { + WidgetState.pressed, + WidgetState.hovered, + WidgetState.focused, + }; + + if (states.any(interactiveStates.contains)) { + return const Color(0xFF505050); + } + + if (states.contains(WidgetState.selected)) { + return HaboColors.primary; + } + + return const Color(0xFF353535); +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..0d057ca --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,428 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + url: "https://pub.dev" + source: hosted + version: "3.0.5" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + get: + dependency: "direct main" + description: + name: get + sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e + url: "https://pub.dev" + source: hosted + version: "4.6.6" + get_storage: + dependency: "direct main" + description: + name: get_storage + sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" + http: + dependency: "direct main" + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + url: "https://pub.dev" + source: hosted + version: "2.2.10" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + scence_map: + dependency: "direct main" + description: + path: "plugins/scence_map" + relative: true + source: path + version: "0.0.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" + source: hosted + version: "14.2.1" + web: + dependency: transitive + description: + name: web + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" +sdks: + dart: ">=3.4.4 <4.0.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..aef09f2 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,97 @@ +name: cpnav +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.4.4 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + scence_map: + path: plugins/scence_map + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.6 + get: ^4.6.6 + get_storage: ^2.1.1 + http: ^1.2.2 + flutter_svg: ^2.0.10+1 + google_fonts: ^6.2.1 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # 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/pilerCar.png + - images/navi_pointer.png + - images/satellite.png + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..5aff2e9 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:cpnav/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +}