first commit
This commit is contained in:
139
lib/views/Dashboard/home/accepted_pill.dart
Normal file
139
lib/views/Dashboard/home/accepted_pill.dart
Normal file
@@ -0,0 +1,139 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
import 'package:miler/views/helpers/constants/Colorconstants.dart';
|
||||
import 'package:miler/views/helpers/constants/design_constants.dart';
|
||||
import 'package:miler/views/helpers/constants/Font_constant.dart';
|
||||
import 'package:miler/widget/Bottom_page.dart';
|
||||
|
||||
/// ─────────────────────────────────────────────────────────────────────────
|
||||
/// ACCEPTED PILL — how many stops you have taken, and the way to them
|
||||
///
|
||||
/// Home is where the rider *decides*; Bookings is where he *works*. The bridge
|
||||
/// between the two used to be a "Continue trip" button sitting under the last
|
||||
/// hub row of a trip — which meant it only existed once that particular trip
|
||||
/// had nothing left to decide, it moved as the route grew, and it was below the
|
||||
/// fold on any route longer than about four stops. A rider who had accepted
|
||||
/// three stops and scrolled back to the top had nothing on screen telling him
|
||||
/// so, and no way through.
|
||||
///
|
||||
/// This says both things in one control, in one fixed place: **how many
|
||||
/// bookings he is holding**, and one tap to go work them. It is the counterpart
|
||||
/// to [SelectionBar] — that one is about the stops he is choosing, this one
|
||||
/// about the stops he has already taken — so they share the floating slot at
|
||||
/// the foot of the page and never appear together. A selection in progress is
|
||||
/// the more urgent of the two and wins the slot.
|
||||
///
|
||||
/// The count comes from the accepted store, which drops a booking once it is
|
||||
/// picked, so the number is "waiting for you on Bookings" rather than "accepted
|
||||
/// at some point today".
|
||||
/// ─────────────────────────────────────────────────────────────────────────
|
||||
class AcceptedPill extends StatelessWidget {
|
||||
/// Accepted bookings still waiting to be worked. Zero renders nothing.
|
||||
final int count;
|
||||
|
||||
/// Jumps to the Bookings tab.
|
||||
final VoidCallback onTap;
|
||||
|
||||
const AcceptedPill({super.key, required this.count, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (count <= 0) return const SizedBox.shrink();
|
||||
|
||||
final radius = BorderRadius.circular(DesignConstants.radiusFull);
|
||||
|
||||
// Rides the floating nav bar: it is `Positioned` outside the Scaffold's
|
||||
// body, so `SafeArea` knows nothing about it and anything pinned to the
|
||||
// bottom lands underneath. See [BottomPage.bottomInset].
|
||||
//
|
||||
// A fixed inset now. This used to follow a `navVisible` notifier up and
|
||||
// down, because the bar left the screen entirely on scroll. It compacts
|
||||
// instead of leaving, so there is no longer a state in which the room is
|
||||
// free — and chasing the 20pt difference re-laid this out every time the
|
||||
// rider changed scroll direction, for a gap he would never notice.
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: BottomPage.bottomInset(context) + 10.h),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Align(
|
||||
// Right-aligned and sized to its content: this is an ambient way
|
||||
// through, not the action the screen is for. A full-width green bar
|
||||
// here would out-rank the accept the rider is actually on Home to
|
||||
// make.
|
||||
alignment: Alignment.centerRight,
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: count == 1
|
||||
? '1 accepted booking. Go to Bookings.'
|
||||
: '$count accepted bookings. Go to Bookings.',
|
||||
child: Material(
|
||||
color: ColorConstants.primary,
|
||||
borderRadius: radius,
|
||||
elevation: 0,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: radius,
|
||||
child: Container(
|
||||
// 48 clears the Material touch-target floor without the pill
|
||||
// reading as a primary CTA.
|
||||
height: 48.h,
|
||||
padding: EdgeInsets.fromLTRB(8.w, 0, 14.w, 0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: radius,
|
||||
boxShadow: DesignConstants.shadowLg,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// The count as a badge, not as a word in a sentence: it
|
||||
// is the thing the rider is checking from across the
|
||||
// handlebars, and it changes while the words do not.
|
||||
Container(
|
||||
width: 32.w,
|
||||
height: 32.w,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: ColorConstants.pureSurface,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Text(
|
||||
'$count',
|
||||
style: TextStyle(
|
||||
fontSize: 15.sp,
|
||||
fontWeight: FontWeight.w800,
|
||||
height: 1,
|
||||
letterSpacing: -0.3,
|
||||
color: ColorConstants.primary,
|
||||
fontFamily: FontConstants.fontFamily,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 9.w),
|
||||
Text(
|
||||
count == 1 ? 'booking accepted' : 'bookings accepted',
|
||||
style: TextStyle(
|
||||
fontSize: 13.sp,
|
||||
fontWeight: FontWeight.w800,
|
||||
letterSpacing: -0.1,
|
||||
color: Colors.white,
|
||||
fontFamily: FontConstants.fontFamily,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 2.w),
|
||||
Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
size: 20.sp,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user