Browse Source

dropdown widget

smf
daivph 4 years ago
parent
commit
260f9f691c
10 changed files with 494 additions and 79 deletions
  1. +2
    -2
      lib/custom_model/action_form/ActionUIField.dart
  2. +22
    -0
      lib/custom_model/action_form/CommonData.dart
  3. +13
    -3
      lib/data/repository/repository.dart
  4. +120
    -67
      lib/presentation/custom_widgets/dropdown_supply_widget.dart
  5. +10
    -7
      lib/presentation/screens/actions/sc_action.dart
  6. +22
    -0
      lib/presentation/screens/actions/state_management_helper/change_dropdown_controller.dart
  7. +52
    -0
      lib/presentation/screens/resources/bloc/bloc/common_data_bloc.dart
  8. +22
    -0
      lib/presentation/screens/resources/bloc/bloc/common_data_event.dart
  9. +25
    -0
      lib/presentation/screens/resources/bloc/bloc/common_data_state.dart
  10. +206
    -0
      lib/presentation/screens/resources/sc_common_data_helper.dart

+ 2
- 2
lib/custom_model/action_form/ActionUIField.dart View File

String tbActivityExtendTypeCondition; String tbActivityExtendTypeCondition;
String relationTable; String relationTable;
String foreignKey; String foreignKey;
int isGuidelineUsing;
int isMandatory;
bool isGuidelineUsing;
bool isMandatory;
String groupName; String groupName;


ActionUIField( ActionUIField(

+ 22
- 0
lib/custom_model/action_form/CommonData.dart View File

class CommonData {
String description;
int id;
String name;
bool isSelected;

CommonData({this.description, this.id, this.name, this.isSelected = false});

CommonData.fromJson(Map<String, dynamic> json) {
description = json['description'];
id = json['id'];
name = json['name'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['description'] = this.description;
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}

+ 13
- 3
lib/data/repository/repository.dart View File

import 'dart:convert';

import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:dio_http_cache/dio_http_cache.dart'; import 'package:dio_http_cache/dio_http_cache.dart';
import 'package:farm_tpf/custom_model/ActionType.dart'; import 'package:farm_tpf/custom_model/ActionType.dart';
import 'package:farm_tpf/custom_model/UpdateNoti.dart'; import 'package:farm_tpf/custom_model/UpdateNoti.dart';
import 'package:farm_tpf/custom_model/WaterType.dart'; import 'package:farm_tpf/custom_model/WaterType.dart';
import 'package:farm_tpf/custom_model/action_form/ActionUIForm.dart'; import 'package:farm_tpf/custom_model/action_form/ActionUIForm.dart';
import 'package:farm_tpf/custom_model/action_form/CommonData.dart';
import 'package:farm_tpf/custom_model/user.dart'; import 'package:farm_tpf/custom_model/user.dart';
import 'package:farm_tpf/custom_model/user_request.dart'; import 'package:farm_tpf/custom_model/user_request.dart';
import 'package:farm_tpf/data/api/dio_provider.dart'; import 'package:farm_tpf/data/api/dio_provider.dart';
import 'package:farm_tpf/data/api/rest_client.dart'; import 'package:farm_tpf/data/api/rest_client.dart';
import 'package:farm_tpf/models/PagedResult.dart'; import 'package:farm_tpf/models/PagedResult.dart';
import 'package:farm_tpf/models/index.dart';
import 'package:farm_tpf/utils/const_common.dart'; import 'package:farm_tpf/utils/const_common.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';


forceRefresh: true, maxAge: Duration(days: ConstCommon.kMaxAgeCache)); forceRefresh: true, maxAge: Duration(days: ConstCommon.kMaxAgeCache));
return client.getActionUIForm(idAction, op); return client.getActionUIForm(idAction, op);
} }

Future<List<CommonData>> getCommonData(
{String tableSupply, String condition}) async {
var url =
'${ConstCommon.baseUrl}/api/get-data-from-table-common?tableName=$tableSupply&condition=$condition';

final Response<List<dynamic>> _result = await dio.get(url);
var value = _result.data
.map((dynamic i) => CommonData.fromJson(i as Map<String, dynamic>))
.toList();
return value;
}
} }

+ 120
- 67
lib/presentation/custom_widgets/dropdown_supply_widget.dart View File

import 'package:farm_tpf/custom_model/action_form/CommonData.dart';
import 'package:farm_tpf/presentation/screens/actions/state_management_helper/change_dropdown_controller.dart';
import 'package:farm_tpf/presentation/screens/resources/sc_common_data_helper.dart';
import 'package:farm_tpf/utils/validators.dart'; import 'package:farm_tpf/utils/validators.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';


class DropdownSupplyWidget extends StatelessWidget {
class DropdownSupplyWidget extends StatefulWidget {
final String titleName;
final String condition; final String condition;
final String hint; final String hint;
final String value; final String value;
final Function onPressed;
final Function(CommonData) onPressed;
final String invalidMessage; final String invalidMessage;
final String tag;
final String tbSupply;
DropdownSupplyWidget( DropdownSupplyWidget(
{@required this.hint,
{this.titleName,
@required this.hint,
@required this.tag,
this.value, this.value,
@required this.condition, @required this.condition,
@required this.onPressed, @required this.onPressed,
this.invalidMessage});
this.invalidMessage,
@required this.tbSupply});

@override
_DropdownSupplyWidgetState createState() => _DropdownSupplyWidgetState();
}

class _DropdownSupplyWidgetState extends State<DropdownSupplyWidget> {
ChangeDropdownController controller;
@override
void initState() {
super.initState();
controller = Get.put(ChangeDropdownController(), tag: widget.tag);
}

@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: Validators.stringNotNullOrEmpty(invalidMessage) ? 85 : 65,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
hint ?? '',
style: TextStyle(
color: Validators.stringNotNullOrEmpty(invalidMessage)
? Colors.red
: Colors.black54,
fontSize: 13.0),
),
SizedBox(
return GetBuilder<ChangeDropdownController>(
tag: widget.tag,
builder: (data) {
return SizedBox(
width: double.infinity, width: double.infinity,
height: 44,
child: FlatButton(
padding: EdgeInsets.only(
top: 0.0, right: 0.0, bottom: 0.0, left: 0.0),
onPressed: onPressed,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
top: 0.0, right: 0.0, bottom: 10.5, left: 0.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0.5,
color: Validators.stringNotNullOrEmpty(
invalidMessage)
? Colors.red
: Colors.black54)),
),
child: Row(
children: [
Expanded(
child: Text(value ?? hint,
style: TextStyle(
fontSize: 16.0,
color: Colors.black45))),
Icon(
Icons.arrow_drop_down,
color: Colors.grey,
),
],
))
],
)),
),
Validators.stringNotNullOrEmpty(invalidMessage)
? Text(
invalidMessage ?? '',
height: Validators.stringNotNullOrEmpty(widget.invalidMessage)
? 85
: 65,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.hint ?? '',
style: TextStyle( style: TextStyle(
fontSize: 12.0,
color: Colors.red,
fontWeight: FontWeight.normal),
textAlign: TextAlign.left,
)
: SizedBox(),
],
),
);
color:
Validators.stringNotNullOrEmpty(widget.invalidMessage)
? Colors.red
: Colors.black54,
fontSize: 13.0),
),
SizedBox(
width: double.infinity,
height: 44,
child: FlatButton(
padding: EdgeInsets.only(
top: 0.0, right: 0.0, bottom: 0.0, left: 0.0),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(
builder: (_) => CommonDataHelperScreen(
titleName: widget.titleName ?? '',
tbSupply: widget.tbSupply ?? '',
condition: widget.condition ?? '',
selectedId: data?.selectedId ?? -1,
currentItems: [],
currentEditId: -1),
fullscreenDialog: false))
.then((value) {
if (value != null) {
var result = value as CommonData;
controller?.change(result);
widget.onPressed(result);
}
});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(
top: 0.0,
right: 0.0,
bottom: 10.5,
left: 0.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0.5,
color: Validators.stringNotNullOrEmpty(
widget.invalidMessage)
? Colors.red
: Colors.black54)),
),
child: Row(
children: [
Expanded(
child: Text(
data?.currentData?.name ??
widget.hint,
style: TextStyle(
fontSize: 16.0,
color: Colors.black))),
Icon(
Icons.arrow_drop_down,
color: Colors.grey,
),
],
))
],
)),
),
Validators.stringNotNullOrEmpty(widget.invalidMessage)
? Text(
widget.invalidMessage ?? '',
style: TextStyle(
fontSize: 12.0,
color: Colors.red,
fontWeight: FontWeight.normal),
textAlign: TextAlign.left,
)
: SizedBox(),
],
),
);
});
} }
} }

+ 10
- 7
lib/presentation/screens/actions/sc_action.dart View File

decoration: InputDecoration(labelText: field.description), decoration: InputDecoration(labelText: field.description),
controller: textFieldControllers[field.id.toString()], controller: textFieldControllers[field.id.toString()],
onSaved: (newValue) {}, onSaved: (newValue) {},
validator: field.isMandatory == 0
validator: field.isMandatory
? (String value) { ? (String value) {
return Validators.validateNotNullOrEmpty( return Validators.validateNotNullOrEmpty(
value, 'Vui lòng nhập ${field.description}'); value, 'Vui lòng nhập ${field.description}');
hintValue: field.description, hintValue: field.description,
textController: textFieldControllers[field.id.toString()], textController: textFieldControllers[field.id.toString()],
onSaved: (newValue) {}, onSaved: (newValue) {},
validator: field.isMandatory == 1
validator: field.isMandatory
? (String value) { ? (String value) {
return Validators.validNumberOrEmpty( return Validators.validNumberOrEmpty(
value, 'Vui lòng nhập ${field.description}'); value, 'Vui lòng nhập ${field.description}');
onSaved: (newValue) {}); onSaved: (newValue) {});
} else if (field.tbControlTypeName == 'dropdown') { } else if (field.tbControlTypeName == 'dropdown') {
return DropdownSupplyWidget( return DropdownSupplyWidget(
titleName: field.description ?? '',
tbSupply: field.tbActivityExtendTypeExternalTable ?? '',
tag: field.name,
value: field.description, value: field.description,
hint:
'${field.description} ${field.isMandatory == 1 ? '*' : ''}',
hint: '${field.description} ${field.isMandatory ? '*' : ''}',
condition: field.tbActivityExtendTypeCondition, condition: field.tbActivityExtendTypeCondition,
invalidMessage: '', invalidMessage: '',
onPressed: () {});
onPressed: (commonData) {
print(commonData.name);
});
} else if (field.tbControlTypeName == 'date') { } else if (field.tbControlTypeName == 'date') {
return FieldDateWidget( return FieldDateWidget(
value: field.description, value: field.description,
hint:
'${field.description} ${field.isMandatory == 1 ? '*' : ''}',
hint: '${field.description} ${field.isMandatory ? '*' : ''}',
invalidMessage: '', invalidMessage: '',
onPressed: () {}); onPressed: () {});
} else if (field.tbControlTypeName == 'radiobutton') { } else if (field.tbControlTypeName == 'radiobutton') {

+ 22
- 0
lib/presentation/screens/actions/state_management_helper/change_dropdown_controller.dart View File

import 'package:get/get_state_manager/get_state_manager.dart';
import 'package:farm_tpf/custom_model/action_form/CommonData.dart';

class ChangeDropdownController extends GetxController {
CommonData currentData;
int selectedId;
String selectedName;

void initValue() {
currentData = CommonData();
selectedId = -1;
selectedName = '';
update();
}

void change(CommonData data) {
currentData = data;
selectedId = data.id;
selectedName = data.name;
update();
}
}

+ 52
- 0
lib/presentation/screens/resources/bloc/bloc/common_data_bloc.dart View File

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:farm_tpf/custom_model/action_form/CommonData.dart';
import 'package:farm_tpf/data/repository/repository.dart';
import 'package:meta/meta.dart';

part 'common_data_event.dart';
part 'common_data_state.dart';

class CommonDataBloc extends Bloc<CommonDataEvent, CommonDataState> {
final Repository repository;
CommonDataBloc({@required this.repository}) : super(CommonDataInitial());

@override
Stream<CommonDataState> mapEventToState(
CommonDataEvent event,
) async* {
if (event is DataFetched) {
try {
final response = await repository.getCommonData(
tableSupply: event.tbSupply, condition: event.condition);
List<CommonData> commonDatas = response.map((data) {
if (data.id == event.selectedId) {
data.isSelected = true;
}
return data;
}).toList();

yield CommonDataSuccess(items: commonDatas);
} catch (_) {
yield CommonDataFailure();
}
} else if (event is OnRefresh) {
try {
final response = await repository.getCommonData(
tableSupply: event.tbSupply, condition: event.condition);
List<CommonData> commonDatas = response.map((data) {
if (data.id == event.selectedId) {
data.isSelected = true;
}
return data;
}).toList();

yield CommonDataSuccess(items: commonDatas);
} catch (_) {
yield CommonDataFailure();
}
}
}
}

+ 22
- 0
lib/presentation/screens/resources/bloc/bloc/common_data_event.dart View File

part of 'common_data_bloc.dart';

abstract class CommonDataEvent extends Equatable {
const CommonDataEvent();

@override
List<Object> get props => [];
}

class DataFetched extends CommonDataEvent {
final int selectedId;
final String tbSupply;
final String condition;
DataFetched({this.selectedId, this.tbSupply, this.condition});
}

class OnRefresh extends CommonDataEvent {
final int selectedId;
final String tbSupply;
final String condition;
OnRefresh({this.selectedId, this.tbSupply, this.condition});
}

+ 25
- 0
lib/presentation/screens/resources/bloc/bloc/common_data_state.dart View File

part of 'common_data_bloc.dart';

abstract class CommonDataState extends Equatable {
const CommonDataState();

@override
List<Object> get props => [];
}

class CommonDataInitial extends CommonDataState {}

class CommonDataFailure extends CommonDataState {}

class CommonDataSuccess<T> extends CommonDataState {
final List<T> items;

const CommonDataSuccess({this.items});

CommonDataSuccess copyWith({List<T> items}) {
return CommonDataSuccess(items: items ?? this.items);
}

@override
List<Object> get props => [items];
}

+ 206
- 0
lib/presentation/screens/resources/sc_common_data_helper.dart View File

import 'package:farm_tpf/custom_model/action_form/CommonData.dart';
import 'package:farm_tpf/data/repository/repository.dart';
import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart';
import 'package:farm_tpf/presentation/custom_widgets/bottom_loader.dart';
import 'package:farm_tpf/presentation/custom_widgets/loading_list_page.dart';
import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
import 'package:farm_tpf/presentation/screens/resources/bloc/bloc/common_data_bloc.dart';
import 'package:farm_tpf/utils/const_string.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get/get.dart';

class CommonDataHelperScreen extends StatefulWidget {
final String tbSupply;
final String condition;
final int selectedId;
final String titleName;
final List<CommonData> currentItems;
final int currentEditId;
CommonDataHelperScreen(
{@required this.tbSupply,
this.condition,
@required this.selectedId,
@required this.titleName,
@required this.currentItems,
@required this.currentEditId});
@override
_CommonDataHelperScreenState createState() => _CommonDataHelperScreenState();
}

class _CommonDataHelperScreenState extends State<CommonDataHelperScreen> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CommonDataBloc(repository: Repository())
..add(DataFetched(
tbSupply: widget.tbSupply,
condition: widget.condition,
selectedId: widget.selectedId)),
child: HoldInfinityWidget(
selectedId: widget.selectedId,
tbSupply: widget.tbSupply,
condition: widget.condition,
titleName: widget.titleName,
currentItems: widget.currentItems,
currentEditId: widget.currentEditId,
),
);
}
}

