added painter

This commit is contained in:
komekh 2024-08-30 16:07:22 +05:00
parent 0eead07f00
commit b946ef0f59
12 changed files with 205 additions and 95 deletions

BIN
assets/images/circle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

BIN
assets/images/circle2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

View File

@ -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()));

View File

@ -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 {

View File

@ -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';
} }

View File

@ -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);

View File

@ -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!,

View File

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

View File

@ -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(

View File

@ -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';

View File

@ -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:

View File

@ -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: