fix: code name space
After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1711877484458" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="27084" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M281.258667 309.248c0 127.317333 103.082667 230.741333 230.741333 230.741333s230.741333-103.082667 230.741333-230.741333v-0.341333c0-127.317333-103.424-230.741333-230.741333-230.741334-127.317333 0.341333-230.741333 103.424-230.741333 231.082667z" fill="#06CC76" opacity=".6" p-id="27085"></path><path d="M462.165333 388.096l-261.12 375.466667c-26.624 38.570667 2.048 89.770667 49.834667 89.770666h522.24c47.786667 0 76.458667-51.2 49.834667-89.429333l-261.12-375.808c-23.552-34.133333-76.117333-34.133333-99.669334 0z" fill="#06CC76" opacity=".6" p-id="27086"></path><path d="M556.032 393.898667h-88.064c-19.114667 0-35.157333-15.701333-35.157333-35.157334 0-19.114667 15.701333-35.157333 35.157333-35.157333h88.064c19.456 0 35.157333 15.701333 35.157333 35.157333s-15.701333 35.157333-35.157333 35.157334z" fill="#FFFFFF" p-id="27087"></path><path d="M710.314667 730.112m-123.221334 0a123.221333 123.221333 0 1 0 246.442667 0 123.221333 123.221333 0 1 0-246.442667 0Z" fill="#06CC76" opacity=".6" p-id="27088"></path><path d="M645.12 784.042667c-8.192-9.216-14.336-20.138667-17.749333-32.085334l10.581333-13.994666c4.437333-5.802667 4.437333-14.336 0-20.138667l-9.557333-12.629333c4.096-12.629333 11.264-23.893333 20.821333-33.109334l15.36 1.706667c3.754667 0.341333 7.509333-0.341333 10.922667-2.048s5.802667-4.437333 7.509333-7.850667l6.144-13.653333c13.312-3.072 26.965333-3.413333 40.277333-0.682667l6.485334 14.336c1.365333 3.413333 4.096 6.144 7.509333 7.850667 3.413333 1.706667 7.168 2.730667 10.922667 2.048l17.408-1.706667c9.216 8.874667 16.042667 19.456 20.138666 31.402667l-11.264 14.677333c-4.437333 5.802667-4.437333 14.336 0 20.138667l12.288 16.042667c-3.413333 11.264-9.557333 21.504-17.408 30.378666l-21.162666-2.048c-3.754667-0.341333-7.509333 0.341333-10.922667 2.048s-5.802667 4.437333-7.509333 7.850667l-8.874667 19.114667c-11.946667 2.048-23.893333 2.048-35.498667-0.341334l-8.533333-18.773333c-1.706667-3.413333-4.096-6.144-7.509333-7.850667-3.413333-1.706667-7.168-2.730667-10.922667-2.048l-19.456 1.365334z m65.536-26.282667c15.701333 0 28.672-12.288 28.672-27.648s-12.970667-27.648-28.672-27.648-28.672 12.288-28.672 27.648 12.629333 27.648 28.672 27.648z" fill="#FFFFFF" p-id="27089"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 5.9 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1711877400209" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22626" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M306.5 756L512 584.7 215.1 401.4 12 564.3 306.5 756zM512 584.7L718.1 756 1012 564.3 808.9 401.4 512 584.7z m1.2 37.3v-1.2l-0.6 0.6-0.6-0.6v1.2L306.5 792.6l-88.3-57.7v64.9L512 975.9v0.6l0.6-0.6 0.6 0.6v-0.6l294.5-176.1v-64.9l-88.3 57.7L513.2 622zM12 239.2l203.1 162.2L512 218.8 306.5 47.5 12 239.2zM718.1 47.5L512 218.8l296.9 182.7L1012 239.2 718.1 47.5z" fill="#f4ea2a" p-id="22627"></path></svg>
|
After Width: | Height: | Size: 728 B |
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1711877635469" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="52624" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M0 0h1024v1024H0V0z" fill="#202425" opacity=".01" p-id="52625"></path><path d="M512 546.133333a34.133333 34.133333 0 0 1 28.808533 15.803734l238.933334 375.466666a34.133333 34.133333 0 0 1-57.617067 36.6592L512 643.857067l-210.1248 330.205866a34.133333 34.133333 0 0 1-57.617067-36.6592l238.933334-375.466666A34.133333 34.133333 0 0 1 512 546.133333z" fill="#11AA66" p-id="52626"></path><path d="M34.133333 170.666667a34.133333 34.133333 0 0 1 34.133334-34.133334h887.466666a34.133333 34.133333 0 0 1 34.133334 34.133334v614.4a34.133333 34.133333 0 0 1-34.133334 34.133333H68.266667a34.133333 34.133333 0 0 1-34.133334-34.133333V170.666667z" fill="#11AA66" p-id="52627"></path><path d="M809.198933 317.201067a34.133333 34.133333 0 0 1 0 48.264533l-238.933333 238.933333a34.133333 34.133333 0 0 1-48.264533 0L409.6 491.997867l-146.5344 146.5344a34.133333 34.133333 0 0 1-48.264533-48.264534l170.666666-170.666666a34.133333 34.133333 0 0 1 48.264534 0L546.133333 532.002133l214.801067-214.801066a34.133333 34.133333 0 0 1 48.264533 0z" fill="#FFFFFF" p-id="52628"></path><path d="M34.133333 68.266667a34.133333 34.133333 0 0 1 34.133334-34.133334h887.466666a34.133333 34.133333 0 1 1 0 68.266667H68.266667a34.133333 34.133333 0 0 1-34.133334-34.133333z" fill="#FFAA44" p-id="52629"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1711877604237" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="48599" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M190.01344 173.30176h642.85696c70.71744 0 128.57344 57.856 128.57344 128.57344V864.3584c0 45.0048-35.35872 80.36352-80.36352 80.36352H190.01344C119.296 944.73216 61.44 886.87616 61.44 816.15872V301.8752c0-70.71744 57.856-128.57344 128.57344-128.57344z" fill="#FFBB96" p-id="48600"></path><path d="M190.01344 173.30176h642.85696c70.71744 0 128.57344 57.856 128.57344 128.57344v401.78688l-128.57344 115.712-3.21536 3.21536-128.57344 122.14272h-511.0784C119.296 944.73216 61.44 886.87616 61.44 816.15872V301.8752c0-70.71744 57.856-128.57344 128.57344-128.57344z" fill="#CF5A1A" p-id="48601"></path><path d="M190.01344 173.30176h642.85696c70.71744 0 128.57344 57.856 128.57344 128.57344v401.78688H784.65024c-44.99456 0-80.35328 35.34848-80.35328 80.35328v160.7168H190.01344C119.296 944.73216 61.44 886.87616 61.44 816.15872V301.8752c0-70.71744 57.856-128.57344 128.57344-128.57344z" fill="#FF7A45" p-id="48602"></path><path d="M350.72 76.87168c19.29216 0 32.1536 12.86144 32.1536 32.14336v147.8656c0 19.27168-12.86144 32.13312-32.1536 32.13312-19.28192 0-32.13312-12.86144-32.13312-32.14336v-147.8656c0-19.27168 12.8512-32.13312 32.14336-32.13312z m321.4336 0c19.28192 0 32.14336 12.86144 32.14336 32.14336v147.8656c0 19.27168-12.86144 32.13312-32.14336 32.13312-19.28192 0-32.14336-12.86144-32.14336-32.14336v-147.8656c0-19.27168 12.86144-32.13312 32.1536-32.13312zM286.44352 494.72512a48.20992 48.20992 0 1 0 96.43008 0 48.20992 48.20992 0 0 0-96.43008 0zM511.4368 462.58176H704.3072c19.28192 0 32.14336 12.86144 32.14336 32.1536 0 19.28192-12.86144 32.13312-32.14336 32.13312H511.4368c-19.28192 0-32.14336-12.8512-32.14336-32.14336 0-19.28192 12.86144-32.14336 32.1536-32.14336z m0 160.7168H704.3072c19.28192 0 32.14336 12.86144 32.14336 32.1536 0 19.27168-12.86144 32.13312-32.14336 32.13312H511.4368c-19.28192 0-32.14336-12.86144-32.14336-32.14336 0-19.28192 12.86144-32.14336 32.1536-32.14336zM286.44352 655.44192a48.20992 48.20992 0 1 0 96.43008 0 48.20992 48.20992 0 0 0-96.43008 0z" fill="#FFBB96" p-id="48603"></path></svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1711877581105" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="46703" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M0 508.808533a509.064533 508.808533 0 1 0 1018.129067 0 509.064533 508.808533 0 1 0-1018.129067 0Z" fill="#BFA573" p-id="46704"></path><path d="M617.745067 341.333333c56.098133 0 118.528 51.421867 170.530133 106.581334 8.738133 9.2672 26.7776 16.384 54.101333 21.333333a34.133333 34.133333 0 0 1 27.938134 30.856533l0.119466 2.730667v89.634133c0 14.609067-11.229867 26.624-25.5488 27.835734l-2.389333 0.1024-44.561067 0.341333c-3.6864 34.1504-33.5872 60.347733-69.2224 59.477333-28.501333 0-54.135467-17.015467-64.7168-42.939733a67.140267 67.140267 0 0 1-4.2496-15.496533l-280.917333 2.082133c-3.9936 33.809067-33.7408 59.630933-69.137067 58.7776-28.501333 0-54.135467-17.015467-64.699733-42.939733a67.157333 67.157333 0 0 1-4.1472-14.779734l-18.722133 0.136534H221.866667a34.133333 34.133333 0 0 1-34.048-31.573334l-0.085334-2.56v-126.754133c0-61.4912 51.882667-120.234667 93.832534-122.760533L284.330667 341.333333h333.397333z m-160.119467 37.751467h-104.055467v85.333333h104.055467v-85.333333z m151.739733 0h-133.444266l-0.8192 85.333333h265.147733s-57.173333-85.333333-130.884267-85.333333z m-274.056533 0h-54.528c-20.616533 0-57.685333 40.277333-54.784 81.271467l0.375467 3.6352h16.3328c5.205333 0.546133 34.286933 0.5632 87.210666 0.0512l5.768534-0.0512-0.375467-84.906667z" fill="#FFFFFF" p-id="46705"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -93,7 +93,7 @@ final theme = ThemeData(
|
||||||
)),
|
)),
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
iconTheme: const IconThemeData(color: Colors.black),
|
iconTheme: const IconThemeData(color: Colors.white),
|
||||||
backgroundColor: AppTheme.primaryColor,
|
backgroundColor: AppTheme.primaryColor,
|
||||||
titleTextStyle: TextStyle(
|
titleTextStyle: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
|
|
@ -5,10 +5,10 @@ class GloablConfig {
|
||||||
// static const BASE_URL = "http://10.0.2.2:8001/api/";
|
// static const BASE_URL = "http://10.0.2.2:8001/api/";
|
||||||
// static const OSS_URL = "http://10.0.2.2:8001";
|
// static const OSS_URL = "http://10.0.2.2:8001";
|
||||||
|
|
||||||
static const BASE_URL = "http://144.123.43.138:3001/api/";
|
// static const BASE_URL = "http://144.123.43.138:3001/api/";
|
||||||
static const OSS_URL = "http://144.123.43.138:3001";
|
// static const OSS_URL = "http://144.123.43.138:3001";
|
||||||
// static const BASE_URL = "http://192.168.60.220:8001/api/";
|
static const BASE_URL = "http://192.168.60.220:8001/api/";
|
||||||
// static const OSS_URL = "http://192.168.60.220:8001";
|
static const OSS_URL = "http://192.168.60.220:8001";
|
||||||
static const DOMAIN_NAME = "山矿通";
|
static const DOMAIN_NAME = "山矿通";
|
||||||
static const DEBUG = true;
|
static const DEBUG = true;
|
||||||
static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html';
|
static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/screens/inventory/inventory.dart';
|
import 'package:sk_base_mobile/screens/inventory/inventory.dart';
|
||||||
import 'package:sk_base_mobile/screens/login/login.dart';
|
import 'package:sk_base_mobile/screens/login/login.dart';
|
||||||
|
import 'package:sk_base_mobile/screens/sale_quotation/sale_quotation.dart';
|
||||||
|
|
||||||
import '../screens/landing/landing.dart';
|
import '../screens/landing/landing.dart';
|
||||||
import '../screens/mine/useinfo/userinfo.dart';
|
import '../screens/mine/useinfo/userinfo.dart';
|
||||||
|
@ -10,10 +11,13 @@ class RouteConfig {
|
||||||
static const String login = '/login';
|
static const String login = '/login';
|
||||||
static const String userinfo = '/userinfo';
|
static const String userinfo = '/userinfo';
|
||||||
static const String inventory = '/inventory';
|
static const String inventory = '/inventory';
|
||||||
|
static const String saleQuotation = '/sale_quotation';
|
||||||
|
|
||||||
static final List<GetPage> getPages = [
|
static final List<GetPage> getPages = [
|
||||||
GetPage(name: login, page: () => LoginScreen()),
|
GetPage(name: login, page: () => LoginScreen()),
|
||||||
GetPage(name: home, page: () => LandingPage()),
|
GetPage(name: home, page: () => LandingPage()),
|
||||||
GetPage(name: userinfo, page: () => UserInfoPage()),
|
GetPage(name: userinfo, page: () => UserInfoPage()),
|
||||||
GetPage(name: inventory, page: () => const InventoryPage()),
|
GetPage(name: inventory, page: () => const InventoryPage()),
|
||||||
|
GetPage(name: saleQuotation, page: () => const SaleQuotationPage())
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
class WorkBenchModel {
|
||||||
|
final String title;
|
||||||
|
final String icon;
|
||||||
|
final String route;
|
||||||
|
WorkBenchModel(
|
||||||
|
{required this.title, required this.route, required this.icon});
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import 'package:sk_base_mobile/constants/constants.dart';
|
||||||
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
||||||
import 'package:sk_base_mobile/store/auth.store.dart';
|
import 'package:sk_base_mobile/store/auth.store.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/zt_base_date_picker.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_base_date_picker.dart';
|
||||||
|
|
||||||
class CustomAppBar extends StatelessWidget {
|
class CustomAppBar extends StatelessWidget {
|
||||||
CustomAppBar({super.key});
|
CustomAppBar({super.key});
|
||||||
|
@ -59,7 +59,7 @@ class CustomAppBar extends StatelessWidget {
|
||||||
showCupertinoModalPopup(
|
showCupertinoModalPopup(
|
||||||
context: Get.overlayContext!,
|
context: Get.overlayContext!,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ZtBaseDatePicker(
|
return SkBaseDatePicker(
|
||||||
initialDate: controller.endTime.value,
|
initialDate: controller.endTime.value,
|
||||||
endDate: controller.endTime.value,
|
endDate: controller.endTime.value,
|
||||||
onDateTimeChanged: (date) {
|
onDateTimeChanged: (date) {
|
||||||
|
|
|
@ -14,6 +14,10 @@ class InvenotryInoutPage extends StatelessWidget {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
// 工具栏的高度
|
||||||
|
SizedBox(
|
||||||
|
height: MediaQuery.of(context).padding.top,
|
||||||
|
),
|
||||||
UperBody(),
|
UperBody(),
|
||||||
const Expanded(
|
const Expanded(
|
||||||
child: TaskPageBody(),
|
child: TaskPageBody(),
|
||||||
|
|
|
@ -16,21 +16,19 @@ class LandingPage extends StatelessWidget {
|
||||||
return Material(
|
return Material(
|
||||||
child: Stack(children: [
|
child: Stack(children: [
|
||||||
const BackColors(),
|
const BackColors(),
|
||||||
SafeArea(
|
Scaffold(
|
||||||
bottom: false,
|
floatingActionButtonLocation:
|
||||||
child: Scaffold(
|
FloatingActionButtonLocation.centerDocked,
|
||||||
floatingActionButtonLocation:
|
// floatingActionButton: [0].indexWhere(
|
||||||
FloatingActionButtonLocation.centerDocked,
|
// (item) => item == controller.currentIndex.value) >
|
||||||
// floatingActionButton: [0].indexWhere(
|
// -1
|
||||||
// (item) => item == controller.currentIndex.value) >
|
// ? FloatingCreateButton()
|
||||||
// -1
|
// : null,
|
||||||
// ? FloatingCreateButton()
|
floatingActionButton: FloatingCreateButton(),
|
||||||
// : null,
|
bottomNavigationBar: BottomNavBar(),
|
||||||
floatingActionButton: FloatingCreateButton(),
|
backgroundColor: Colors.transparent,
|
||||||
bottomNavigationBar: BottomNavBar(),
|
body: Obx(() => controller.pages[controller.currentIndex.value]),
|
||||||
backgroundColor: Colors.transparent,
|
)
|
||||||
body: Obx(() => controller.pages[controller.currentIndex.value]),
|
|
||||||
))
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ class InventorySearch extends StatelessWidget {
|
||||||
// return Container(
|
// return Container(
|
||||||
// width: ScreenAdaper.width(200),
|
// width: ScreenAdaper.width(200),
|
||||||
// constraints: BoxConstraints(minWidth: ScreenAdaper.width(200)),
|
// constraints: BoxConstraints(minWidth: ScreenAdaper.width(200)),
|
||||||
// child: ZtSearchSelect<ProjectModel>(
|
// child: SkSearchSelect<ProjectModel>(
|
||||||
// isRequired: true,
|
// isRequired: true,
|
||||||
// contentPadding:
|
// contentPadding:
|
||||||
// EdgeInsets.symmetric(horizontal: ScreenAdaper.width(15)),
|
// EdgeInsets.symmetric(horizontal: ScreenAdaper.width(15)),
|
||||||
|
|
|
@ -13,10 +13,10 @@ import 'package:sk_base_mobile/screens/new_inventory_inout/components/inventory_
|
||||||
import 'package:sk_base_mobile/screens/new_inventory_inout/components/product_search.dart';
|
import 'package:sk_base_mobile/screens/new_inventory_inout/components/product_search.dart';
|
||||||
import 'package:sk_base_mobile/store/dict.store.dart';
|
import 'package:sk_base_mobile/store/dict.store.dart';
|
||||||
import 'package:sk_base_mobile/util/util.dart';
|
import 'package:sk_base_mobile/util/util.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/zt_number_input.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_number_input.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/zt_search_select.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_search_select.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/zk_date_picker.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_date_picker.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/zt_text_input.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_text_input.dart';
|
||||||
import 'package:sk_base_mobile/widgets/gradient_button.dart';
|
import 'package:sk_base_mobile/widgets/gradient_button.dart';
|
||||||
import 'package:sk_base_mobile/screens/new_inventory_inout/new_inventory_inout_controller.dart';
|
import 'package:sk_base_mobile/screens/new_inventory_inout/new_inventory_inout_controller.dart';
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 项目
|
/// 项目
|
||||||
Widget buildProjectPicker() {
|
Widget buildProjectPicker() {
|
||||||
return ZtSearchSelect<ProjectModel>(
|
return SkSearchSelect<ProjectModel>(
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
textController: controller.projectTextController,
|
textController: controller.projectTextController,
|
||||||
labelText: '项目',
|
labelText: '项目',
|
||||||
|
@ -278,7 +278,7 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 时间
|
/// 时间
|
||||||
Widget buildDatePicker() {
|
Widget buildDatePicker() {
|
||||||
return ZtDatePicker(
|
return SkDatePicker(
|
||||||
textController: controller.dateTextController,
|
textController: controller.dateTextController,
|
||||||
onClear: () {
|
onClear: () {
|
||||||
controller.payload.remove('time');
|
controller.payload.remove('time');
|
||||||
|
@ -294,7 +294,7 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 数量
|
/// 数量
|
||||||
Widget buildQuantity() {
|
Widget buildQuantity() {
|
||||||
return ZtNumberInput(
|
return SkNumberInput(
|
||||||
textController: controller.quantityTextController,
|
textController: controller.quantityTextController,
|
||||||
labelText: '数量',
|
labelText: '数量',
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -306,7 +306,7 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 单价
|
/// 单价
|
||||||
Widget buildUnitPrice() {
|
Widget buildUnitPrice() {
|
||||||
return ZtNumberInput(
|
return SkNumberInput(
|
||||||
textController: controller.unitPriceTextController,
|
textController: controller.unitPriceTextController,
|
||||||
labelText: '单价',
|
labelText: '单价',
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -317,7 +317,7 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 金额
|
/// 金额
|
||||||
Widget buildAmount() {
|
Widget buildAmount() {
|
||||||
return ZtNumberInput(
|
return SkNumberInput(
|
||||||
textController: controller.amountTextController,
|
textController: controller.amountTextController,
|
||||||
labelText: '金额',
|
labelText: '金额',
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -375,7 +375,7 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 备注
|
/// 备注
|
||||||
Widget buildRemark() {
|
Widget buildRemark() {
|
||||||
return ZtTextInput(
|
return SkTextInput(
|
||||||
textController: controller.remarkTextController,
|
textController: controller.remarkTextController,
|
||||||
labelText: '备注',
|
labelText: '备注',
|
||||||
isTextArea: true,
|
isTextArea: true,
|
||||||
|
|
|
@ -0,0 +1,692 @@
|
||||||
|
// ignore_for_file: avoid_print
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:data_table_2/data_table_2.dart';
|
||||||
|
|
||||||
|
// Copyright 2019 The Flutter team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// The file was extracted from GitHub: https://github.com/flutter/gallery
|
||||||
|
// Changes and modifications by Maxim Saplin, 2021
|
||||||
|
|
||||||
|
/// Keeps track of selected rows, feed the data into DesertsDataSource
|
||||||
|
class RestorableDessertSelections extends RestorableProperty<Set<int>> {
|
||||||
|
Set<int> _dessertSelections = {};
|
||||||
|
|
||||||
|
/// Returns whether or not a dessert row is selected by index.
|
||||||
|
bool isSelected(int index) => _dessertSelections.contains(index);
|
||||||
|
|
||||||
|
/// Takes a list of [Dessert]s and saves the row indices of selected rows
|
||||||
|
/// into a [Set].
|
||||||
|
void setDessertSelections(List<Dessert> desserts) {
|
||||||
|
final updatedSet = <int>{};
|
||||||
|
for (var i = 0; i < desserts.length; i += 1) {
|
||||||
|
var dessert = desserts[i];
|
||||||
|
if (dessert.selected) {
|
||||||
|
updatedSet.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_dessertSelections = updatedSet;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<int> createDefaultValue() => _dessertSelections;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<int> fromPrimitives(Object? data) {
|
||||||
|
final selectedItemIndices = data as List<dynamic>;
|
||||||
|
_dessertSelections = {
|
||||||
|
...selectedItemIndices.map<int>((dynamic id) => id as int),
|
||||||
|
};
|
||||||
|
return _dessertSelections;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initWithValue(Set<int> value) {
|
||||||
|
_dessertSelections = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object toPrimitives() => _dessertSelections.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
int _idCounter = 0;
|
||||||
|
|
||||||
|
/// Domain model entity
|
||||||
|
class Dessert {
|
||||||
|
Dessert(
|
||||||
|
this.name,
|
||||||
|
this.calories,
|
||||||
|
this.fat,
|
||||||
|
this.carbs,
|
||||||
|
this.protein,
|
||||||
|
this.sodium,
|
||||||
|
this.calcium,
|
||||||
|
this.iron,
|
||||||
|
);
|
||||||
|
|
||||||
|
final int id = _idCounter++;
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
final int calories;
|
||||||
|
final double fat;
|
||||||
|
final int carbs;
|
||||||
|
final double protein;
|
||||||
|
final int sodium;
|
||||||
|
final int calcium;
|
||||||
|
final int iron;
|
||||||
|
bool selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data source implementing standard Flutter's DataTableSource abstract class
|
||||||
|
/// which is part of DataTable and PaginatedDataTable synchronous data fecthin API.
|
||||||
|
/// This class uses static collection of deserts as a data store, projects it into
|
||||||
|
/// DataRows, keeps track of selected items, provides sprting capability
|
||||||
|
class DessertDataSource extends DataTableSource {
|
||||||
|
DessertDataSource.empty(this.context) {
|
||||||
|
desserts = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
DessertDataSource(this.context,
|
||||||
|
[sortedByCalories = false,
|
||||||
|
this.hasRowTaps = false,
|
||||||
|
this.hasRowHeightOverrides = false,
|
||||||
|
this.hasZebraStripes = false]) {
|
||||||
|
desserts = _desserts;
|
||||||
|
if (sortedByCalories) {
|
||||||
|
sort((d) => d.calories, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final BuildContext context;
|
||||||
|
late List<Dessert> desserts;
|
||||||
|
// Add row tap handlers and show snackbar
|
||||||
|
bool hasRowTaps = false;
|
||||||
|
// Override height values for certain rows
|
||||||
|
bool hasRowHeightOverrides = false;
|
||||||
|
// Color each Row by index's parity
|
||||||
|
bool hasZebraStripes = false;
|
||||||
|
|
||||||
|
void sort<T>(Comparable<T> Function(Dessert d) getField, bool ascending) {
|
||||||
|
desserts.sort((a, b) {
|
||||||
|
final aValue = getField(a);
|
||||||
|
final bValue = getField(b);
|
||||||
|
return ascending
|
||||||
|
? Comparable.compare(aValue, bValue)
|
||||||
|
: Comparable.compare(bValue, aValue);
|
||||||
|
});
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSelectedDesserts(RestorableDessertSelections selectedRows) {
|
||||||
|
_selectedCount = 0;
|
||||||
|
for (var i = 0; i < desserts.length; i += 1) {
|
||||||
|
var dessert = desserts[i];
|
||||||
|
if (selectedRows.isSelected(i)) {
|
||||||
|
dessert.selected = true;
|
||||||
|
_selectedCount += 1;
|
||||||
|
} else {
|
||||||
|
dessert.selected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
DataRow2 getRow(int index, [Color? color]) {
|
||||||
|
final format = NumberFormat.decimalPercentPattern(
|
||||||
|
locale: 'en',
|
||||||
|
decimalDigits: 0,
|
||||||
|
);
|
||||||
|
assert(index >= 0);
|
||||||
|
if (index >= desserts.length) throw 'index > _desserts.length';
|
||||||
|
final dessert = desserts[index];
|
||||||
|
return DataRow2.byIndex(
|
||||||
|
index: index,
|
||||||
|
selected: dessert.selected,
|
||||||
|
color: color != null
|
||||||
|
? MaterialStateProperty.all(color)
|
||||||
|
: (hasZebraStripes && index.isEven
|
||||||
|
? MaterialStateProperty.all(Theme.of(context).highlightColor)
|
||||||
|
: null),
|
||||||
|
onSelectChanged: (value) {
|
||||||
|
if (dessert.selected != value) {
|
||||||
|
_selectedCount += value! ? 1 : -1;
|
||||||
|
assert(_selectedCount >= 0);
|
||||||
|
dessert.selected = value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTap: hasRowTaps
|
||||||
|
? () => _showSnackbar(context, 'Tapped on row ${dessert.name}')
|
||||||
|
: null,
|
||||||
|
onDoubleTap: hasRowTaps
|
||||||
|
? () => _showSnackbar(context, 'Double Tapped on row ${dessert.name}')
|
||||||
|
: null,
|
||||||
|
onLongPress: hasRowTaps
|
||||||
|
? () => _showSnackbar(context, 'Long pressed on row ${dessert.name}')
|
||||||
|
: null,
|
||||||
|
onSecondaryTap: hasRowTaps
|
||||||
|
? () => _showSnackbar(context, 'Right clicked on row ${dessert.name}')
|
||||||
|
: null,
|
||||||
|
onSecondaryTapDown: hasRowTaps
|
||||||
|
? (d) =>
|
||||||
|
_showSnackbar(context, 'Right button down on row ${dessert.name}')
|
||||||
|
: null,
|
||||||
|
specificRowHeight:
|
||||||
|
hasRowHeightOverrides && dessert.fat >= 25 ? 100 : null,
|
||||||
|
cells: [
|
||||||
|
DataCell(Text(dessert.name)),
|
||||||
|
DataCell(Text('${dessert.calories}'),
|
||||||
|
onTap: () => _showSnackbar(context,
|
||||||
|
'Tapped on a cell with "${dessert.calories}"', Colors.red)),
|
||||||
|
DataCell(Text(dessert.fat.toStringAsFixed(1))),
|
||||||
|
DataCell(Text('${dessert.carbs}')),
|
||||||
|
DataCell(Text(dessert.protein.toStringAsFixed(1))),
|
||||||
|
DataCell(Text('${dessert.sodium}')),
|
||||||
|
DataCell(Text(format.format(dessert.calcium / 100))),
|
||||||
|
DataCell(Text(format.format(dessert.iron / 100))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get rowCount => desserts.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isRowCountApproximate => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get selectedRowCount => _selectedCount;
|
||||||
|
|
||||||
|
void selectAll(bool? checked) {
|
||||||
|
for (final dessert in desserts) {
|
||||||
|
dessert.selected = checked ?? false;
|
||||||
|
}
|
||||||
|
_selectedCount = (checked ?? false) ? desserts.length : 0;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Async datasource for AsynPaginatedDataTabke2 example. Based on AsyncDataTableSource which
|
||||||
|
/// is an extension to Flutter's DataTableSource and aimed at solving
|
||||||
|
/// saync data fetching scenarious by paginated table (such as using Web API)
|
||||||
|
class DessertDataSourceAsync extends AsyncDataTableSource {
|
||||||
|
DessertDataSourceAsync() {
|
||||||
|
print('DessertDataSourceAsync created');
|
||||||
|
}
|
||||||
|
|
||||||
|
DessertDataSourceAsync.empty() {
|
||||||
|
_empty = true;
|
||||||
|
print('DessertDataSourceAsync.empty created');
|
||||||
|
}
|
||||||
|
|
||||||
|
DessertDataSourceAsync.error() {
|
||||||
|
_errorCounter = 0;
|
||||||
|
print('DessertDataSourceAsync.error created');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _empty = false;
|
||||||
|
int? _errorCounter;
|
||||||
|
|
||||||
|
RangeValues? _caloriesFilter;
|
||||||
|
|
||||||
|
RangeValues? get caloriesFilter => _caloriesFilter;
|
||||||
|
set caloriesFilter(RangeValues? calories) {
|
||||||
|
_caloriesFilter = calories;
|
||||||
|
refreshDatasource();
|
||||||
|
}
|
||||||
|
|
||||||
|
final DesertsFakeWebService _repo = DesertsFakeWebService();
|
||||||
|
|
||||||
|
String _sortColumn = "name";
|
||||||
|
bool _sortAscending = true;
|
||||||
|
|
||||||
|
void sort(String columnName, bool ascending) {
|
||||||
|
_sortColumn = columnName;
|
||||||
|
_sortAscending = ascending;
|
||||||
|
refreshDatasource();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> getTotalRecords() {
|
||||||
|
return Future<int>.delayed(
|
||||||
|
const Duration(milliseconds: 0), () => _empty ? 0 : _dessertsX3.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<AsyncRowsResponse> getRows(int startIndex, int count) async {
|
||||||
|
print('getRows($startIndex, $count)');
|
||||||
|
if (_errorCounter != null) {
|
||||||
|
_errorCounter = _errorCounter! + 1;
|
||||||
|
|
||||||
|
if (_errorCounter! % 2 == 1) {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 1000));
|
||||||
|
throw 'Error #${((_errorCounter! - 1) / 2).round() + 1} has occured';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final format = NumberFormat.decimalPercentPattern(
|
||||||
|
locale: 'en',
|
||||||
|
decimalDigits: 0,
|
||||||
|
);
|
||||||
|
assert(startIndex >= 0);
|
||||||
|
|
||||||
|
// List returned will be empty is there're fewer items than startingAt
|
||||||
|
var x = _empty
|
||||||
|
? await Future.delayed(const Duration(milliseconds: 2000),
|
||||||
|
() => DesertsFakeWebServiceResponse(0, []))
|
||||||
|
: await _repo.getData(
|
||||||
|
startIndex, count, _caloriesFilter, _sortColumn, _sortAscending);
|
||||||
|
|
||||||
|
var r = AsyncRowsResponse(
|
||||||
|
x.totalRecords,
|
||||||
|
x.data.map((dessert) {
|
||||||
|
return DataRow(
|
||||||
|
key: ValueKey<int>(dessert.id),
|
||||||
|
//selected: dessert.selected,
|
||||||
|
onSelectChanged: (value) {
|
||||||
|
if (value != null) {
|
||||||
|
setRowSelection(ValueKey<int>(dessert.id), value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cells: [
|
||||||
|
DataCell(Text(dessert.name)),
|
||||||
|
DataCell(Text('${dessert.calories}')),
|
||||||
|
DataCell(Text(dessert.fat.toStringAsFixed(1))),
|
||||||
|
DataCell(Text('${dessert.carbs}')),
|
||||||
|
DataCell(Text(dessert.protein.toStringAsFixed(1))),
|
||||||
|
DataCell(Text('${dessert.sodium}')),
|
||||||
|
DataCell(Text(format.format(dessert.calcium / 100))),
|
||||||
|
DataCell(Text(format.format(dessert.iron / 100))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList());
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesertsFakeWebServiceResponse {
|
||||||
|
DesertsFakeWebServiceResponse(this.totalRecords, this.data);
|
||||||
|
|
||||||
|
/// THe total ammount of records on the server, e.g. 100
|
||||||
|
final int totalRecords;
|
||||||
|
|
||||||
|
/// One page, e.g. 10 reocrds
|
||||||
|
final List<Dessert> data;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesertsFakeWebService {
|
||||||
|
int Function(Dessert, Dessert)? _getComparisonFunction(
|
||||||
|
String column, bool ascending) {
|
||||||
|
var coef = ascending ? 1 : -1;
|
||||||
|
switch (column) {
|
||||||
|
case 'name':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * d1.name.compareTo(d2.name);
|
||||||
|
case 'calories':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * (d1.calories - d2.calories);
|
||||||
|
case 'fat':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * (d1.fat - d2.fat).round();
|
||||||
|
case 'carbs':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * (d1.carbs - d2.carbs);
|
||||||
|
case 'protein':
|
||||||
|
return (Dessert d1, Dessert d2) =>
|
||||||
|
coef * (d1.protein - d2.protein).round();
|
||||||
|
case 'sodium':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * (d1.sodium - d2.sodium);
|
||||||
|
case 'calcium':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * (d1.calcium - d2.calcium);
|
||||||
|
case 'iron':
|
||||||
|
return (Dessert d1, Dessert d2) => coef * (d1.iron - d2.iron);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<DesertsFakeWebServiceResponse> getData(int startingAt, int count,
|
||||||
|
RangeValues? caloriesFilter, String sortedBy, bool sortedAsc) async {
|
||||||
|
return Future.delayed(
|
||||||
|
Duration(
|
||||||
|
milliseconds: startingAt == 0
|
||||||
|
? 2650
|
||||||
|
: startingAt < 20
|
||||||
|
? 2000
|
||||||
|
: 400), () {
|
||||||
|
var result = _dessertsX3;
|
||||||
|
|
||||||
|
if (caloriesFilter != null) {
|
||||||
|
result = result
|
||||||
|
.where((e) =>
|
||||||
|
e.calories >= caloriesFilter.start &&
|
||||||
|
e.calories <= caloriesFilter.end)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.sort(_getComparisonFunction(sortedBy, sortedAsc));
|
||||||
|
return DesertsFakeWebServiceResponse(
|
||||||
|
result.length, result.skip(startingAt).take(count).toList());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _selectedCount = 0;
|
||||||
|
|
||||||
|
List<Dessert> _desserts = <Dessert>[
|
||||||
|
Dessert(
|
||||||
|
'Frozen Yogurt',
|
||||||
|
159,
|
||||||
|
6.0,
|
||||||
|
24,
|
||||||
|
4.0,
|
||||||
|
87,
|
||||||
|
14,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Ice Cream Sandwich',
|
||||||
|
237,
|
||||||
|
9.0,
|
||||||
|
37,
|
||||||
|
4.3,
|
||||||
|
129,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Eclair',
|
||||||
|
262,
|
||||||
|
16.0,
|
||||||
|
24,
|
||||||
|
6.0,
|
||||||
|
337,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Cupcake',
|
||||||
|
305,
|
||||||
|
3.7,
|
||||||
|
67,
|
||||||
|
4.3,
|
||||||
|
413,
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Gingerbread',
|
||||||
|
356,
|
||||||
|
16.0,
|
||||||
|
49,
|
||||||
|
3.9,
|
||||||
|
327,
|
||||||
|
7,
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Jelly Bean',
|
||||||
|
375,
|
||||||
|
0.0,
|
||||||
|
94,
|
||||||
|
0.0,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Lollipop',
|
||||||
|
392,
|
||||||
|
0.2,
|
||||||
|
98,
|
||||||
|
0.0,
|
||||||
|
38,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Honeycomb',
|
||||||
|
408,
|
||||||
|
3.2,
|
||||||
|
87,
|
||||||
|
6.5,
|
||||||
|
562,
|
||||||
|
0,
|
||||||
|
45,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Donut',
|
||||||
|
452,
|
||||||
|
25.0,
|
||||||
|
51,
|
||||||
|
4.9,
|
||||||
|
326,
|
||||||
|
2,
|
||||||
|
22,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Apple Pie',
|
||||||
|
518,
|
||||||
|
26.0,
|
||||||
|
65,
|
||||||
|
7.0,
|
||||||
|
54,
|
||||||
|
12,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Frozen Yougurt with sugar',
|
||||||
|
168,
|
||||||
|
6.0,
|
||||||
|
26,
|
||||||
|
4.0,
|
||||||
|
87,
|
||||||
|
14,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Ice Cream Sandwich with sugar',
|
||||||
|
246,
|
||||||
|
9.0,
|
||||||
|
39,
|
||||||
|
4.3,
|
||||||
|
129,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Eclair with sugar',
|
||||||
|
271,
|
||||||
|
16.0,
|
||||||
|
26,
|
||||||
|
6.0,
|
||||||
|
337,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Cupcake with sugar',
|
||||||
|
314,
|
||||||
|
3.7,
|
||||||
|
69,
|
||||||
|
4.3,
|
||||||
|
413,
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Gingerbread with sugar',
|
||||||
|
345,
|
||||||
|
16.0,
|
||||||
|
51,
|
||||||
|
3.9,
|
||||||
|
327,
|
||||||
|
7,
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Jelly Bean with sugar',
|
||||||
|
364,
|
||||||
|
0.0,
|
||||||
|
96,
|
||||||
|
0.0,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Lollipop with sugar',
|
||||||
|
401,
|
||||||
|
0.2,
|
||||||
|
100,
|
||||||
|
0.0,
|
||||||
|
38,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Honeycomd with sugar',
|
||||||
|
417,
|
||||||
|
3.2,
|
||||||
|
89,
|
||||||
|
6.5,
|
||||||
|
562,
|
||||||
|
0,
|
||||||
|
45,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Donut with sugar',
|
||||||
|
461,
|
||||||
|
25.0,
|
||||||
|
53,
|
||||||
|
4.9,
|
||||||
|
326,
|
||||||
|
2,
|
||||||
|
22,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Apple pie with sugar',
|
||||||
|
527,
|
||||||
|
26.0,
|
||||||
|
67,
|
||||||
|
7.0,
|
||||||
|
54,
|
||||||
|
12,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Forzen yougurt with honey',
|
||||||
|
223,
|
||||||
|
6.0,
|
||||||
|
36,
|
||||||
|
4.0,
|
||||||
|
87,
|
||||||
|
14,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Ice Cream Sandwich with honey',
|
||||||
|
301,
|
||||||
|
9.0,
|
||||||
|
49,
|
||||||
|
4.3,
|
||||||
|
129,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Eclair with honey',
|
||||||
|
326,
|
||||||
|
16.0,
|
||||||
|
36,
|
||||||
|
6.0,
|
||||||
|
337,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Cupcake with honey',
|
||||||
|
369,
|
||||||
|
3.7,
|
||||||
|
79,
|
||||||
|
4.3,
|
||||||
|
413,
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Gignerbread with hone',
|
||||||
|
420,
|
||||||
|
16.0,
|
||||||
|
61,
|
||||||
|
3.9,
|
||||||
|
327,
|
||||||
|
7,
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Jelly Bean with honey',
|
||||||
|
439,
|
||||||
|
0.0,
|
||||||
|
106,
|
||||||
|
0.0,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Lollipop with honey',
|
||||||
|
456,
|
||||||
|
0.2,
|
||||||
|
110,
|
||||||
|
0.0,
|
||||||
|
38,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Honeycomd with honey',
|
||||||
|
472,
|
||||||
|
3.2,
|
||||||
|
99,
|
||||||
|
6.5,
|
||||||
|
562,
|
||||||
|
0,
|
||||||
|
45,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Donut with honey',
|
||||||
|
516,
|
||||||
|
25.0,
|
||||||
|
63,
|
||||||
|
4.9,
|
||||||
|
326,
|
||||||
|
2,
|
||||||
|
22,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Apple pie with honey',
|
||||||
|
582,
|
||||||
|
26.0,
|
||||||
|
77,
|
||||||
|
7.0,
|
||||||
|
54,
|
||||||
|
12,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<Dessert> _dessertsX3 = _desserts.toList()
|
||||||
|
..addAll(_desserts.map((i) => Dessert('${i.name} x2', i.calories, i.fat,
|
||||||
|
i.carbs, i.protein, i.sodium, i.calcium, i.iron)))
|
||||||
|
..addAll(_desserts.map((i) => Dessert('${i.name} x3', i.calories, i.fat,
|
||||||
|
i.carbs, i.protein, i.sodium, i.calcium, i.iron)));
|
||||||
|
|
||||||
|
_showSnackbar(BuildContext context, String text, [Color? color]) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||||
|
backgroundColor: color,
|
||||||
|
duration: const Duration(seconds: 1),
|
||||||
|
content: Text(text),
|
||||||
|
));
|
||||||
|
}
|
|
@ -0,0 +1,755 @@
|
||||||
|
import 'package:data_table_2/data_table_2.dart';
|
||||||
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
import 'package:sk_base_mobile/widgets/core/sk_text_input.dart';
|
||||||
|
import './helper.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import './data_sources.dart';
|
||||||
|
import './nav_helper.dart';
|
||||||
|
|
||||||
|
// Copyright 2019 The Flutter team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// The file was extracted from GitHub: https://github.com/flutter/gallery
|
||||||
|
// Changes and modifications by Maxim Saplin, 2021
|
||||||
|
|
||||||
|
class DataTable2FixedNMDemo extends StatefulWidget {
|
||||||
|
const DataTable2FixedNMDemo({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
DataTable2FixedNMDemoState createState() => DataTable2FixedNMDemoState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataTable2FixedNMDemoState extends State<DataTable2FixedNMDemo> {
|
||||||
|
bool _sortAscending = true;
|
||||||
|
int? _sortColumnIndex;
|
||||||
|
late DessertDataSource _dessertsDataSource;
|
||||||
|
late DessertDataSourceAsync _asyncDessertsDataSource;
|
||||||
|
bool _initialized = false;
|
||||||
|
final ScrollController _controller = ScrollController();
|
||||||
|
String selectedTableType = dflt;
|
||||||
|
|
||||||
|
int _fixedRows = 1;
|
||||||
|
int _fixedCols = 1;
|
||||||
|
int _dataItems = 30;
|
||||||
|
|
||||||
|
DataRow _getRow(int index, [Color? color]) {
|
||||||
|
final format = NumberFormat.decimalPercentPattern(
|
||||||
|
locale: 'zh',
|
||||||
|
decimalDigits: 0,
|
||||||
|
);
|
||||||
|
assert(index >= 0);
|
||||||
|
if (index >= _desserts.length) throw 'index > _desserts.length';
|
||||||
|
final dessert = _desserts[index];
|
||||||
|
return DataRow2.byIndex(
|
||||||
|
index: index,
|
||||||
|
// selected: dessert.selected,
|
||||||
|
color: color != null ? MaterialStateProperty.all(color) : null,
|
||||||
|
// onSelectChanged: (value) {
|
||||||
|
// if (dessert.selected != value) {
|
||||||
|
// dessert.selected = value!;
|
||||||
|
// setState(() {});
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
cells: [
|
||||||
|
DataCell(SkTextInput(textController: TextEditingController())),
|
||||||
|
DataCell(Text('${dessert.calories}')),
|
||||||
|
DataCell(Text(dessert.fat.toStringAsFixed(1))),
|
||||||
|
DataCell(Text('${dessert.carbs}')),
|
||||||
|
DataCell(Text(dessert.protein.toStringAsFixed(1))),
|
||||||
|
DataCell(Text('${dessert.sodium}')),
|
||||||
|
DataCell(Text(format.format(dessert.calcium / 100))),
|
||||||
|
DataCell(Text(format.format(dessert.iron / 100))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectAll(bool? checked) {
|
||||||
|
for (final dessert in _desserts) {
|
||||||
|
dessert.selected = checked ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
if (!_initialized) {
|
||||||
|
_dessertsDataSource = DessertDataSource(context);
|
||||||
|
_asyncDessertsDataSource = DessertDataSourceAsync();
|
||||||
|
_initialized = true;
|
||||||
|
_dessertsDataSource.addListener(() {
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sort<T>(
|
||||||
|
Comparable<T> Function(Dessert d) getField,
|
||||||
|
int columnIndex,
|
||||||
|
bool ascending,
|
||||||
|
) {
|
||||||
|
_dessertsDataSource.sort<T>(getField, ascending);
|
||||||
|
setState(() {
|
||||||
|
_sortColumnIndex = columnIndex;
|
||||||
|
_sortAscending = ascending;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getTableFromSelectedType() {
|
||||||
|
switch (getCurrentRouteOption(context)) {
|
||||||
|
case paginatedFixedRowsCols:
|
||||||
|
{
|
||||||
|
return getPaginatedDataTable();
|
||||||
|
}
|
||||||
|
case asyncPaginatedFixedRowsCols:
|
||||||
|
{
|
||||||
|
return getAsyncPaginatedDataTable();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return getDataTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_dessertsDataSource.dispose();
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(children: [
|
||||||
|
// _getParamsWidget(context),
|
||||||
|
Flexible(
|
||||||
|
fit: FlexFit.tight,
|
||||||
|
child: Theme(
|
||||||
|
data: ThemeData(dividerColor: Colors.grey[400]),
|
||||||
|
child: getTableFromSelectedType()))
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTable2 getDataTable() {
|
||||||
|
return DataTable2(
|
||||||
|
scrollController: _controller,
|
||||||
|
columnSpacing: 0,
|
||||||
|
bottomMargin: 20,
|
||||||
|
border: TableBorder.all(width: 1.0, color: AppTheme.dividerColor),
|
||||||
|
// headingRowColor: MaterialStateProperty.resolveWith(
|
||||||
|
// (states) => _fixedRows > 0 ? Colors.grey[200] : Colors.transparent),
|
||||||
|
// headingRowDecoration: BoxDecoration(
|
||||||
|
// gradient: LinearGradient(
|
||||||
|
// colors: [
|
||||||
|
// Colors.grey[400]!,
|
||||||
|
// Colors.grey[200]!,
|
||||||
|
// ],
|
||||||
|
// begin: Alignment.topCenter,
|
||||||
|
// end: Alignment.bottomCenter,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
fixedColumnsColor: Colors.grey[100],
|
||||||
|
// fixedCornerColor: Colors.grey[400],
|
||||||
|
minWidth: 1000,
|
||||||
|
fixedTopRows: _fixedRows,
|
||||||
|
fixedLeftColumns: _fixedCols,
|
||||||
|
// sortColumnIndex: _sortColumnIndex,
|
||||||
|
// sortAscending: _sortAscending,
|
||||||
|
// onSelectAll: (val) => setState(() => selectAll(val)),
|
||||||
|
columns: [
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('过渡'),
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<String>((d) => d.name, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('名称'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.calories, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('规格、型号及说明'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.fat, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('单位'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.carbs, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('数量'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.protein, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('备注'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.sodium, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('单价'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.calcium, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('总价'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.iron, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
rows: List<DataRow>.generate(
|
||||||
|
_dataItems, (index) => _getRow(index, Colors.transparent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getPaginatedDataTable() {
|
||||||
|
return PaginatedDataTable2(
|
||||||
|
scrollController: _controller,
|
||||||
|
columnSpacing: 0,
|
||||||
|
horizontalMargin: 12,
|
||||||
|
border: TableBorder.all(width: 1.0, color: Colors.grey),
|
||||||
|
headingRowColor: MaterialStateProperty.resolveWith(
|
||||||
|
(states) => _fixedRows > 0 ? Colors.grey[200] : Colors.transparent),
|
||||||
|
fixedColumnsColor: Colors.grey[300],
|
||||||
|
fixedCornerColor: Colors.grey[400],
|
||||||
|
minWidth: 1000,
|
||||||
|
fixedTopRows: _fixedRows,
|
||||||
|
fixedLeftColumns: _fixedCols,
|
||||||
|
sortColumnIndex: _sortColumnIndex,
|
||||||
|
sortAscending: _sortAscending,
|
||||||
|
onSelectAll: (val) => setState(() => selectAll(val)),
|
||||||
|
columns: [
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Desert'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<String>((d) => d.name, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Calories'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.calories, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Fat (gm)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.fat, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Carbs (gm)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.carbs, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Protein (gm)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.protein, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Sodium (mg)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.sodium, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Calcium (%)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.calcium, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Iron (%)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.iron, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
source: _dessertsDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getAsyncPaginatedDataTable() {
|
||||||
|
return AsyncPaginatedDataTable2(
|
||||||
|
scrollController: _controller,
|
||||||
|
columnSpacing: 0,
|
||||||
|
horizontalMargin: 12,
|
||||||
|
border: TableBorder.all(width: 1.0, color: Colors.grey),
|
||||||
|
headingRowColor: MaterialStateProperty.resolveWith(
|
||||||
|
(states) => _fixedRows > 0 ? Colors.grey[200] : Colors.transparent),
|
||||||
|
fixedColumnsColor: Colors.grey[300],
|
||||||
|
fixedCornerColor: Colors.grey[400],
|
||||||
|
minWidth: 1000,
|
||||||
|
fixedTopRows: _fixedRows,
|
||||||
|
fixedLeftColumns: _fixedCols,
|
||||||
|
sortColumnIndex: _sortColumnIndex,
|
||||||
|
sortAscending: _sortAscending,
|
||||||
|
onSelectAll: (val) => setState(() => selectAll(val)),
|
||||||
|
columns: [
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Desert'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<String>((d) => d.name, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Calories'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.calories, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Fat (gm)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.fat, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Carbs (gm)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.carbs, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Protein (gm)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.protein, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Sodium (mg)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.sodium, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Calcium (%)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.calcium, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
DataColumn2(
|
||||||
|
label: const Text('Iron (%)'),
|
||||||
|
size: ColumnSize.S,
|
||||||
|
numeric: true,
|
||||||
|
onSort: (columnIndex, ascending) =>
|
||||||
|
_sort<num>((d) => d.iron, columnIndex, ascending),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
source: _asyncDessertsDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
Theme _getParamsWidget(BuildContext context) {
|
||||||
|
const double col1 = 130;
|
||||||
|
const double col2 = 210;
|
||||||
|
return Theme(
|
||||||
|
data: blackSlider(context),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 36,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: col1, child: Text('Fixed rows ($_fixedRows)')),
|
||||||
|
SizedBox(
|
||||||
|
width: col2,
|
||||||
|
child: Slider(
|
||||||
|
value: _fixedRows.toDouble(),
|
||||||
|
min: 0,
|
||||||
|
max: 10,
|
||||||
|
divisions: 10,
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
_fixedRows = val.toInt();
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
SizedBox(
|
||||||
|
height: 36,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: col1,
|
||||||
|
child: Text('Fixed columns ($_fixedCols)')),
|
||||||
|
SizedBox(
|
||||||
|
width: col2,
|
||||||
|
child: Slider(
|
||||||
|
value: _fixedCols.toDouble(),
|
||||||
|
min: 0,
|
||||||
|
max: 10,
|
||||||
|
divisions: 10,
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
_fixedCols = val.toInt();
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
SizedBox(
|
||||||
|
height: 36,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: col1, child: Text('Data items ($_dataItems)')),
|
||||||
|
SizedBox(
|
||||||
|
width: col2,
|
||||||
|
child: Slider(
|
||||||
|
value: _dataItems.toDouble(),
|
||||||
|
min: 0,
|
||||||
|
max: 30,
|
||||||
|
divisions: 10,
|
||||||
|
onChanged: (val) {
|
||||||
|
setState(() {
|
||||||
|
_dataItems = val.toInt();
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
],
|
||||||
|
))
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Dessert> _desserts = <Dessert>[
|
||||||
|
Dessert(
|
||||||
|
'Frozen Yogurt',
|
||||||
|
159,
|
||||||
|
6.0,
|
||||||
|
24,
|
||||||
|
4.0,
|
||||||
|
87,
|
||||||
|
14,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Ice Cream Sandwich',
|
||||||
|
237,
|
||||||
|
9.0,
|
||||||
|
37,
|
||||||
|
4.3,
|
||||||
|
129,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Eclair',
|
||||||
|
262,
|
||||||
|
16.0,
|
||||||
|
24,
|
||||||
|
6.0,
|
||||||
|
337,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Cupcake',
|
||||||
|
305,
|
||||||
|
3.7,
|
||||||
|
67,
|
||||||
|
4.3,
|
||||||
|
413,
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Gingerbread',
|
||||||
|
356,
|
||||||
|
16.0,
|
||||||
|
49,
|
||||||
|
3.9,
|
||||||
|
327,
|
||||||
|
7,
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Jelly Bean',
|
||||||
|
375,
|
||||||
|
0.0,
|
||||||
|
94,
|
||||||
|
0.0,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Lollipop',
|
||||||
|
392,
|
||||||
|
0.2,
|
||||||
|
98,
|
||||||
|
0.0,
|
||||||
|
38,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Honeycomb',
|
||||||
|
408,
|
||||||
|
3.2,
|
||||||
|
87,
|
||||||
|
6.5,
|
||||||
|
562,
|
||||||
|
0,
|
||||||
|
45,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Donut',
|
||||||
|
452,
|
||||||
|
25.0,
|
||||||
|
51,
|
||||||
|
4.9,
|
||||||
|
326,
|
||||||
|
2,
|
||||||
|
22,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Apple Pie',
|
||||||
|
518,
|
||||||
|
26.0,
|
||||||
|
65,
|
||||||
|
7.0,
|
||||||
|
54,
|
||||||
|
12,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Frozen Yougurt with sugar',
|
||||||
|
168,
|
||||||
|
6.0,
|
||||||
|
26,
|
||||||
|
4.0,
|
||||||
|
87,
|
||||||
|
14,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Ice Cream Sandwich with sugar',
|
||||||
|
246,
|
||||||
|
9.0,
|
||||||
|
39,
|
||||||
|
4.3,
|
||||||
|
129,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Eclair with sugar',
|
||||||
|
271,
|
||||||
|
16.0,
|
||||||
|
26,
|
||||||
|
6.0,
|
||||||
|
337,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Cupcake with sugar',
|
||||||
|
314,
|
||||||
|
3.7,
|
||||||
|
69,
|
||||||
|
4.3,
|
||||||
|
413,
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Gingerbread with sugar',
|
||||||
|
345,
|
||||||
|
16.0,
|
||||||
|
51,
|
||||||
|
3.9,
|
||||||
|
327,
|
||||||
|
7,
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Jelly Bean with sugar',
|
||||||
|
364,
|
||||||
|
0.0,
|
||||||
|
96,
|
||||||
|
0.0,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Lollipop with sugar',
|
||||||
|
401,
|
||||||
|
0.2,
|
||||||
|
100,
|
||||||
|
0.0,
|
||||||
|
38,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Honeycomd with sugar',
|
||||||
|
417,
|
||||||
|
3.2,
|
||||||
|
89,
|
||||||
|
6.5,
|
||||||
|
562,
|
||||||
|
0,
|
||||||
|
45,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Donut with sugar',
|
||||||
|
461,
|
||||||
|
25.0,
|
||||||
|
53,
|
||||||
|
4.9,
|
||||||
|
326,
|
||||||
|
2,
|
||||||
|
22,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Apple pie with sugar',
|
||||||
|
527,
|
||||||
|
26.0,
|
||||||
|
67,
|
||||||
|
7.0,
|
||||||
|
54,
|
||||||
|
12,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Forzen yougurt with honey',
|
||||||
|
223,
|
||||||
|
6.0,
|
||||||
|
36,
|
||||||
|
4.0,
|
||||||
|
87,
|
||||||
|
14,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Ice Cream Sandwich with honey',
|
||||||
|
301,
|
||||||
|
9.0,
|
||||||
|
49,
|
||||||
|
4.3,
|
||||||
|
129,
|
||||||
|
8,
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Eclair with honey',
|
||||||
|
326,
|
||||||
|
16.0,
|
||||||
|
36,
|
||||||
|
6.0,
|
||||||
|
337,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Cupcake with honey',
|
||||||
|
369,
|
||||||
|
3.7,
|
||||||
|
79,
|
||||||
|
4.3,
|
||||||
|
413,
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Gignerbread with hone',
|
||||||
|
420,
|
||||||
|
16.0,
|
||||||
|
61,
|
||||||
|
3.9,
|
||||||
|
327,
|
||||||
|
7,
|
||||||
|
16,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Jelly Bean with honey',
|
||||||
|
439,
|
||||||
|
0.0,
|
||||||
|
106,
|
||||||
|
0.0,
|
||||||
|
50,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Lollipop with honey',
|
||||||
|
456,
|
||||||
|
0.2,
|
||||||
|
110,
|
||||||
|
0.0,
|
||||||
|
38,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Honeycomd with honey',
|
||||||
|
472,
|
||||||
|
3.2,
|
||||||
|
99,
|
||||||
|
6.5,
|
||||||
|
562,
|
||||||
|
0,
|
||||||
|
45,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Donut with honey',
|
||||||
|
516,
|
||||||
|
25.0,
|
||||||
|
63,
|
||||||
|
4.9,
|
||||||
|
326,
|
||||||
|
2,
|
||||||
|
22,
|
||||||
|
),
|
||||||
|
Dessert(
|
||||||
|
'Apple pie with honey',
|
||||||
|
582,
|
||||||
|
26.0,
|
||||||
|
77,
|
||||||
|
7.0,
|
||||||
|
54,
|
||||||
|
12,
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
];
|
|
@ -0,0 +1,176 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
ThemeData blackSlider(BuildContext context) {
|
||||||
|
return Theme.of(context).copyWith(
|
||||||
|
sliderTheme: SliderThemeData(
|
||||||
|
rangeThumbShape:
|
||||||
|
const RectRangeSliderThumbShape(enabledThumbRadius: 8),
|
||||||
|
thumbShape: const RectSliderThumbShape(enabledThumbRadius: 8),
|
||||||
|
thumbColor: Colors.grey[800],
|
||||||
|
activeTrackColor: Colors.grey[700],
|
||||||
|
inactiveTrackColor: Colors.grey[400],
|
||||||
|
activeTickMarkColor: Colors.white,
|
||||||
|
inactiveTickMarkColor: Colors.white));
|
||||||
|
}
|
||||||
|
|
||||||
|
class RectRangeSliderThumbShape extends RangeSliderThumbShape {
|
||||||
|
const RectRangeSliderThumbShape({
|
||||||
|
this.enabledThumbRadius = 10.0,
|
||||||
|
this.disabledThumbRadius,
|
||||||
|
this.elevation = 1.0,
|
||||||
|
this.pressedElevation = 6.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
final double enabledThumbRadius;
|
||||||
|
|
||||||
|
final double? disabledThumbRadius;
|
||||||
|
double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius;
|
||||||
|
|
||||||
|
final double elevation;
|
||||||
|
|
||||||
|
final double pressedElevation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
|
||||||
|
return Size.fromRadius(
|
||||||
|
isEnabled == true ? enabledThumbRadius : _disabledThumbRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(
|
||||||
|
PaintingContext context,
|
||||||
|
Offset center, {
|
||||||
|
required Animation<double> activationAnimation,
|
||||||
|
required Animation<double> enableAnimation,
|
||||||
|
bool isDiscrete = false,
|
||||||
|
bool isEnabled = false,
|
||||||
|
bool? isOnTop,
|
||||||
|
required SliderThemeData sliderTheme,
|
||||||
|
TextDirection? textDirection,
|
||||||
|
Thumb? thumb,
|
||||||
|
bool? isPressed,
|
||||||
|
}) {
|
||||||
|
assert(sliderTheme.showValueIndicator != null);
|
||||||
|
assert(sliderTheme.overlappingShapeStrokeColor != null);
|
||||||
|
|
||||||
|
final Canvas canvas = context.canvas;
|
||||||
|
final Tween<double> radiusTween = Tween<double>(
|
||||||
|
begin: _disabledThumbRadius,
|
||||||
|
end: enabledThumbRadius,
|
||||||
|
);
|
||||||
|
final ColorTween colorTween = ColorTween(
|
||||||
|
begin: sliderTheme.disabledThumbColor,
|
||||||
|
end: sliderTheme.thumbColor,
|
||||||
|
);
|
||||||
|
final double radius = radiusTween.evaluate(enableAnimation);
|
||||||
|
final Tween<double> elevationTween = Tween<double>(
|
||||||
|
begin: elevation,
|
||||||
|
end: pressedElevation,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isOnTop ?? false) {
|
||||||
|
final Paint strokePaint = Paint()
|
||||||
|
..color = sliderTheme.overlappingShapeStrokeColor!
|
||||||
|
..strokeWidth = 1.0
|
||||||
|
..style = PaintingStyle.stroke;
|
||||||
|
canvas.drawRect(
|
||||||
|
Rect.fromCenter(
|
||||||
|
center: center, width: 2 * radius, height: 2 * radius),
|
||||||
|
strokePaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Color color = colorTween.evaluate(enableAnimation)!;
|
||||||
|
|
||||||
|
final double evaluatedElevation =
|
||||||
|
isPressed! ? elevationTween.evaluate(activationAnimation) : elevation;
|
||||||
|
final Path shadowPath = Path()
|
||||||
|
..addArc(
|
||||||
|
Rect.fromCenter(
|
||||||
|
center: center, width: 2 * radius, height: 2 * radius),
|
||||||
|
0,
|
||||||
|
pi * 2);
|
||||||
|
canvas.drawShadow(shadowPath, Colors.black, evaluatedElevation, true);
|
||||||
|
|
||||||
|
canvas.drawRect(
|
||||||
|
Rect.fromCenter(center: center, width: 2 * radius, height: 2 * radius),
|
||||||
|
Paint()..color = color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RectSliderThumbShape extends SliderComponentShape {
|
||||||
|
const RectSliderThumbShape({
|
||||||
|
this.enabledThumbRadius = 10.0,
|
||||||
|
this.disabledThumbRadius,
|
||||||
|
this.elevation = 1.0,
|
||||||
|
this.pressedElevation = 6.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
final double enabledThumbRadius;
|
||||||
|
|
||||||
|
final double? disabledThumbRadius;
|
||||||
|
double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius;
|
||||||
|
|
||||||
|
final double elevation;
|
||||||
|
|
||||||
|
final double pressedElevation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
|
||||||
|
return Size.fromRadius(
|
||||||
|
isEnabled == true ? enabledThumbRadius : _disabledThumbRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(
|
||||||
|
PaintingContext context,
|
||||||
|
Offset center, {
|
||||||
|
required Animation<double> activationAnimation,
|
||||||
|
required Animation<double> enableAnimation,
|
||||||
|
required bool isDiscrete,
|
||||||
|
required TextPainter labelPainter,
|
||||||
|
required RenderBox parentBox,
|
||||||
|
required SliderThemeData sliderTheme,
|
||||||
|
required TextDirection textDirection,
|
||||||
|
required double value,
|
||||||
|
required double textScaleFactor,
|
||||||
|
required Size sizeWithOverflow,
|
||||||
|
}) {
|
||||||
|
assert(sliderTheme.disabledThumbColor != null);
|
||||||
|
assert(sliderTheme.thumbColor != null);
|
||||||
|
|
||||||
|
final Canvas canvas = context.canvas;
|
||||||
|
final Tween<double> radiusTween = Tween<double>(
|
||||||
|
begin: _disabledThumbRadius,
|
||||||
|
end: enabledThumbRadius,
|
||||||
|
);
|
||||||
|
final ColorTween colorTween = ColorTween(
|
||||||
|
begin: sliderTheme.disabledThumbColor,
|
||||||
|
end: sliderTheme.thumbColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
final Color color = colorTween.evaluate(enableAnimation)!;
|
||||||
|
final double radius = radiusTween.evaluate(enableAnimation);
|
||||||
|
|
||||||
|
final Tween<double> elevationTween = Tween<double>(
|
||||||
|
begin: elevation,
|
||||||
|
end: pressedElevation,
|
||||||
|
);
|
||||||
|
|
||||||
|
final double evaluatedElevation =
|
||||||
|
elevationTween.evaluate(activationAnimation);
|
||||||
|
final Path path = Path()
|
||||||
|
..addArc(
|
||||||
|
Rect.fromCenter(
|
||||||
|
center: center, width: 2 * radius, height: 2 * radius),
|
||||||
|
0,
|
||||||
|
pi * 2);
|
||||||
|
canvas.drawShadow(path, Colors.black, evaluatedElevation, true);
|
||||||
|
|
||||||
|
canvas.drawRect(
|
||||||
|
Rect.fromCenter(center: center, width: 2 * radius, height: 2 * radius),
|
||||||
|
Paint()..color = color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Route options are used to configure certain features of
|
||||||
|
/// the given example
|
||||||
|
String getCurrentRouteOption(BuildContext context) {
|
||||||
|
var isEmpty = ModalRoute.of(context) != null &&
|
||||||
|
ModalRoute.of(context)!.settings.arguments != null &&
|
||||||
|
ModalRoute.of(context)!.settings.arguments is String
|
||||||
|
? ModalRoute.of(context)!.settings.arguments as String
|
||||||
|
: '';
|
||||||
|
|
||||||
|
return isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route options
|
||||||
|
const dflt = 'Default';
|
||||||
|
const noData = 'No data';
|
||||||
|
const autoRows = 'Auto rows';
|
||||||
|
const showBordersWithZebraStripes = 'Borders with Zebra';
|
||||||
|
const custPager = 'Custom pager';
|
||||||
|
const defaultSorting = 'Default sorting';
|
||||||
|
const selectAllPage = 'Select all at page';
|
||||||
|
const rowTaps = 'Row Taps';
|
||||||
|
const rowHeightOverrides = 'Row height overrides';
|
||||||
|
const fixedColumnWidth = 'Fixed column width';
|
||||||
|
const dataTable2 = 'DataTable2';
|
||||||
|
const paginatedFixedRowsCols = 'PaginatedDataTable2';
|
||||||
|
const asyncPaginatedFixedRowsCols = 'AsyncPaginatedDataTable2';
|
||||||
|
const custArrows = 'Custom sort arrows';
|
||||||
|
const asyncErrors =
|
||||||
|
"Errors/Retries"; // Async sample that emulates network error and allow retrying load operation
|
||||||
|
const goToLast =
|
||||||
|
"Start at last page"; // Used by async example, navigates to the very last page upon opening the screen
|
||||||
|
const rounded = 'Rounded style';
|
||||||
|
|
||||||
|
/// Configurations available to given example routes
|
||||||
|
const Map<String, List<String>> routeOptions = {
|
||||||
|
'/datatable2': [
|
||||||
|
dflt,
|
||||||
|
noData,
|
||||||
|
showBordersWithZebraStripes,
|
||||||
|
fixedColumnWidth,
|
||||||
|
rowTaps,
|
||||||
|
rowHeightOverrides,
|
||||||
|
custArrows,
|
||||||
|
rounded
|
||||||
|
],
|
||||||
|
'/paginated2': [dflt, noData, autoRows, custPager, defaultSorting],
|
||||||
|
'/datatable2fixedmn': [
|
||||||
|
dataTable2,
|
||||||
|
paginatedFixedRowsCols,
|
||||||
|
asyncPaginatedFixedRowsCols
|
||||||
|
],
|
||||||
|
'/asyncpaginated2': [
|
||||||
|
dflt,
|
||||||
|
noData,
|
||||||
|
selectAllPage,
|
||||||
|
autoRows,
|
||||||
|
asyncErrors,
|
||||||
|
goToLast,
|
||||||
|
custPager
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
List<String>? getOptionsForRoute(String route) {
|
||||||
|
if (!routeOptions.containsKey(route)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return routeOptions[route];
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
||||||
|
import 'package:sk_base_mobile/screens/sale_quotation/components/data_table.dart';
|
||||||
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
import 'package:sk_base_mobile/widgets/sk_appbar.dart';
|
||||||
|
|
||||||
|
class SaleQuotationPage extends StatelessWidget {
|
||||||
|
const SaleQuotationPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: const SkAppbar(title: '报价计算'),
|
||||||
|
body: buildBody(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildBody() {
|
||||||
|
return DataTable2FixedNMDemo();
|
||||||
|
// return SingleChildScrollView(
|
||||||
|
// child: Column(
|
||||||
|
// children: [Text('11')],
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// return SliverStickyHeader.builder(
|
||||||
|
// builder: (context, state) => Container(
|
||||||
|
// height: 60.0,
|
||||||
|
// color: (state.isPinned ? Colors.pink : Colors.lightBlue)
|
||||||
|
// .withOpacity(1.0 - state.scrollPercentage),
|
||||||
|
// padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
// alignment: Alignment.centerLeft,
|
||||||
|
// child: Text(
|
||||||
|
// 'Header #1',
|
||||||
|
// style: const TextStyle(color: Colors.white),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// sliver: SliverList(
|
||||||
|
// delegate: SliverChildBuilderDelegate(
|
||||||
|
// (context, i) => ListTile(
|
||||||
|
// leading: CircleAvatar(
|
||||||
|
// child: Text('0'),
|
||||||
|
// ),
|
||||||
|
// title: Text('List tile #$i'),
|
||||||
|
// ),
|
||||||
|
// childCount: 4,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,118 +1,150 @@
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
|
||||||
import 'package:sk_base_mobile/constants/router.dart';
|
import 'package:sk_base_mobile/constants/router.dart';
|
||||||
|
import 'package:sk_base_mobile/screens/workbench/workbench_controller.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
||||||
|
|
||||||
class WorkBenchModel {
|
|
||||||
final String title;
|
|
||||||
final String route;
|
|
||||||
WorkBenchModel({required this.title, required this.route});
|
|
||||||
}
|
|
||||||
|
|
||||||
class WorkBenchPage extends StatelessWidget {
|
class WorkBenchPage extends StatelessWidget {
|
||||||
WorkBenchPage({super.key});
|
WorkBenchPage({super.key});
|
||||||
final List<WorkBenchModel> works = [
|
final controller = Get.put(WorkBenchController());
|
||||||
WorkBenchModel(title: '库存', route: '/inventory'),
|
|
||||||
WorkBenchModel(title: '产品', route: '/product'),
|
|
||||||
WorkBenchModel(title: '合同', route: '/contract'),
|
|
||||||
WorkBenchModel(title: '人事', route: '/personnel'),
|
|
||||||
WorkBenchModel(title: '公车', route: '/finance'),
|
|
||||||
WorkBenchModel(title: '任务', route: '/task_manage'),
|
|
||||||
WorkBenchModel(title: '报表', route: '/report'),
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: const SizedBox(),
|
leading: const SizedBox(),
|
||||||
title: const Text(
|
title: const Text(
|
||||||
'工作台',
|
'工作台',
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Column(children: [
|
|
||||||
Container(
|
|
||||||
padding: EdgeInsets.all(ScreenAdaper.width(20)),
|
|
||||||
child: GridView.builder(
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemCount: works.length,
|
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: Get.width > 800 ? 5 : 3,
|
|
||||||
crossAxisSpacing: ScreenAdaper.width(20),
|
|
||||||
mainAxisSpacing: ScreenAdaper.height(20),
|
|
||||||
childAspectRatio: 1.0),
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
return buildCard(index);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
])),
|
body: buildList()
|
||||||
|
// Container(
|
||||||
|
// padding: EdgeInsets.all(ScreenAdaper.width(20)),
|
||||||
|
// child: GridView.builder(
|
||||||
|
// shrinkWrap: true,
|
||||||
|
// physics: const NeverScrollableScrollPhysics(),
|
||||||
|
// itemCount: works.length,
|
||||||
|
// gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
// crossAxisCount: Get.width > 800 ? 5 : 3,
|
||||||
|
// crossAxisSpacing: ScreenAdaper.width(20),
|
||||||
|
// mainAxisSpacing: ScreenAdaper.height(20),
|
||||||
|
// childAspectRatio: 1.0),
|
||||||
|
// itemBuilder: (BuildContext context, int index) {
|
||||||
|
// return buildCard(index);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildList() {
|
||||||
|
return MasonryGridView.count(
|
||||||
|
padding: EdgeInsets.only(top: ScreenAdaper.width(20)),
|
||||||
|
crossAxisCount: Get.width > 800 ? 6 : 4,
|
||||||
|
itemCount: controller.menus.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return buildItem(
|
||||||
|
index,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildCard(int index) {
|
Widget buildItem(int index) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final route = RouteConfig.getPages
|
final route = RouteConfig.getPages
|
||||||
.map((e) => e.name)
|
.map((e) => e.name)
|
||||||
.firstWhereOrNull((name) => name == works[index].route);
|
.firstWhereOrNull((name) => name == controller.menus[index].route);
|
||||||
if (route != null) {
|
if (route != null) {
|
||||||
Get.toNamed(works[index].route);
|
Get.toNamed(controller.menus[index].route);
|
||||||
} else {
|
} else {
|
||||||
SnackBarUtil().info('功能待开发。');
|
SnackBarUtil().info('功能待开发。');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
clipBehavior: Clip.antiAlias,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
padding: EdgeInsets.only(
|
||||||
borderRadius: BorderRadius.circular(10),
|
top: ScreenAdaper.height(20), bottom: ScreenAdaper.height(20)),
|
||||||
gradient: const LinearGradient(
|
child: Column(
|
||||||
begin: Alignment.centerLeft,
|
children: [
|
||||||
end: Alignment.centerRight,
|
SvgPicture.asset(
|
||||||
colors: [AppTheme.primaryColorLight, AppTheme.primaryColor]),
|
'assets/icons/${controller.menus[index].icon}',
|
||||||
boxShadow: [
|
width: ScreenAdaper.width(100),
|
||||||
BoxShadow(
|
height: ScreenAdaper.width(100),
|
||||||
color: AppTheme.black.withOpacity(0.4),
|
|
||||||
offset: const Offset(0, 0),
|
|
||||||
blurRadius: 1,
|
|
||||||
spreadRadius: 1)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
child: Stack(
|
SizedBox(
|
||||||
children: [
|
height: ScreenAdaper.height(10),
|
||||||
// Image.asset(works[index].icon),
|
),
|
||||||
Center(
|
Text(controller.menus[index].title)
|
||||||
child: Stack(
|
],
|
||||||
alignment: Alignment.center,
|
),
|
||||||
children: [
|
),
|
||||||
Text(
|
);
|
||||||
works[index].title,
|
|
||||||
style: TextStyle(
|
|
||||||
letterSpacing: ScreenAdaper.width(10),
|
|
||||||
fontSize: ScreenAdaper.height(40),
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
foreground: Paint()
|
|
||||||
..style = PaintingStyle.stroke
|
|
||||||
..strokeWidth = 5
|
|
||||||
..color = Colors.black),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
works[index].title,
|
|
||||||
style: TextStyle(
|
|
||||||
letterSpacing: ScreenAdaper.width(10),
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: ScreenAdaper.height(40),
|
|
||||||
fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
// Widget buildCard(int index) {
|
||||||
|
// return InkWell(
|
||||||
|
// onTap: () {
|
||||||
|
// final route = RouteConfig.getPages
|
||||||
|
// .map((e) => e.name)
|
||||||
|
// .firstWhereOrNull((name) => name == works[index].route);
|
||||||
|
// if (route != null) {
|
||||||
|
// Get.toNamed(works[index].route);
|
||||||
|
// } else {
|
||||||
|
// SnackBarUtil().info('功能待开发。');
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// child: Container(
|
||||||
|
// clipBehavior: Clip.antiAlias,
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// borderRadius: BorderRadius.circular(10),
|
||||||
|
// gradient: const LinearGradient(
|
||||||
|
// begin: Alignment.centerLeft,
|
||||||
|
// end: Alignment.centerRight,
|
||||||
|
// colors: [AppTheme.primaryColorLight, AppTheme.primaryColor]),
|
||||||
|
// boxShadow: [
|
||||||
|
// BoxShadow(
|
||||||
|
// color: AppTheme.black.withOpacity(0.4),
|
||||||
|
// offset: const Offset(0, 0),
|
||||||
|
// blurRadius: 1,
|
||||||
|
// spreadRadius: 1)
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// child: Stack(
|
||||||
|
// children: [
|
||||||
|
// // Image.asset(works[index].icon),
|
||||||
|
// Center(
|
||||||
|
// child: Stack(
|
||||||
|
// alignment: Alignment.center,
|
||||||
|
// children: [
|
||||||
|
// Text(
|
||||||
|
// works[index].title,
|
||||||
|
// style: TextStyle(
|
||||||
|
// letterSpacing: ScreenAdaper.width(10),
|
||||||
|
// fontSize: ScreenAdaper.height(40),
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// foreground: Paint()
|
||||||
|
// ..style = PaintingStyle.stroke
|
||||||
|
// ..strokeWidth = 5
|
||||||
|
// ..color = Colors.black),
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// works[index].title,
|
||||||
|
// style: TextStyle(
|
||||||
|
// letterSpacing: ScreenAdaper.width(10),
|
||||||
|
// color: Colors.white,
|
||||||
|
// fontSize: ScreenAdaper.height(40),
|
||||||
|
// fontWeight: FontWeight.bold),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// )));
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:sk_base_mobile/models/workbench.model.dart';
|
||||||
|
|
||||||
class WorkBenchController extends GetxController {
|
class WorkBenchController extends GetxController {
|
||||||
late final AnimationController animationController;
|
late final AnimationController animationController;
|
||||||
|
final List<WorkBenchModel> menus = [
|
||||||
|
WorkBenchModel(title: '库存', route: '/inventory', icon: 'inventory.svg'),
|
||||||
|
WorkBenchModel(title: '产品', route: '/product', icon: 'product.svg'),
|
||||||
|
WorkBenchModel(title: '合同', route: '/contract', icon: 'contract.svg'),
|
||||||
|
WorkBenchModel(title: '人事', route: '/hr', icon: 'hr.svg'),
|
||||||
|
WorkBenchModel(title: '公车', route: '/vehicle', icon: 'vehicle.svg'),
|
||||||
|
WorkBenchModel(title: '任务', route: '/task_manage', icon: 'task_manage.svg'),
|
||||||
|
WorkBenchModel(title: '报表', route: '/report', icon: 'report.svg'),
|
||||||
|
WorkBenchModel(
|
||||||
|
title: '报价计算', route: '/sale_quotation', icon: 'sale_quotation.svg'),
|
||||||
|
];
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
animationController.dispose();
|
animationController.dispose();
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/zt_bottomsheet_picker.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_bottomsheet_picker.dart';
|
||||||
|
|
||||||
class ModalUtil {
|
class ModalUtil {
|
||||||
static Future<bool> showWarningDialog(
|
static Future<bool> showWarningDialog(
|
||||||
|
@ -55,7 +55,7 @@ class ModalUtil {
|
||||||
showCupertinoModalPopup(
|
showCupertinoModalPopup(
|
||||||
context: Get.overlayContext!,
|
context: Get.overlayContext!,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ZtBottomSheetPicker(
|
return SkBottomSheetPicker(
|
||||||
title: title,
|
title: title,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
firstLevel: firstLevel,
|
firstLevel: firstLevel,
|
||||||
|
|
|
@ -5,14 +5,14 @@ import 'package:sk_base_mobile/util/logger_util.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class ZtBaseDatePicker extends StatelessWidget {
|
class SkBaseDatePicker extends StatelessWidget {
|
||||||
final Function(String)? onDateTimeChanged;
|
final Function(String)? onDateTimeChanged;
|
||||||
late final FixedExtentScrollController yearController;
|
late final FixedExtentScrollController yearController;
|
||||||
late final FixedExtentScrollController monthController;
|
late final FixedExtentScrollController monthController;
|
||||||
late final FixedExtentScrollController dayController;
|
late final FixedExtentScrollController dayController;
|
||||||
DateTime? initialDate = DateTime.now();
|
DateTime? initialDate = DateTime.now();
|
||||||
DateTime? endDate = DateTime.now();
|
DateTime? endDate = DateTime.now();
|
||||||
ZtBaseDatePicker(
|
SkBaseDatePicker(
|
||||||
{super.key, this.onDateTimeChanged, this.initialDate, this.endDate});
|
{super.key, this.onDateTimeChanged, this.initialDate, this.endDate});
|
||||||
|
|
||||||
@override
|
@override
|
|
@ -4,7 +4,7 @@ import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
class ZtBottomSheetPicker extends StatelessWidget {
|
class SkBottomSheetPicker extends StatelessWidget {
|
||||||
final Function? onChanged;
|
final Function? onChanged;
|
||||||
final FixedExtentScrollController firstLevelControlller =
|
final FixedExtentScrollController firstLevelControlller =
|
||||||
FixedExtentScrollController();
|
FixedExtentScrollController();
|
||||||
|
@ -18,7 +18,7 @@ class ZtBottomSheetPicker extends StatelessWidget {
|
||||||
final double? itemHeight;
|
final double? itemHeight;
|
||||||
final double? popupHeight;
|
final double? popupHeight;
|
||||||
final String title;
|
final String title;
|
||||||
ZtBottomSheetPicker(
|
SkBottomSheetPicker(
|
||||||
{super.key,
|
{super.key,
|
||||||
this.title = '请选择',
|
this.title = '请选择',
|
||||||
required this.onChanged,
|
required this.onChanged,
|
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
class ZtDatePicker extends StatelessWidget {
|
class SkDatePicker extends StatelessWidget {
|
||||||
final TextEditingController textController;
|
final TextEditingController textController;
|
||||||
final VoidCallback? onClear;
|
final VoidCallback? onClear;
|
||||||
final Function? onDateSelected;
|
final Function? onDateSelected;
|
||||||
final bool isRequired;
|
final bool isRequired;
|
||||||
final String labelText;
|
final String labelText;
|
||||||
|
|
||||||
const ZtDatePicker({
|
const SkDatePicker({
|
||||||
super.key,
|
super.key,
|
||||||
this.onClear,
|
this.onClear,
|
||||||
this.onDateSelected,
|
this.onDateSelected,
|
|
@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
class ZtNumberInput extends StatelessWidget {
|
class SkNumberInput extends StatelessWidget {
|
||||||
final TextEditingController textController;
|
final TextEditingController textController;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
final Function(String)? onChanged;
|
final Function(String)? onChanged;
|
||||||
|
@ -11,7 +11,7 @@ class ZtNumberInput extends StatelessWidget {
|
||||||
final bool isRequired;
|
final bool isRequired;
|
||||||
final String labelText;
|
final String labelText;
|
||||||
final String? hint;
|
final String? hint;
|
||||||
const ZtNumberInput(
|
const SkNumberInput(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.textController,
|
required this.textController,
|
||||||
this.onTap,
|
this.onTap,
|
|
@ -3,7 +3,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
class ZtSearchSelect<T> extends StatelessWidget {
|
class SkSearchSelect<T> extends StatelessWidget {
|
||||||
final TextEditingController textController;
|
final TextEditingController textController;
|
||||||
final Function? suggestionsCallback;
|
final Function? suggestionsCallback;
|
||||||
final void Function(T)? onSelected;
|
final void Function(T)? onSelected;
|
||||||
|
@ -13,7 +13,7 @@ class ZtSearchSelect<T> extends StatelessWidget {
|
||||||
final EdgeInsetsGeometry? contentPadding;
|
final EdgeInsetsGeometry? contentPadding;
|
||||||
final bool isRequired;
|
final bool isRequired;
|
||||||
final Widget Function(BuildContext, T) itemBuilder;
|
final Widget Function(BuildContext, T) itemBuilder;
|
||||||
const ZtSearchSelect(
|
const SkSearchSelect(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.textController,
|
required this.textController,
|
||||||
required this.itemBuilder,
|
required this.itemBuilder,
|
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
class ZtTextInput extends StatelessWidget {
|
class SkTextInput extends StatelessWidget {
|
||||||
final TextEditingController textController;
|
final TextEditingController textController;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
final bool isRequired;
|
final bool isRequired;
|
||||||
final String labelText;
|
final String labelText;
|
||||||
final String? hint;
|
final String? hint;
|
||||||
final bool isTextArea;
|
final bool isTextArea;
|
||||||
const ZtTextInput({
|
const SkTextInput({
|
||||||
super.key,
|
super.key,
|
||||||
required this.textController,
|
required this.textController,
|
||||||
this.onTap,
|
this.onTap,
|
|
@ -0,0 +1,14 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SkAppbar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
|
final String title;
|
||||||
|
const SkAppbar({super.key, required this.title});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AppBar(title: Text(title));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size get preferredSize => Size.fromHeight(kToolbarHeight);
|
||||||
|
}
|
64
pubspec.lock
|
@ -161,6 +161,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "1.0.6"
|
||||||
|
data_table_2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: data_table_2
|
||||||
|
sha256: e403de6d9a58dddf27700114b614ea8ea5aa8442d7fbdfbe8b3d11b0512e7a49
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.12"
|
||||||
date_format:
|
date_format:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -366,6 +374,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.0"
|
||||||
|
flutter_sticky_header:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_sticky_header
|
||||||
|
sha256: "017f398fbb45a589e01491861ca20eb6570a763fd9f3888165a978e11248c709"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.5"
|
||||||
|
flutter_svg:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_svg
|
||||||
|
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.10+1"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -592,6 +616,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.8.3"
|
||||||
|
path_parsing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_parsing
|
||||||
|
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -957,6 +989,38 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.3"
|
version: "4.3.3"
|
||||||
|
value_layout_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: value_layout_builder
|
||||||
|
sha256: "98202ec1807e94ac72725b7f0d15027afde513c55c69ff3f41bcfccb950831bc"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
|
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:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -61,6 +61,9 @@ dependencies:
|
||||||
image_gallery_saver: ^2.0.3
|
image_gallery_saver: ^2.0.3
|
||||||
flutter_staggered_grid_view: ^0.7.0
|
flutter_staggered_grid_view: ^0.7.0
|
||||||
flutter_native_splash: ^2.3.11
|
flutter_native_splash: ^2.3.11
|
||||||
|
flutter_svg: ^2.0.10+1
|
||||||
|
flutter_sticky_header: ^0.6.5
|
||||||
|
data_table_2: ^2.5.12
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|