class HoldInfinityWidget extends StatelessWidget {
final int selectedId;
final String tbSupply;
final String condition;
final String titleName;
final List<CommonData> currentItems;
final int currentEditId;
HoldInfinityWidget(
{@required this.selectedId,
@required this.tbSupply,
this.condition,
@required this.titleName,
@required this.currentItems,
@required this.currentEditId});
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
key: _scaffoldKey,
appBar: AppBarWidget(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'$titleName',
style: TextStyle(fontWeight: FontWeight.w500, fontSize: 22),
),
),
Expanded(
child: InfinityView(
selectedId: selectedId,
tbsupply: tbSupply,
condition: condition,
currentItems: currentItems,
currentEditId: currentEditId,
))
],
));
}
}

class InfinityView extends StatefulWidget {
final int selectedId;
final String tbsupply;
final String condition;
final List<CommonData> currentItems;
final int currentEditId;
InfinityView(
{@required this.selectedId,
@required this.tbsupply,
this.condition,
@required this.currentItems,
@required this.currentEditId});
@override
_InfinityViewState createState() => _InfinityViewState();
}

class _InfinityViewState extends State<InfinityView> {
CommonDataBloc _commonDataBloc;

@override
void initState() {
_commonDataBloc = BlocProvider.of<CommonDataBloc>(context);
_commonDataBloc.add(DataFetched(
tbSupply: widget.tbsupply,
condition: widget.condition,
selectedId: widget.selectedId));
super.initState();
}

@override
Widget build(BuildContext context) {
return BlocBuilder<CommonDataBloc, CommonDataState>(
builder: (context, state) {
if (state is CommonDataFailure) {
return Center(child: Text(label_error_get_data));
}
if (state is CommonDataSuccess) {
if (state.items.isEmpty) {
return Center(child: Text(label_list_empty));
}
return RefreshIndicator(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return index >= state.items.length
? BottomLoader()
: ItemInfinityWidget(
item: state.items[index],
currentItems: widget.currentItems,
currentEditId: widget.currentEditId,
);
},
itemCount: state.items.length),
onRefresh: () async {
_commonDataBloc.add(OnRefresh(
tbSupply: widget.tbsupply,
condition: widget.condition,
selectedId: widget.selectedId));
});
}
return Center(
child: LoadingListPage(),
);
},
);
}

@override
void dispose() {
super.dispose();
}
}

class ItemInfinityWidget extends StatelessWidget {
final CommonData item;
final List<CommonData> currentItems;
final int currentEditId;

const ItemInfinityWidget(
{Key key,
@required this.item,
@required this.currentItems,
@required this.currentEditId})
: super(key: key);

@override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey, width: 0.35))),
child: RadioListTile(
title: Text(item.name.toString()),
value: item,
groupValue: item?.isSelected == true ? item : null,
onChanged: (CommonData value) {
var editedId = (currentEditId > 0) ? currentEditId : -1;
if (currentItems.map((e) => e.id).contains(item.id) &&
item.id != editedId) {
Utils.showSnackBarWarning(
message:
"Vật tư đã được thêm, vui lòng chọn vật tư khác");
} else {
//close nackbar if open
if (Get.isSnackbarOpen) Get.back();
Navigator.of(context).pop(value);
}
})),
onTap: () {});
}
}

Loading…
Cancel
Save