Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Easy Stepper Not Respecting Fixed Width and Exceeding Container Boundaries on Android #56

Open
gabrielMorais21 opened this issue Jan 6, 2025 · 0 comments

Comments

@gabrielMorais21
Copy link

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,
),
],
);
}
}
`

befcf64f-e94c-4809-9b71-9979958bdabe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant