| @@ -23,6 +23,7 @@ import 'package:farm_tpf/presentation/screens/codes/models/activity_request.dart | |||
| import 'package:farm_tpf/presentation/screens/codes/models/activity_type.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_request.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | |||
| import 'package:farm_tpf/utils/const_common.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| @@ -365,4 +366,45 @@ class Repository { | |||
| onError(AppException.handleError(e)); | |||
| } | |||
| } | |||
| Future<Stamp> getStampDetail({required int id}) async { | |||
| try { | |||
| var url = '${ConstCommon.baseUrl}/api/tb-codes/$id'; | |||
| var res = await dio.get(url); | |||
| return Stamp.fromJson(res.data); | |||
| } catch (e) { | |||
| rethrow; | |||
| } | |||
| } | |||
| Future<StampTimeline> getStampTimeline({required int stampId}) async { | |||
| try { | |||
| var url = '${ConstCommon.baseUrl}/api/tb-codes-timeline/$stampId'; | |||
| var res = await dio.get(url); | |||
| return StampTimeline.fromJson(res.data); | |||
| } catch (e) { | |||
| rethrow; | |||
| } | |||
| } | |||
| Future<void> updateStampStatus( | |||
| Function(dynamic) onSuccess, | |||
| Function(String) onError, { | |||
| required int stampId, | |||
| required String status, | |||
| }) async { | |||
| try { | |||
| var url = '${ConstCommon.baseUrl}/api/tb-codes/update/$stampId/status/$status'; | |||
| await dio.put(url).then( | |||
| (value) { | |||
| onSuccess(value); | |||
| }, | |||
| ).catchError((e) { | |||
| onError(AppException.handleError(e)); | |||
| }); | |||
| } catch (e) { | |||
| onError(AppException.handleError(e)); | |||
| } | |||
| } | |||
| } | |||
| @@ -3,6 +3,7 @@ import 'dart:io'; | |||
| import 'package:farm_tpf/data/repository/repository.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/bloc/stamp_bloc.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/cubit/detail_stamp_cubit.dart'; | |||
| import 'package:firebase_core/firebase_core.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter/services.dart'; | |||
| @@ -45,6 +46,9 @@ Future<void> main() async { | |||
| Repository(), | |||
| ), | |||
| ), | |||
| BlocProvider( | |||
| create: (_) => DetailStampCubit(), | |||
| ), | |||
| ], | |||
| child: App( | |||
| authenticationRepository: AuthenticationRepository(), | |||
| @@ -16,14 +16,14 @@ class StampFailure extends StampState { | |||
| StampFailure({required this.errorString}); | |||
| } | |||
| class StampSuccess<T> extends StampState { | |||
| final List<T>? items; | |||
| class StampSuccess<Stamp> extends StampState { | |||
| final List<Stamp>? items; | |||
| final int? page; | |||
| final bool? hasReachedMax; | |||
| const StampSuccess({this.items, this.page, this.hasReachedMax}); | |||
| StampSuccess copyWith({List<T>? items, int? page, bool? hasReachedMax}) { | |||
| StampSuccess copyWith({List<Stamp>? items, int? page, bool? hasReachedMax}) { | |||
| return StampSuccess( | |||
| items: items ?? this.items, | |||
| page: page ?? this.page, | |||
| @@ -1,29 +1,49 @@ | |||
| import 'package:farm_tpf/presentation/custom_widgets/app_bar_widget.dart'; | |||
| import 'package:farm_tpf/presentation/custom_widgets/button/second_button.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/cubit/detail_stamp_cubit.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/update_activity_page.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/widgets/item_code_timeline.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| import 'package:get/get.dart'; | |||
| import 'package:farm_tpf/utils/formatter.dart'; | |||
| import '../../../themes/styles_text.dart'; | |||
| import '../../custom_widgets/loading_list_page.dart'; | |||
| class CodeDetailPage extends StatefulWidget { | |||
| const CodeDetailPage({super.key}); | |||
| final int stampId; | |||
| final String stampCode; | |||
| const CodeDetailPage({ | |||
| super.key, | |||
| required this.stampId, | |||
| required this.stampCode, | |||
| }); | |||
| @override | |||
| State<CodeDetailPage> createState() => _CodeDetailPageState(); | |||
| } | |||
| class _CodeDetailPageState extends State<CodeDetailPage> { | |||
| var bloc = DetailStampCubit(); | |||
| @override | |||
| void initState() { | |||
| super.initState(); | |||
| bloc.preparedData(widget.stampId); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| appBar: AppBarWidget( | |||
| action: IconButton( | |||
| onPressed: () { | |||
| Get.to(() => UpdateActivityPage( | |||
| stampCode: 'AC_494D9D90', | |||
| )); | |||
| // Get.to( | |||
| // () => UpdateActivityPage( | |||
| // stampCode: widget.stampCode, | |||
| // ), | |||
| // ); | |||
| }, | |||
| icon: Icon( | |||
| Icons.edit, | |||
| @@ -36,39 +56,54 @@ class _CodeDetailPageState extends State<CodeDetailPage> { | |||
| child: Column( | |||
| children: [ | |||
| Expanded( | |||
| child: SingleChildScrollView( | |||
| child: Column( | |||
| children: [ | |||
| _itemCodeDetail( | |||
| title: 'Tên sản phẩm', | |||
| detail: 'Cà rốt', | |||
| titleStyle: StylesText.body4, | |||
| detailStyle: StylesText.body4.copyWith( | |||
| color: Colors.blue, | |||
| ), | |||
| child: BlocBuilder<DetailStampCubit, DetailStampState>( | |||
| bloc: bloc, | |||
| builder: (context, state) { | |||
| if (state is DetailStampLoading) { | |||
| return Center( | |||
| child: LoadingListPage(), | |||
| ); | |||
| } else if (state is DetailStampFailure) { | |||
| return Center(child: Text(state.errorMessage)); | |||
| } else if (state is DetailStampSuccessful) { | |||
| var stamp = state.stamp; | |||
| return SingleChildScrollView( | |||
| child: Column( | |||
| children: [ | |||
| _itemCodeDetail( | |||
| title: 'Tên sản phẩm', | |||
| detail: 'Cà rốt', | |||
| titleStyle: StylesText.body4, | |||
| detailStyle: StylesText.body4.copyWith( | |||
| color: Colors.blue, | |||
| ), | |||
| ), | |||
| _itemCodeDetail(title: 'Mô tả', detail: stamp.description ?? ''), | |||
| _itemCodeDetail(title: 'Số lượng tem', detail: stamp.quantity?.formatNumtoStringDecimal().toString() ?? ''), | |||
| _itemCodeDetail(title: 'Trạng thái', detail: stamp.status ?? ''), | |||
| _itemCodeDetail(title: 'Hạn sử dụng', detail: stamp.expiredDate?.format_DDMMYY().toString() ?? ''), | |||
| _itemCodeDetail(title: 'Mẫu tem', detail: stamp.stampType?.exampleStampName ?? ''), | |||
| const SizedBox( | |||
| height: 8, | |||
| ), | |||
| Text( | |||
| 'Timeline hoạt động', | |||
| style: StylesText.body1, | |||
| ), | |||
| const SizedBox( | |||
| height: 8, | |||
| ), | |||
| _timelineWidget(state.timeline), | |||
| ], | |||
| ), | |||
| _itemCodeDetail(title: 'Mô tả', detail: 'detail'), | |||
| _itemCodeDetail(title: 'Số lượng tem', detail: 'detail'), | |||
| _itemCodeDetail(title: 'Trạng thái', detail: 'detail'), | |||
| _itemCodeDetail(title: 'Hạn sử dụng', detail: 'detail'), | |||
| _itemCodeDetail(title: 'Mẫu tem', detail: 'detail'), | |||
| Text( | |||
| 'Timeline hoạt động', | |||
| style: StylesText.body1, | |||
| ), | |||
| _timelineWidget(), | |||
| ], | |||
| ), | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| return const SizedBox.shrink(); | |||
| }, | |||
| )), | |||
| const SizedBox( | |||
| height: 8, | |||
| ), | |||
| // Container( | |||
| // width: 100, | |||
| // height: 100, | |||
| // color: Colors.red, | |||
| // ), | |||
| _actionButtonWidget(), | |||
| ], | |||
| ), | |||
| @@ -76,14 +111,16 @@ class _CodeDetailPageState extends State<CodeDetailPage> { | |||
| ); | |||
| } | |||
| Widget _timelineWidget() { | |||
| Widget _timelineWidget(StampTimeline timeline) { | |||
| if ((timeline.content?.length ?? 0) == 0) return const SizedBox.shrink(); | |||
| return ListView.builder( | |||
| itemBuilder: (context, index) { | |||
| return ItemCodeTimeline( | |||
| item: timeline.content![index], | |||
| onPressed: () {}, | |||
| ); | |||
| }, | |||
| itemCount: 20, | |||
| itemCount: timeline.content?.length ?? 0, | |||
| physics: NeverScrollableScrollPhysics(), | |||
| shrinkWrap: true, | |||
| ); | |||
| @@ -97,7 +134,12 @@ class _CodeDetailPageState extends State<CodeDetailPage> { | |||
| children: [ | |||
| Expanded( | |||
| child: SecondButton( | |||
| onPressed: () {}, | |||
| onPressed: () { | |||
| bloc.updateStampStatus( | |||
| stampId: widget.stampId, | |||
| status: 'ACTIVE', | |||
| ); | |||
| }, | |||
| title: 'Kích hoạt toàn bộ', | |||
| borderColor: Colors.blue, | |||
| textColor: Colors.blue, | |||
| @@ -107,7 +149,12 @@ class _CodeDetailPageState extends State<CodeDetailPage> { | |||
| ), | |||
| Expanded( | |||
| child: SecondButton( | |||
| onPressed: () {}, | |||
| onPressed: () { | |||
| bloc.updateStampStatus( | |||
| stampId: widget.stampId, | |||
| status: 'CANCELED', | |||
| ); | |||
| }, | |||
| title: 'Huỷ toàn bộ', | |||
| borderColor: Colors.red, | |||
| textColor: Colors.white, | |||
| @@ -125,7 +172,17 @@ class _CodeDetailPageState extends State<CodeDetailPage> { | |||
| children: [ | |||
| Expanded( | |||
| child: SecondButton( | |||
| onPressed: () {}, | |||
| onPressed: () { | |||
| Get.to( | |||
| () => UpdateActivityPage( | |||
| stampCode: widget.stampCode, | |||
| ), | |||
| )?.then((value) { | |||
| if (value != null) { | |||
| bloc.preparedData(widget.stampId); | |||
| } | |||
| }); | |||
| }, | |||
| title: 'Cập nhật hoạt động', | |||
| borderColor: Colors.green, | |||
| textColor: Colors.green, | |||
| @@ -145,7 +145,12 @@ class _CodePageState extends State<CodePage> { | |||
| : ItemCode( | |||
| item: state.items?[index], | |||
| onPressed: () { | |||
| Get.to(() => CodeDetailPage()); | |||
| Get.to( | |||
| () => CodeDetailPage( | |||
| stampId: state.items?[index].id, | |||
| stampCode: state.items?[index].code, | |||
| ), | |||
| ); | |||
| }, | |||
| ); | |||
| }, | |||
| @@ -1,67 +0,0 @@ | |||
| import 'package:bloc/bloc.dart'; | |||
| import 'package:equatable/equatable.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import '../../../../data/api/app_exception.dart'; | |||
| import '../../../../data/repository/repository.dart'; | |||
| import '../../../../models/item_dropdown.dart'; | |||
| part 'code_update_timeline_state.dart'; | |||
| class CodeUpdateTimelineCubit extends Cubit<CodeUpdateTimelineState> { | |||
| CodeUpdateTimelineCubit() : super(CodeUpdateTimelineInitial()); | |||
| final repository = Repository(); | |||
| final formKey = GlobalKey<FormState>(); | |||
| var actionDate = ValueNotifier(DateTime.now()); | |||
| final descriptionCtl = TextEditingController(); | |||
| var actionTypes = [ | |||
| ItemDropDown(key: 'hoat dong 1', value: 'hoat dong 1'), | |||
| ItemDropDown(key: 'hoat dong 2', value: 'hoat dong 2'), | |||
| ]; | |||
| var selectedActionType = ValueNotifier(''); | |||
| // var existedCodeUpdateTimeline = UpdateCodeUpdateTimeline(); | |||
| void dispose() { | |||
| descriptionCtl.dispose(); | |||
| } | |||
| Future<void> preparedData() async { | |||
| try { | |||
| await Future.delayed(const Duration(seconds: 0)); | |||
| emit(CodeUpdateTimelineLoading()); | |||
| emit(CodeUpdateTimelinePrepareDataSuccessful()); | |||
| } catch (e) { | |||
| emit(CodeUpdateTimelineFailure(AppException.handleError(e))); | |||
| } | |||
| } | |||
| Future<void> onSubmit() async { | |||
| if (formKey.currentState!.validate()) { | |||
| // var gioiTinh = gioiTinhs.firstWhere( | |||
| // (element) => selectedGioiTinh.value == element.key, | |||
| // orElse: () => ItemDropDown(), | |||
| // ); | |||
| // existedCodeUpdateTimeline | |||
| // ..gioiTinhBe = gioiTinh.value | |||
| // ..ghiChu = noteCtl.text | |||
| // ..ngayTiemUngKhiThan = ungKhiThanDate.value.convertLocalDateTimeToServer(); | |||
| // UtilWidget.showLoading(); | |||
| // await repository.updateCodeUpdateTimeline( | |||
| // (success) { | |||
| // UtilWidget.hideDialog(); | |||
| // UtilWidget.showToastSuccess('Thêm thành công'); | |||
| // Get.back(); | |||
| // }, | |||
| // (errorMessage) { | |||
| // UtilWidget.hideDialog(); | |||
| // UtilWidget.showToastError(errorMessage); | |||
| // }, | |||
| // item: existedCodeUpdateTimeline, | |||
| // ); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| part of 'code_update_timeline_cubit.dart'; | |||
| abstract class CodeUpdateTimelineState extends Equatable { | |||
| const CodeUpdateTimelineState(); | |||
| @override | |||
| List<Object> get props => []; | |||
| } | |||
| class CodeUpdateTimelineInitial extends CodeUpdateTimelineState {} | |||
| class CodeUpdateTimelineLoading extends CodeUpdateTimelineState {} | |||
| class CodeUpdateTimelineFailure extends CodeUpdateTimelineState { | |||
| final String errorMessage; | |||
| CodeUpdateTimelineFailure(this.errorMessage); | |||
| } | |||
| class CodeUpdateTimelinePrepareDataSuccessful extends CodeUpdateTimelineState { | |||
| CodeUpdateTimelinePrepareDataSuccessful(); | |||
| } | |||
| @@ -0,0 +1,54 @@ | |||
| import 'package:bloc/bloc.dart'; | |||
| import 'package:equatable/equatable.dart'; | |||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_timeline.dart'; | |||
| import '../../../../data/api/app_exception.dart'; | |||
| import '../../../../data/repository/repository.dart'; | |||
| import '../../../../utils/utils.dart'; | |||
| import '../../../custom_widgets/widget_utils.dart'; | |||
| import '../models/stamp.dart'; | |||
| part 'detail_stamp_state.dart'; | |||
| class DetailStampCubit extends Cubit<DetailStampState> { | |||
| final repository = Repository(); | |||
| DetailStampCubit() : super(DetailStampInitial()); | |||
| Future<void> preparedData(int stampId) async { | |||
| try { | |||
| await Future.delayed(const Duration(seconds: 0)); | |||
| emit(DetailStampLoading()); | |||
| var stamp = await repository.getStampDetail(id: stampId); | |||
| var timeline = await repository.getStampTimeline(stampId: stampId); | |||
| // stampTypeRaws = await repository.stampTypes(); | |||
| // stampTypes.value = stampTypeRaws | |||
| // .map( | |||
| // (e) => ItemDropDown(key: e.id?.toString(), value: e.exampleStampName), | |||
| // ) | |||
| // .toList(); | |||
| emit(DetailStampSuccessful(stamp, timeline)); | |||
| } catch (e) { | |||
| emit(DetailStampFailure(AppException.handleError(e))); | |||
| } | |||
| } | |||
| Future<void> updateStampStatus({ | |||
| required int stampId, | |||
| required String status, | |||
| }) async { | |||
| UtilWidget.showLoading(); | |||
| await repository.updateStampStatus( | |||
| (success) { | |||
| UtilWidget.hideDialog(); | |||
| Utils.showSnackBarSuccess(); | |||
| preparedData(stampId); | |||
| }, | |||
| (errorMessage) { | |||
| UtilWidget.hideDialog(); | |||
| Utils.showSnackBarError(); | |||
| }, | |||
| stampId: stampId, | |||
| status: status, | |||
| ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| part of 'detail_stamp_cubit.dart'; | |||
| abstract class DetailStampState extends Equatable { | |||
| const DetailStampState(); | |||
| @override | |||
| List<Object> get props => []; | |||
| } | |||
| class DetailStampInitial extends DetailStampState {} | |||
| class DetailStampLoading extends DetailStampState {} | |||
| class DetailStampFailure extends DetailStampState { | |||
| final String errorMessage; | |||
| DetailStampFailure(this.errorMessage); | |||
| } | |||
| class DetailStampSuccessful extends DetailStampState { | |||
| final Stamp stamp; | |||
| final StampTimeline timeline; | |||
| DetailStampSuccessful(this.stamp, this.timeline); | |||
| } | |||
| @@ -1,3 +1,5 @@ | |||
| import 'package:farm_tpf/presentation/screens/codes/models/stamp_type.dart'; | |||
| import '../../../../custom_model/TbCropDTO.dart'; | |||
| class Stamp { | |||
| @@ -10,6 +12,7 @@ class Stamp { | |||
| String? status; | |||
| String? expiredDate; | |||
| String? createdDate; | |||
| StampType? stampType; | |||
| Stamp({ | |||
| this.id, | |||
| @@ -21,6 +24,7 @@ class Stamp { | |||
| this.status, | |||
| this.expiredDate, | |||
| this.createdDate, | |||
| this.stampType, | |||
| }); | |||
| Stamp.fromJson(Map<String, dynamic> json) { | |||
| @@ -33,6 +37,7 @@ class Stamp { | |||
| status = json['status']; | |||
| expiredDate = json['expiredDate']; | |||
| createdDate = json['createdDate']; | |||
| stampType = json['tbExampleStamp'] != null ? new StampType.fromJson(json['tbExampleStamp']) : null; | |||
| } | |||
| Map<String, dynamic> toJson() { | |||
| @@ -48,6 +53,9 @@ class Stamp { | |||
| data['status'] = this.status; | |||
| data['expiredDate'] = this.expiredDate; | |||
| data['createdDate'] = this.createdDate; | |||
| if (this.stampType != null) { | |||
| data['tbExampleStamp'] = this.stampType?.toJson(); | |||
| } | |||
| return data; | |||
| } | |||
| } | |||
| @@ -0,0 +1,87 @@ | |||
| class StampTimeline { | |||
| List<ContentTimeline>? content; | |||
| StampTimeline({this.content}); | |||
| StampTimeline.fromJson(Map<String, dynamic> json) { | |||
| if (json['content'] != null) { | |||
| content = <ContentTimeline>[]; | |||
| json['content'].forEach((v) { | |||
| content?.add(new ContentTimeline.fromJson(v)); | |||
| }); | |||
| } | |||
| } | |||
| Map<String, dynamic> toJson() { | |||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
| if (this.content != null) { | |||
| data['content'] = this.content?.map((v) => v.toJson()).toList(); | |||
| } | |||
| return data; | |||
| } | |||
| } | |||
| class ContentTimeline { | |||
| int? id; | |||
| int? ageDay; | |||
| int? cropId; | |||
| String? executeDate; | |||
| String? description; | |||
| String? createdDate; | |||
| int? createdById; | |||
| String? createdByName; | |||
| int? activityTypeId; | |||
| String? activityTypeName; | |||
| String? activityTypeDescription; | |||
| String? codeId; | |||
| bool? afterHarvest; | |||
| ContentTimeline( | |||
| {this.id, | |||
| this.ageDay, | |||
| this.cropId, | |||
| this.executeDate, | |||
| this.description, | |||
| this.createdDate, | |||
| this.createdById, | |||
| this.createdByName, | |||
| this.activityTypeId, | |||
| this.activityTypeName, | |||
| this.activityTypeDescription, | |||
| this.codeId, | |||
| this.afterHarvest}); | |||
| ContentTimeline.fromJson(Map<String, dynamic> json) { | |||
| id = json['id']; | |||
| ageDay = json['ageDay']; | |||
| cropId = json['cropId']; | |||
| executeDate = json['executeDate']; | |||
| description = json['description']; | |||
| createdDate = json['createdDate']; | |||
| createdById = json['createdById']; | |||
| createdByName = json['createdByName']; | |||
| activityTypeId = json['activityTypeId']; | |||
| activityTypeName = json['activityTypeName']; | |||
| activityTypeDescription = json['activityTypeDescription']; | |||
| codeId = json['codeId']; | |||
| afterHarvest = json['afterHarvest']; | |||
| } | |||
| Map<String, dynamic> toJson() { | |||
| final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
| data['id'] = this.id; | |||
| data['ageDay'] = this.ageDay; | |||
| data['cropId'] = this.cropId; | |||
| data['executeDate'] = this.executeDate; | |||
| data['description'] = this.description; | |||
| data['createdDate'] = this.createdDate; | |||
| data['createdById'] = this.createdById; | |||
| data['createdByName'] = this.createdByName; | |||
| data['activityTypeId'] = this.activityTypeId; | |||
| data['activityTypeName'] = this.activityTypeName; | |||
| data['activityTypeDescription'] = this.activityTypeDescription; | |||
| data['codeId'] = this.codeId; | |||
| data['afterHarvest'] = this.afterHarvest; | |||
| return data; | |||
| } | |||
| } | |||
| @@ -1,13 +1,17 @@ | |||
| import 'package:farm_tpf/utils/formatter.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import '../../../../themes/app_colors.dart'; | |||
| import '../../../../themes/styles_text.dart'; | |||
| import '../models/stamp_timeline.dart'; | |||
| class ItemCodeTimeline extends StatelessWidget { | |||
| final Function onPressed; | |||
| final ContentTimeline item; | |||
| const ItemCodeTimeline({ | |||
| super.key, | |||
| required this.onPressed, | |||
| required this.item, | |||
| }); | |||
| @override | |||
| @@ -73,11 +77,11 @@ class ItemCodeTimeline extends StatelessWidget { | |||
| mainAxisAlignment: MainAxisAlignment.start, | |||
| children: [ | |||
| Text( | |||
| 'ss - ', | |||
| '${item.activityTypeDescription ?? ''} - ', | |||
| style: StylesText.body5, | |||
| ), | |||
| Text( | |||
| '20/22/2202', | |||
| '${item.executeDate?.format_DDMMYY()}', | |||
| style: StylesText.caption3.copyWith(), | |||
| ) | |||
| ], | |||
| @@ -86,9 +90,9 @@ class ItemCodeTimeline extends StatelessWidget { | |||
| height: 8, | |||
| ), | |||
| _widgetItemInfoCompleted( | |||
| title: 'title', | |||
| actionDate: '2/2/2023', | |||
| nguoiThucHiens: 'nguoi thuc hien', | |||
| title: 'Mô tả', | |||
| actionDate: item.description ?? '', | |||
| location: 'dsfsdfsd f sdf dsf sd fds ', | |||
| ), | |||
| ], | |||
| ), | |||
| @@ -98,7 +102,7 @@ class ItemCodeTimeline extends StatelessWidget { | |||
| Widget _widgetItemInfoCompleted({ | |||
| required String title, | |||
| required String actionDate, | |||
| String? nguoiThucHiens, | |||
| String? location, | |||
| }) { | |||
| return Container( | |||
| padding: const EdgeInsets.all(8), | |||
| @@ -108,6 +112,7 @@ class ItemCodeTimeline extends StatelessWidget { | |||
| ), | |||
| child: Column( | |||
| mainAxisAlignment: MainAxisAlignment.start, | |||
| crossAxisAlignment: CrossAxisAlignment.start, | |||
| children: [ | |||
| Row( | |||
| children: [ | |||
| @@ -129,23 +134,11 @@ class ItemCodeTimeline extends StatelessWidget { | |||
| ), | |||
| Padding( | |||
| padding: const EdgeInsets.symmetric(vertical: 8.0), | |||
| child: Row( | |||
| children: [ | |||
| Expanded( | |||
| child: Text( | |||
| 'Người thực hiện', | |||
| style: StylesText.caption2.copyWith( | |||
| color: AppColors.neutral1, | |||
| ), | |||
| ), | |||
| ), | |||
| Text( | |||
| nguoiThucHiens ?? '', | |||
| style: StylesText.caption3.copyWith( | |||
| color: AppColors.neutral1, | |||
| ), | |||
| ), | |||
| ], | |||
| child: Text( | |||
| location ?? '', | |||
| style: StylesText.caption3.copyWith( | |||
| color: AppColors.neutral1, | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||