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(
|
||||
centerTitle: true,
|
||||
iconTheme: const IconThemeData(color: Colors.black),
|
||||
iconTheme: const IconThemeData(color: Colors.white),
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.white,
|
||||
|
|
|
@ -5,10 +5,10 @@ class GloablConfig {
|
|||
// static const BASE_URL = "http://10.0.2.2:8001/api/";
|
||||
// static const OSS_URL = "http://10.0.2.2:8001";
|
||||
|
||||
static const BASE_URL = "http://144.123.43.138:3001/api/";
|
||||
static const OSS_URL = "http://144.123.43.138:3001";
|
||||
// static const BASE_URL = "http://192.168.60.220:8001/api/";
|
||||
// static const OSS_URL = "http://192.168.60.220:8001";
|
||||
// static const BASE_URL = "http://144.123.43.138:3001/api/";
|
||||
// static const OSS_URL = "http://144.123.43.138:3001";
|
||||
static const BASE_URL = "http://192.168.60.220:8001/api/";
|
||||
static const OSS_URL = "http://192.168.60.220:8001";
|
||||
static const DOMAIN_NAME = "山矿通";
|
||||
static const DEBUG = true;
|
||||
static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:get/get.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/sale_quotation/sale_quotation.dart';
|
||||
|
||||
import '../screens/landing/landing.dart';
|
||||
import '../screens/mine/useinfo/userinfo.dart';
|
||||
|
@ -10,10 +11,13 @@ class RouteConfig {
|
|||
static const String login = '/login';
|
||||
static const String userinfo = '/userinfo';
|
||||
static const String inventory = '/inventory';
|
||||
static const String saleQuotation = '/sale_quotation';
|
||||
|
||||
static final List<GetPage> getPages = [
|
||||
GetPage(name: login, page: () => LoginScreen()),
|
||||
GetPage(name: home, page: () => LandingPage()),
|
||||
GetPage(name: userinfo, page: () => UserInfoPage()),
|
||||
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/store/auth.store.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 {
|
||||
CustomAppBar({super.key});
|
||||
|
@ -59,7 +59,7 @@ class CustomAppBar extends StatelessWidget {
|
|||
showCupertinoModalPopup(
|
||||
context: Get.overlayContext!,
|
||||
builder: (BuildContext context) {
|
||||
return ZtBaseDatePicker(
|
||||
return SkBaseDatePicker(
|
||||
initialDate: controller.endTime.value,
|
||||
endDate: controller.endTime.value,
|
||||
onDateTimeChanged: (date) {
|
||||
|
|
|
@ -14,6 +14,10 @@ class InvenotryInoutPage extends StatelessWidget {
|
|||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 工具栏的高度
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).padding.top,
|
||||
),
|
||||
UperBody(),
|
||||
const Expanded(
|
||||
child: TaskPageBody(),
|
||||
|
|
|
@ -16,21 +16,19 @@ class LandingPage extends StatelessWidget {
|
|||
return Material(
|
||||
child: Stack(children: [
|
||||
const BackColors(),
|
||||
SafeArea(
|
||||
bottom: false,
|
||||
child: Scaffold(
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.centerDocked,
|
||||
// floatingActionButton: [0].indexWhere(
|
||||
// (item) => item == controller.currentIndex.value) >
|
||||
// -1
|
||||
// ? FloatingCreateButton()
|
||||
// : null,
|
||||
floatingActionButton: FloatingCreateButton(),
|
||||
bottomNavigationBar: BottomNavBar(),
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Obx(() => controller.pages[controller.currentIndex.value]),
|
||||
))
|
||||
Scaffold(
|
||||
floatingActionButtonLocation:
|
||||
FloatingActionButtonLocation.centerDocked,
|
||||
// floatingActionButton: [0].indexWhere(
|
||||
// (item) => item == controller.currentIndex.value) >
|
||||
// -1
|
||||
// ? FloatingCreateButton()
|
||||
// : null,
|
||||
floatingActionButton: FloatingCreateButton(),
|
||||
bottomNavigationBar: BottomNavBar(),
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Obx(() => controller.pages[controller.currentIndex.value]),
|
||||
)
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ class InventorySearch extends StatelessWidget {
|
|||
// return Container(
|
||||
// width: ScreenAdaper.width(200),
|
||||
// constraints: BoxConstraints(minWidth: ScreenAdaper.width(200)),
|
||||
// child: ZtSearchSelect<ProjectModel>(
|
||||
// child: SkSearchSelect<ProjectModel>(
|
||||
// isRequired: true,
|
||||
// contentPadding:
|
||||
// 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/store/dict.store.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/zt_search_select.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/zk_date_picker.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/zt_text_input.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_number_input.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_search_select.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_date_picker.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/screens/new_inventory_inout/new_inventory_inout_controller.dart';
|
||||
|
||||
|
@ -180,7 +180,7 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 项目
|
||||
Widget buildProjectPicker() {
|
||||
return ZtSearchSelect<ProjectModel>(
|
||||
return SkSearchSelect<ProjectModel>(
|
||||
isRequired: true,
|
||||
textController: controller.projectTextController,
|
||||
labelText: '项目',
|
||||
|
@ -278,7 +278,7 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 时间
|
||||
Widget buildDatePicker() {
|
||||
return ZtDatePicker(
|
||||
return SkDatePicker(
|
||||
textController: controller.dateTextController,
|
||||
onClear: () {
|
||||
controller.payload.remove('time');
|
||||
|
@ -294,7 +294,7 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 数量
|
||||
Widget buildQuantity() {
|
||||
return ZtNumberInput(
|
||||
return SkNumberInput(
|
||||
textController: controller.quantityTextController,
|
||||
labelText: '数量',
|
||||
onChanged: (value) {
|
||||
|
@ -306,7 +306,7 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 单价
|
||||
Widget buildUnitPrice() {
|
||||
return ZtNumberInput(
|
||||
return SkNumberInput(
|
||||
textController: controller.unitPriceTextController,
|
||||
labelText: '单价',
|
||||
onChanged: (value) {
|
||||
|
@ -317,7 +317,7 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 金额
|
||||
Widget buildAmount() {
|
||||
return ZtNumberInput(
|
||||
return SkNumberInput(
|
||||
textController: controller.amountTextController,
|
||||
labelText: '金额',
|
||||
onChanged: (value) {
|
||||
|
@ -375,7 +375,7 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 备注
|
||||
Widget buildRemark() {
|
||||
return ZtTextInput(
|
||||
return SkTextInput(
|
||||
textController: controller.remarkTextController,
|
||||
labelText: '备注',
|
||||
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: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:sk_base_mobile/app_theme.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/snack_bar.util.dart';
|
||||
|
||||
class WorkBenchModel {
|
||||
final String title;
|
||||
final String route;
|
||||
WorkBenchModel({required this.title, required this.route});
|
||||
}
|
||||
|
||||
class WorkBenchPage extends StatelessWidget {
|
||||
WorkBenchPage({super.key});
|
||||
final List<WorkBenchModel> works = [
|
||||
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'),
|
||||
];
|
||||
final controller = Get.put(WorkBenchController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const SizedBox(),
|
||||
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);
|
||||
},
|
||||
appBar: AppBar(
|
||||
leading: const SizedBox(),
|
||||
title: const Text(
|
||||
'工作台',
|
||||
),
|
||||
)
|
||||
])),
|
||||
),
|
||||
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(
|
||||
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)
|
||||
],
|
||||
onTap: () {
|
||||
final route = RouteConfig.getPages
|
||||
.map((e) => e.name)
|
||||
.firstWhereOrNull((name) => name == controller.menus[index].route);
|
||||
if (route != null) {
|
||||
Get.toNamed(controller.menus[index].route);
|
||||
} else {
|
||||
SnackBarUtil().info('功能待开发。');
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.only(
|
||||
top: ScreenAdaper.height(20), bottom: ScreenAdaper.height(20)),
|
||||
child: Column(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/icons/${controller.menus[index].icon}',
|
||||
width: ScreenAdaper.width(100),
|
||||
height: ScreenAdaper.width(100),
|
||||
),
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)));
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(10),
|
||||
),
|
||||
Text(controller.menus[index].title)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
// 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:get/get.dart';
|
||||
import 'package:sk_base_mobile/models/workbench.model.dart';
|
||||
|
||||
class WorkBenchController extends GetxController {
|
||||
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
|
||||
void onClose() {
|
||||
animationController.dispose();
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.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 {
|
||||
static Future<bool> showWarningDialog(
|
||||
|
@ -55,7 +55,7 @@ class ModalUtil {
|
|||
showCupertinoModalPopup(
|
||||
context: Get.overlayContext!,
|
||||
builder: (BuildContext context) {
|
||||
return ZtBottomSheetPicker(
|
||||
return SkBottomSheetPicker(
|
||||
title: title,
|
||||
onChanged: onChanged,
|
||||
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';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ZtBaseDatePicker extends StatelessWidget {
|
||||
class SkBaseDatePicker extends StatelessWidget {
|
||||
final Function(String)? onDateTimeChanged;
|
||||
late final FixedExtentScrollController yearController;
|
||||
late final FixedExtentScrollController monthController;
|
||||
late final FixedExtentScrollController dayController;
|
||||
DateTime? initialDate = DateTime.now();
|
||||
DateTime? endDate = DateTime.now();
|
||||
ZtBaseDatePicker(
|
||||
SkBaseDatePicker(
|
||||
{super.key, this.onDateTimeChanged, this.initialDate, this.endDate});
|
||||
|
||||
@override
|
|
@ -4,7 +4,7 @@ import 'package:get/get.dart';
|
|||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
|
||||
class ZtBottomSheetPicker extends StatelessWidget {
|
||||
class SkBottomSheetPicker extends StatelessWidget {
|
||||
final Function? onChanged;
|
||||
final FixedExtentScrollController firstLevelControlller =
|
||||
FixedExtentScrollController();
|
||||
|
@ -18,7 +18,7 @@ class ZtBottomSheetPicker extends StatelessWidget {
|
|||
final double? itemHeight;
|
||||
final double? popupHeight;
|
||||
final String title;
|
||||
ZtBottomSheetPicker(
|
||||
SkBottomSheetPicker(
|
||||
{super.key,
|
||||
this.title = '请选择',
|
||||
required this.onChanged,
|
|
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
|||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
|
||||
class ZtDatePicker extends StatelessWidget {
|
||||
class SkDatePicker extends StatelessWidget {
|
||||
final TextEditingController textController;
|
||||
final VoidCallback? onClear;
|
||||
final Function? onDateSelected;
|
||||
final bool isRequired;
|
||||
final String labelText;
|
||||
|
||||
const ZtDatePicker({
|
||||
const SkDatePicker({
|
||||
super.key,
|
||||
this.onClear,
|
||||
this.onDateSelected,
|
|
@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
|
||||
class ZtNumberInput extends StatelessWidget {
|
||||
class SkNumberInput extends StatelessWidget {
|
||||
final TextEditingController textController;
|
||||
final VoidCallback? onTap;
|
||||
final Function(String)? onChanged;
|
||||
|
@ -11,7 +11,7 @@ class ZtNumberInput extends StatelessWidget {
|
|||
final bool isRequired;
|
||||
final String labelText;
|
||||
final String? hint;
|
||||
const ZtNumberInput(
|
||||
const SkNumberInput(
|
||||
{super.key,
|
||||
required this.textController,
|
||||
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/util/screen_adaper_util.dart';
|
||||
|
||||
class ZtSearchSelect<T> extends StatelessWidget {
|
||||
class SkSearchSelect<T> extends StatelessWidget {
|
||||
final TextEditingController textController;
|
||||
final Function? suggestionsCallback;
|
||||
final void Function(T)? onSelected;
|
||||
|
@ -13,7 +13,7 @@ class ZtSearchSelect<T> extends StatelessWidget {
|
|||
final EdgeInsetsGeometry? contentPadding;
|
||||
final bool isRequired;
|
||||
final Widget Function(BuildContext, T) itemBuilder;
|
||||
const ZtSearchSelect(
|
||||
const SkSearchSelect(
|
||||
{super.key,
|
||||
required this.textController,
|
||||
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/util/screen_adaper_util.dart';
|
||||
|
||||
class ZtTextInput extends StatelessWidget {
|
||||
class SkTextInput extends StatelessWidget {
|
||||
final TextEditingController textController;
|
||||
final VoidCallback? onTap;
|
||||
final bool isRequired;
|
||||
final String labelText;
|
||||
final String? hint;
|
||||
final bool isTextArea;
|
||||
const ZtTextInput({
|
||||
const SkTextInput({
|
||||
super.key,
|
||||
required this.textController,
|
||||
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"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -366,6 +374,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
@ -592,6 +616,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -957,6 +989,38 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -61,6 +61,9 @@ dependencies:
|
|||
image_gallery_saver: ^2.0.3
|
||||
flutter_staggered_grid_view: ^0.7.0
|
||||
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:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|