-
Notifications
You must be signed in to change notification settings - Fork 52
Description
Hello, how are you? I'm facing an issue on Android with the Easy Stepper component. In some cases, the text is exceeding the container's boundaries. I created a container with 16 padding, and all other elements are respecting this configuration. However, even when setting a fixed width for the Easy Stepper, it doesn't comply and ends up taking 100% of the screen width.
code: `import 'package:flutter/material.dart';
import 'package:micro_app_wagon_locator/app/wagon_home/domain/entities/tran_entity.dart';
import 'package:micro_app_wagon_locator/app/wagon_home/presentation/widget/timeLine.dart';
import 'package:shared_dependencies/shared_dependencies.dart';
// ignore: depend_on_referenced_packages
import 'package:intl/intl.dart';
class TrainModal extends StatelessWidget {
final PinType pinType;
final VoidCallback onPressedDetails;
final VoidCallback onPressedCancel;
final DraggableScrollableController draggableScrollableController;
final TrainEntity? trainEntity;
const TrainModal({
super.key,
required this.pinType,
required this.onPressedCancel,
required this.trainEntity,
required this.onPressedDetails,
required this.draggableScrollableController,
});
@OverRide
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: TrainContent(
pinType: pinType,
onPressedDetails: onPressedDetails,
onPressedCancel: onPressedCancel,
trainEntity: trainEntity,
),
),
],
);
}
}
class TrainContent extends StatelessWidget {
final PinType pinType;
final VoidCallback onPressedDetails;
final VoidCallback onPressedCancel;
final TrainEntity? trainEntity;
const TrainContent({
super.key,
required this.pinType,
required this.onPressedDetails,
required this.onPressedCancel,
required this.trainEntity,
});
@OverRide
Widget build(BuildContext context) {
return Container(
height: pinType == PinType.normal ? 541 : 659,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(24),
topLeft: Radius.circular(24),
),
color: DsColors.greyBlue25,
boxShadow: [
BoxShadow(
color: const Color(0xFF1D29394D).withOpacity(0.3),
offset: const Offset(-3, -4),
blurRadius: 24,
),
],
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 16),
const DragIndicator(),
if (pinType != PinType.normal)
AlertSection(pinType: pinType, trainEntity: trainEntity),
LocationInfo(trainEntity: trainEntity),
const SizedBox(height: 16),
LastUpdateInfo(trainEntity: trainEntity),
const SizedBox(height: 16),
TrainDetails(trainEntity: trainEntity),
const SizedBox(height: 12),
TrainAttributes(trainEntity: trainEntity),
TimelineWidget(trainEntity: trainEntity!),
const SizedBox(height: 16),
ActionButtons(
onPressedDetails: onPressedDetails,
onPressedCancel: onPressedCancel,
),
],
),
),
);
}
}
class DragIndicator extends StatelessWidget {
const DragIndicator({super.key});
@OverRide
Widget build(BuildContext context) {
return Center(
child: Container(
width: 36,
height: 5,
decoration: BoxDecoration(
color: const Color(0XFFBEBFC0),
borderRadius: BorderRadius.circular(4),
),
),
);
}
}
class AlertSection extends StatelessWidget {
final PinType pinType;
final TrainEntity? trainEntity;
const AlertSection({
super.key,
required this.pinType,
required this.trainEntity,
});
@OverRide
Widget build(BuildContext context) {
final alertColor = pinType == PinType.broken
? const Color(0XFFC01048)
: DsColors.warning400;
final alertIcon = pinType == PinType.broken
? DsIconSource.alertIcon.iconPath
: DsIconSource.alertTriangle.iconPath;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border(left: BorderSide(color: alertColor, width: 4)),
),
child: Column(
children: [
Row(
children: [
SvgPicture.asset(
'assets/images/$alertIcon',
package: 'core_design_system',
height: 12,
),
const SizedBox(width: 6),
Text(
pinType == PinType.broken
? trainEntity?.vehicleCondition ?? ''
: 'Ocorrência ferroviária',
style: const TextStyle(
fontFamily: 'Mission Gothic',
fontWeight: FontWeight.w600,
fontSize: 12,
color: DsColors.greyBlue800,
),
),
],
),
const SizedBox(height: 6),
Text(
pinType == PinType.occurrence
? trainEntity?.occurrence ?? 'Valor padrão'
: trainEntity?.vehicleConditionDetail ?? 'Valor padrão',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
fontSize: 12,
color: DsColors.greyBlue500,
),
),
],
),
),
);
}
}
class LocationInfo extends StatelessWidget {
final TrainEntity? trainEntity;
const LocationInfo({super.key, required this.trainEntity});
@OverRide
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Localização',
style: TextStyle(
fontFamily: 'Mission Gothic',
fontWeight: FontWeight.w600,
fontSize: 16,
color: DsColors.greyBlue900,
),
),
Container(
height: 22,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: DsColors.primary50,
borderRadius: BorderRadius.circular(16),
),
child: IntrinsicWidth(
child: Center(
child: Text(
trainEntity?.transportStageName ?? '',
textAlign: TextAlign.center,
style: const TextStyle(
color: Color(0xFF1849A9),
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
),
),
),
],
);
}
}
class LastUpdateInfo extends StatelessWidget {
final TrainEntity? trainEntity;
const LastUpdateInfo({super.key, required this.trainEntity});
@OverRide
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text(
'Última atualização realizada em:',
style: TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
fontStyle: FontStyle.italic,
fontSize: 9,
color: DsColors.greyBlue500,
),
),
Text(
trainEntity?.lastUpdateDate ?? "",
style: const TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
fontSize: 10,
color: DsColors.greyBlue700,
),
),
],
);
}
}
class TrainDetails extends StatelessWidget {
final TrainEntity? trainEntity;
const TrainDetails({super.key, required this.trainEntity});
@OverRide
Widget build(BuildContext context) {
return Row(
children: [
SvgPicture.asset(
'assets/images/${DsIconSource.train.iconPath}',
package: 'core_design_system',
height: 20,
),
const SizedBox(width: 4),
Text(
trainEntity?.locationName ?? "",
style: const TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w500,
fontSize: 14,
color: DsColors.primary800,
),
),
],
);
}
}
class TrainAttributes extends StatelessWidget {
final TrainEntity? trainEntity;
const TrainAttributes({super.key, required this.trainEntity});
String _obterTextoPrevisaoEntrega(TrainEntity? trainEntity) {
String dataString = trainEntity?.estimatedDestinationEntryDate ?? '';
if (trainEntity?.transportStageName == "Fila terminal" &&
dataString != '') {
DateFormat dateFormat = DateFormat('dd/MM/yyyy HH:mm');
DateTime dataConvertida = dateFormat.parse(dataString);
DateTime dataAtual = DateTime.now();
if (dataConvertida.isBefore(dataAtual)) {
return 'Vagão em fila para entrega';
}
}
return dataString;
}
@OverRide
Widget build(BuildContext context) {
final attributes = [
{'title': 'Cliente', 'subtitle': trainEntity?.clientName ?? ""},
{'title': 'Trem/Pátio', 'subtitle': trainEntity?.currentLocation ?? ""},
{
'title': 'Quantidade vagões',
'subtitle': trainEntity?.numberOfWagons.toString() ?? ""
},
{'title': 'Origem', 'subtitle': trainEntity?.origin ?? ""},
{'title': 'Destino', 'subtitle': trainEntity?.destination ?? ""},
{
'title': trainEntity?.transportStageName == 'Entregue'
? 'Hora da Entrega'
: 'Previsão chegada',
'subtitle': _obterTextoPrevisaoEntrega(trainEntity)
},
];
return GridView.count(
padding: EdgeInsets.zero,
crossAxisCount: 3,
shrinkWrap: true,
childAspectRatio: 3,
physics: const NeverScrollableScrollPhysics(),
children: attributes
.map((attr) =>
GridItem(title: attr['title']!, subtitle: attr['subtitle']!))
.toList(),
);
}
}
class ActionButtons extends StatelessWidget {
final VoidCallback onPressedDetails;
final VoidCallback onPressedCancel;
const ActionButtons({
super.key,
required this.onPressedDetails,
required this.onPressedCancel,
});
@OverRide
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: DsColors.primary600,
minimumSize: const Size(double.infinity, 40),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
),
onPressed: onPressedDetails,
child: const Text(
'Detalhar',
style: TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w700,
fontSize: 14.0,
color: Colors.white,
),
),
),
const SizedBox(height: 16),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
minimumSize: const Size(double.infinity, 40),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
side: const BorderSide(color: DsColors.greyBlue300),
),
),
onPressed: onPressedCancel,
child: const Text(
'Fechar',
style: TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w700,
fontSize: 14.0,
color: DsColors.greyBlue700,
),
),
),
],
);
}
}
class GridItem extends StatelessWidget {
final String title;
final String subtitle;
const GridItem({super.key, required this.title, required this.subtitle});
@OverRide
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w500,
fontSize: 10,
color: DsColors.greyBlue700,
),
),
Text(
subtitle,
style: const TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
fontSize: 12,
color: DsColors.greyBlue900,
),
),
],
);
}
}
`
`import 'package:easy_stepper/easy_stepper.dart';
import 'package:flutter/material.dart';
import 'package:micro_app_wagon_locator/app/wagon_home/domain/entities/tran_entity.dart';
import 'package:micro_app_wagon_locator/micro_app_wagon_locator.dart';
import 'package:shared_dependencies/shared_dependencies.dart' hide LineStyle;
// Widget principal da Timeline
class TimelineWidget extends StatelessWidget {
final TrainEntity trainEntity;
const TimelineWidget({Key? key, required this.trainEntity}) : super(key: key);
@OverRide
Widget build(BuildContext context) {
int activeStep = _determineActiveStep(trainEntity.transportStageName);
return EasyStepper(
lineStyle: const LineStyle(
lineSpace: 4,
lineLength: 110,
lineWidth: 20,
lineType: LineType.normal,
progress: 0.5,
defaultLineColor: DsColors.greyBlue300,
finishedLineColor: DsColors.primary700,
progressColor: DsColors.primary700,
),
activeStep: activeStep,
activeStepTextColor: Colors.black87,
finishedStepTextColor: Colors.black87,
internalPadding: 0,
showLoadingAnimation: false,
stepRadius: 8,
showStepBorder: false,
activeStepBorderType: BorderType.normal,
activeStepBackgroundColor: Colors.transparent,
finishedStepBorderType: BorderType.normal,
finishedStepBackgroundColor: Colors.transparent,
unreachedStepBorderType: BorderType.normal,
unreachedStepBackgroundColor: Colors.transparent,
steps: [
TimelineStep(
isActive: activeStep == 0,
checkStep: activeStep > 0,
title: trainEntity.originEntryDate ?? "",
subtitle: _formatSubTitle(
trainEntity.origin,
trainEntity.originCityName,
),
),
TimelineStep(
isActive: activeStep == 1,
checkStep: activeStep > 1,
title: trainEntity.currentLocationEntryDate ?? '',
subtitle: trainEntity.currentCityName ?? "",
),
TimelineStep(
isActive: activeStep == 2,
checkStep: activeStep >= 2,
title: trainEntity.estimatedDestinationEntryDate ?? "",
subtitle: _formatSubTitle(
trainEntity.destination,
trainEntity.destinationCityName,
),
transportStageName: trainEntity.transportStageName,
),
],
);
}
int _determineActiveStep(String? stageName) {
switch (stageName) {
case "Aguardando circulação":
return 0;
case "Circulando":
return 1;
case "Fila terminal":
case "Entregue":
return 2;
default:
return 0;
}
}
String _formatSubTitle(String? terminal, String? cidade) {
if (terminal != null && terminal.isNotEmpty) {
return terminal;
}
if (cidade != null && cidade.isNotEmpty) {
return cidade;
}
return '';
}
}
class TimelineStep extends EasyStep {
final bool isActive;
final bool checkStep;
final String title;
final String subtitle;
final String? transportStageName;
TimelineStep({
required this.isActive,
required this.checkStep,
required this.title,
required this.subtitle,
this.transportStageName,
}) : super(
customStep: transportStageName != null
? CheckStage(transportStageName: transportStageName!)
: CircleWidget(activeStep: isActive, checkStep: checkStep),
customTitle: StepText(
isActive: isActive,
title: title,
subtitle: subtitle,
),
);
}
class CheckStage extends StatelessWidget {
final String transportStageName;
const CheckStage({Key? key, required this.transportStageName})
: super(key: key);
@OverRide
Widget build(BuildContext context) {
if (transportStageName == "Entregue") {
return CircleWidget(activeStep: true, checkStep: true);
}
if (transportStageName == "Fila terminal") {
return CircleWidget(activeStep: false, checkStep: true);
}
return CircleWidget(activeStep: false, checkStep: false);
}
}
class CircleWidget extends StatelessWidget {
final bool activeStep;
final bool checkStep;
const CircleWidget(
{Key? key, required this.activeStep, required this.checkStep})
: super(key: key);
@OverRide
Widget build(BuildContext context) {
return Container(
width: activeStep ? 24 : 12,
height: activeStep ? 24 : 12,
decoration: BoxDecoration(
color: activeStep
? const Color(0xFF175CD3)
: (checkStep ? const Color(0xFF175CD3) : DsColors.greyBlue300),
shape: BoxShape.circle,
border: activeStep
? Border.all(
color: const Color(0xFF1849A9),
width: 2,
)
: Border.all(
color: Colors.white,
width: 2,
),
),
child: activeStep
? SvgPicture.asset(
'assets/leading_icon.svg',
package: MicroAppWagonlocator.microAppName,
colorFilter: const ColorFilter.mode(
Colors.white,
BlendMode.srcIn,
),
)
: null,
);
}
}
class StepText extends StatelessWidget {
final String title;
final String subtitle;
final bool isActive;
const StepText({
Key? key,
required this.title,
required this.subtitle,
required this.isActive,
}) : super(key: key);
@OverRide
Widget build(BuildContext context) {
return Column(
children: [
Text(
isActive ? 'Localização atual' : title,
style: TextStyle(
fontFamily: 'Roboto',
fontWeight: isActive ? FontWeight.w700 : FontWeight.w500,
fontSize: 10,
color: isActive ? const Color(0xFF1570EF) : const Color(0xFF667085),
),
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
Text(
subtitle,
style: TextStyle(
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
fontSize: 10,
color: isActive ? const Color(0xFF175CD3) : const Color(0xFF344054),
),
textAlign: TextAlign.center,
),
],
);
}
}
`
