added painter
This commit is contained in:
parent
0eead07f00
commit
b946ef0f59
Binary file not shown.
|
After Width: | Height: | Size: 774 B |
Binary file not shown.
|
After Width: | Height: | Size: 243 B |
|
|
@ -1,11 +1,17 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:another_stepper/another_stepper.dart';
|
||||||
|
import 'package:cargo/core/constants/colors.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
|
import '../../core/constants/assets.dart';
|
||||||
import '../../core/errors/failures.dart';
|
import '../../core/errors/failures.dart';
|
||||||
import '../../domain/entities/route/route.dart';
|
import '../../domain/entities/route/route.dart';
|
||||||
import '../../domain/usecases/order/get_routes_usecase.dart';
|
import '../../domain/usecases/order/get_routes_usecase.dart';
|
||||||
|
import '../../presentation/widgets/circle_painter.dart';
|
||||||
|
|
||||||
part 'order_detail_event.dart';
|
part 'order_detail_event.dart';
|
||||||
part 'order_detail_state.dart';
|
part 'order_detail_state.dart';
|
||||||
|
|
@ -23,7 +29,87 @@ class OrderDetailBloc extends Bloc<OrderDetailEvent, OrderDetailState> {
|
||||||
final result = await _getRoutesUseCase(event.cargoId);
|
final result = await _getRoutesUseCase(event.cargoId);
|
||||||
result.fold(
|
result.fold(
|
||||||
(failure) => emit(RoutesError(failure: failure)),
|
(failure) => emit(RoutesError(failure: failure)),
|
||||||
(response) => emit(RoutesLoaded(routes: response.routes)),
|
(response) {
|
||||||
|
// Find the index of the current route
|
||||||
|
int currentIndex = response.routes.indexWhere((r) => r.isCurrent);
|
||||||
|
|
||||||
|
emit(
|
||||||
|
RoutesLoaded(
|
||||||
|
routes: response.routes,
|
||||||
|
activeIndex: currentIndex,
|
||||||
|
steppers: response.routes.mapIndexed((index, route) {
|
||||||
|
// Determine if the icon should be splashed
|
||||||
|
final bool isSplashedIcon = index == 0 || index == response.routes.length - 1;
|
||||||
|
|
||||||
|
// Determine the color based on the conditions
|
||||||
|
Color textColor;
|
||||||
|
Color iconColor;
|
||||||
|
|
||||||
|
if (route.isCurrent) {
|
||||||
|
textColor = AppColors.greenDark;
|
||||||
|
iconColor = AppColors.greenDark;
|
||||||
|
} else if (index < currentIndex) {
|
||||||
|
textColor = const Color(0xFFD8D8DA);
|
||||||
|
iconColor = AppColors.greenDark;
|
||||||
|
} else {
|
||||||
|
textColor = AppColors.darkGrey;
|
||||||
|
iconColor = AppColors.darkGrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StepperData(
|
||||||
|
title: StepperText(
|
||||||
|
route.name,
|
||||||
|
textStyle: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: StepperText(
|
||||||
|
route.dateAt,
|
||||||
|
textStyle: TextStyle(
|
||||||
|
color: textColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
iconWidget: isSplashedIcon
|
||||||
|
? Image.asset(
|
||||||
|
AppAssets.circle,
|
||||||
|
color: iconColor,
|
||||||
|
)
|
||||||
|
: CirclePainterWidget(
|
||||||
|
radius: 8,
|
||||||
|
color: iconColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
/* RoutesLoaded(
|
||||||
|
routes: response.routes,
|
||||||
|
steppers: response.routes.mapIndexed((index, route) {
|
||||||
|
return StepperData(
|
||||||
|
title: StepperText(
|
||||||
|
route.name,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: StepperText(route.dateAt),
|
||||||
|
iconWidget: Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.green,
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(18),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
), */
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(RoutesError(failure: ExceptionFailure()));
|
emit(RoutesError(failure: ExceptionFailure()));
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,15 @@ class RoutesLoading extends OrderDetailState {}
|
||||||
|
|
||||||
class RoutesLoaded extends OrderDetailState {
|
class RoutesLoaded extends OrderDetailState {
|
||||||
final List<RouteEntity> routes;
|
final List<RouteEntity> routes;
|
||||||
const RoutesLoaded({required this.routes});
|
final List<StepperData> steppers;
|
||||||
|
final int activeIndex;
|
||||||
|
const RoutesLoaded({
|
||||||
|
required this.routes,
|
||||||
|
required this.steppers,
|
||||||
|
required this.activeIndex,
|
||||||
|
});
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [routes];
|
List<Object> get props => [routes, steppers, activeIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoutesError extends OrderDetailState {
|
class RoutesError extends OrderDetailState {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ sealed class AppAssets {
|
||||||
static const String boxesPng = 'assets/images/boxes.png';
|
static const String boxesPng = 'assets/images/boxes.png';
|
||||||
static const String trucksPng = 'assets/images/trucks.png';
|
static const String trucksPng = 'assets/images/trucks.png';
|
||||||
static const String header = 'assets/images/header.png';
|
static const String header = 'assets/images/header.png';
|
||||||
|
static const String circle = 'assets/images/circle.png';
|
||||||
|
static const String circle2 = 'assets/images/circle2.png';
|
||||||
static const String search = 'assets/images/search.png';
|
static const String search = 'assets/images/search.png';
|
||||||
static const String searchGif = 'assets/images/search.gif';
|
static const String searchGif = 'assets/images/search.gif';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ sealed class AppColors {
|
||||||
static const Color yellow = Color(0xFFFFC71E);
|
static const Color yellow = Color(0xFFFFC71E);
|
||||||
static const Color surface = Color(0xFFEDEEFC);
|
static const Color surface = Color(0xFFEDEEFC);
|
||||||
static const Color green = Color(0xFFA2E052);
|
static const Color green = Color(0xFFA2E052);
|
||||||
|
static const Color greenDark = Color(0xFF61971B);
|
||||||
static const Color grey = Color(0xFF96969C);
|
static const Color grey = Color(0xFF96969C);
|
||||||
static const Color darkGrey = Color(0xFF57575C);
|
static const Color darkGrey = Color(0xFF57575C);
|
||||||
static const Color lightGrey = Color(0xFFE5E5E6);
|
static const Color lightGrey = Color(0xFFE5E5E6);
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,15 @@ class _OrderDetailsScreenState extends State<OrderDetailsScreen> {
|
||||||
),
|
),
|
||||||
|
|
||||||
if (!_isFullScreen) ...[
|
if (!_isFullScreen) ...[
|
||||||
|
/// current location info
|
||||||
|
if (_showLocation)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: Space.all(1, 1),
|
||||||
|
child: LocationCard(cargoId: widget.order.cargoId),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
/// info text
|
/// info text
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
@ -116,29 +125,6 @@ class _OrderDetailsScreenState extends State<OrderDetailsScreen> {
|
||||||
|
|
||||||
/// info card
|
/// info card
|
||||||
InfoCard(order: widget.order),
|
InfoCard(order: widget.order),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
/// current location info
|
|
||||||
if (_showLocation)
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Padding(
|
|
||||||
padding: Space.all(1, 1),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'route'.tr(),
|
|
||||||
style: AppText.h2b,
|
|
||||||
),
|
|
||||||
|
|
||||||
/// gap
|
|
||||||
Space.y!,
|
|
||||||
|
|
||||||
/// location card
|
|
||||||
LocationCard(cargoId: widget.order.cargoId),
|
|
||||||
|
|
||||||
/// gap
|
/// gap
|
||||||
Space.y!,
|
Space.y!,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class CirclePainter extends CustomPainter {
|
||||||
|
final double radius;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
CirclePainter({required this.radius, required this.color});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
// Create a paint object with the specified color
|
||||||
|
final paint = Paint()
|
||||||
|
..color = color
|
||||||
|
..style = PaintingStyle.fill;
|
||||||
|
|
||||||
|
// Draw the circle in the center of the canvas
|
||||||
|
canvas.drawCircle(
|
||||||
|
Offset(size.width / 2, size.height / 2),
|
||||||
|
radius,
|
||||||
|
paint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CirclePainterWidget extends StatelessWidget {
|
||||||
|
final double radius;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
const CirclePainterWidget({super.key, required this.radius, required this.color});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CustomPaint(
|
||||||
|
painter: CirclePainter(radius: radius, color: color),
|
||||||
|
// Ensure the widget is large enough to fit the circle
|
||||||
|
size: Size(radius * 2, radius * 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
import 'package:another_stepper/another_stepper.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../application/application.dart';
|
import '../../application/application.dart';
|
||||||
import '../../configs/configs.dart';
|
import '../../configs/configs.dart';
|
||||||
import '../../core/core.dart';
|
import '../../core/core.dart';
|
||||||
import 'dashed_line.dart';
|
|
||||||
import 'retry_widget.dart';
|
import 'retry_widget.dart';
|
||||||
|
|
||||||
class LocationCard extends StatelessWidget {
|
class LocationCard extends StatelessWidget {
|
||||||
|
|
@ -16,69 +17,43 @@ class LocationCard extends StatelessWidget {
|
||||||
return BlocBuilder<OrderDetailBloc, OrderDetailState>(
|
return BlocBuilder<OrderDetailBloc, OrderDetailState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is RoutesLoading) {
|
if (state is RoutesLoading) {
|
||||||
return const Center(
|
return const SizedBox.shrink();
|
||||||
child: CircularProgressIndicator(),
|
// const Center(
|
||||||
);
|
// child: CircularProgressIndicator(),
|
||||||
|
// );
|
||||||
} else if (state is RoutesLoaded) {
|
} else if (state is RoutesLoaded) {
|
||||||
final routes = state.routes;
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'route'.tr(),
|
||||||
|
style: AppText.h2b,
|
||||||
|
),
|
||||||
|
|
||||||
return SizedBox(
|
/// gap
|
||||||
|
Space.y!,
|
||||||
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Card(
|
child: Card(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: ListView.separated(
|
child: AnotherStepper(
|
||||||
shrinkWrap: true,
|
stepperList: state.steppers,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
stepperDirection: Axis.vertical,
|
||||||
itemBuilder: (context, index) {
|
iconWidth: 30,
|
||||||
final route = routes[index];
|
iconHeight: 30,
|
||||||
return Row(
|
activeBarColor: AppColors.greenDark,
|
||||||
children: [
|
inActiveBarColor: AppColors.darkGrey,
|
||||||
route.isCurrent
|
inverted: false,
|
||||||
? const Icon(
|
verticalGap: 25,
|
||||||
Icons.radio_button_checked,
|
activeIndex: state.activeIndex,
|
||||||
color: AppColors.primary,
|
barThickness: 2.6,
|
||||||
)
|
|
||||||
: Container(
|
|
||||||
margin: Space.hf(0.35),
|
|
||||||
height: AppDimensions.normalize(4.5),
|
|
||||||
width: AppDimensions.normalize(4.5),
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: AppColors.grey,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Space.x!,
|
|
||||||
Text(
|
|
||||||
routes[index].name,
|
|
||||||
style: AppText.h3b,
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
Text(
|
|
||||||
routes[index].dateAt,
|
|
||||||
style: AppText.b1!.copyWith(color: AppColors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: routes.length,
|
|
||||||
separatorBuilder: (BuildContext context, int index) {
|
|
||||||
return Padding(
|
|
||||||
padding: Space.vf(0.5),
|
|
||||||
child: DashedLine(
|
|
||||||
height: 1,
|
|
||||||
width: AppDimensions.normalize(8),
|
|
||||||
color: AppColors.lightGrey,
|
|
||||||
strokeWidth: 1,
|
|
||||||
dashWidth: 5,
|
|
||||||
dashSpace: AppDimensions.normalize(2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
} else if (state is RoutesError) {
|
} else if (state is RoutesError) {
|
||||||
return Center(
|
return Center(
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ export 'successful_auth_dialog.dart';
|
||||||
export 'vertical_line.dart';
|
export 'vertical_line.dart';
|
||||||
export 'images.dart';
|
export 'images.dart';
|
||||||
export 'empty_order.dart';
|
export 'empty_order.dart';
|
||||||
|
export 'circle_painter.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
another_stepper:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: another_stepper
|
||||||
|
sha256: "04f5166c57f2412c612b17101e8a3d819f210c53f6bc1b5be541dc4c6987c681"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.2"
|
||||||
ansicolor:
|
ansicolor:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ dependencies:
|
||||||
# cached_network_image: ^3.4.1
|
# cached_network_image: ^3.4.1
|
||||||
flutter_native_splash: ^2.4.1
|
flutter_native_splash: ^2.4.1
|
||||||
url_launcher: ^6.3.0
|
url_launcher: ^6.3.0
|
||||||
|
another_stepper: ^1.2.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue