Update: 2026-07-12 05:49:17

This commit is contained in:
Hamza-Ayed
2026-07-12 05:49:17 +03:00
parent 24fb56f08f
commit 1f68cb7333
3 changed files with 129 additions and 104 deletions
@@ -22,25 +22,29 @@ class TransitHomePage extends StatelessWidget {
title: 'Mawasalati'.tr, title: 'Mawasalati'.tr,
isleading: true, isleading: true,
body: [ body: [
Expanded( Column(
child: RefreshIndicator( children: [
onRefresh: c.fetchMyEnrollments, Expanded(
child: c.isLoadingEnrollments child: RefreshIndicator(
? const Center(child: CircularProgressIndicator()) onRefresh: c.fetchMyEnrollments,
: c.myEnrollments.isEmpty child: c.isLoadingEnrollments
? _emptyState(c) ? const Center(child: CircularProgressIndicator())
: ListView( : c.myEnrollments.isEmpty
padding: const EdgeInsets.all(16), ? _emptyState(c)
children: [ : ListView(
Text('My Memberships'.tr, padding: const EdgeInsets.all(16),
style: AppStyle.headTitle2.copyWith(fontSize: 18)), children: [
const SizedBox(height: 12), Text('My Memberships'.tr,
...c.myEnrollments.map((e) => _enrollmentCard(e, c)), style: AppStyle.headTitle2.copyWith(fontSize: 18)),
const SizedBox(height: 20), const SizedBox(height: 12),
_addOrgTile(), ...c.myEnrollments.map((e) => _enrollmentCard(e, c)),
], const SizedBox(height: 20),
), _addOrgTile(),
), ],
),
),
),
],
), ),
], ],
), ),
@@ -22,7 +22,9 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Get.find<TransitController>().browseOrgs(); WidgetsBinding.instance.addPostFrameCallback((_) {
Get.find<TransitController>().browseOrgs();
});
} }
@override @override
@@ -32,59 +34,69 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
title: 'Choose your institution'.tr, title: 'Choose your institution'.tr,
isleading: true, isleading: true,
body: [ body: [
Padding( Column(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), children: [
child: TextField( Padding(
controller: _searchCtrl, padding:
onSubmitted: (v) => c.browseOrgs(search: v), const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: InputDecoration( child: TextField(
hintText: 'Search for a university or institution...'.tr, controller: _searchCtrl,
prefixIcon: const Icon(Icons.search), onSubmitted: (v) => c.browseOrgs(search: v),
filled: true, decoration: InputDecoration(
fillColor: AppColor.cardColor, hintText: 'Search for a university or institution...'.tr,
border: OutlineInputBorder( prefixIcon: const Icon(Icons.search),
borderRadius: BorderRadius.circular(12), filled: true,
borderSide: BorderSide(color: AppColor.borderColor), fillColor: AppColor.cardColor,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColor.borderColor),
),
),
), ),
), ),
), Expanded(
), child: c.isLoadingOrgs
Expanded( ? const Center(child: CircularProgressIndicator())
child: c.isLoadingOrgs : c.browsableOrgs.isEmpty
? const Center(child: CircularProgressIndicator()) ? Center(
: c.browsableOrgs.isEmpty child: Text('No results'.tr, style: AppStyle.title),
? Center( )
child: Text('No results'.tr, style: AppStyle.title), : ListView.builder(
) padding: const EdgeInsets.symmetric(horizontal: 16),
: ListView.builder( itemCount: c.browsableOrgs.length,
padding: const EdgeInsets.symmetric(horizontal: 16), itemBuilder: (_, i) {
itemCount: c.browsableOrgs.length, final org = c.browsableOrgs[i];
itemBuilder: (_, i) { return Card(
final org = c.browsableOrgs[i]; margin: const EdgeInsets.only(bottom: 10),
return Card( color: AppColor.cardColor,
margin: const EdgeInsets.only(bottom: 10), elevation: 0,
color: AppColor.cardColor, shape: RoundedRectangleBorder(
elevation: 0, borderRadius: BorderRadius.circular(14),
shape: RoundedRectangleBorder( side: BorderSide(color: AppColor.borderColor),
borderRadius: BorderRadius.circular(14), ),
side: BorderSide(color: AppColor.borderColor), child: ListTile(
), title:
child: ListTile( Text(org.nameAr, style: AppStyle.title),
title: Text(org.nameAr, style: AppStyle.title), subtitle:
subtitle: Text(org.city, style: AppStyle.subtitle), Text(org.city, style: AppStyle.subtitle),
trailing: const Icon(Icons.arrow_forward_ios, size: 16), trailing: const Icon(Icons.arrow_forward_ios,
onTap: () => _showActivateSheet(context, c, org), size: 16),
), onTap: () =>
); _showActivateSheet(context, c, org),
}, ),
), );
},
),
),
],
), ),
], ],
), ),
); );
} }
void _showActivateSheet(BuildContext context, TransitController c, TransitOrg org) { void _showActivateSheet(
BuildContext context, TransitController c, TransitOrg org) {
final idCtrl = TextEditingController(); final idCtrl = TextEditingController();
bool loading = false; bool loading = false;
@@ -107,7 +119,8 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(org.nameAr, style: AppStyle.headTitle2.copyWith(fontSize: 18)), Text(org.nameAr,
style: AppStyle.headTitle2.copyWith(fontSize: 18)),
const SizedBox(height: 6), const SizedBox(height: 6),
Text('Enter your student/employee ID to activate membership'.tr, Text('Enter your student/employee ID to activate membership'.tr,
style: AppStyle.subtitle), style: AppStyle.subtitle),
@@ -118,7 +131,8 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
hintText: 'Student ID'.tr, hintText: 'Student ID'.tr,
filled: true, filled: true,
fillColor: AppColor.secondaryColor, fillColor: AppColor.secondaryColor,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12)),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
@@ -128,7 +142,8 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
onPressed: () async { onPressed: () async {
if (idCtrl.text.trim().isEmpty) return; if (idCtrl.text.trim().isEmpty) return;
setState(() => loading = true); setState(() => loading = true);
final ok = await c.activateEnrollment(org.id, idCtrl.text.trim()); final ok =
await c.activateEnrollment(org.id, idCtrl.text.trim());
setState(() => loading = false); setState(() => loading = false);
if (ok && ctx.mounted) { if (ok && ctx.mounted) {
Navigator.pop(ctx); Navigator.pop(ctx);
@@ -21,7 +21,9 @@ class _TransitRoutesPageState extends State<TransitRoutesPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Get.find<TransitController>().openOrgRoutes(widget.orgId); WidgetsBinding.instance.addPostFrameCallback((_) {
Get.find<TransitController>().openOrgRoutes(widget.orgId);
});
} }
@override @override
@@ -31,41 +33,45 @@ class _TransitRoutesPageState extends State<TransitRoutesPage> {
title: widget.orgName, title: widget.orgName,
isleading: true, isleading: true,
body: [ body: [
Expanded( Column(
child: c.isLoadingRoutes children: [
? const Center(child: CircularProgressIndicator()) Expanded(
: c.currentOrgRoutes.isEmpty child: c.isLoadingRoutes
? Center( ? const Center(child: CircularProgressIndicator())
child: Text('No active routes currently'.tr, style: AppStyle.title), : c.currentOrgRoutes.isEmpty
) ? Center(
: ListView.builder( child: Text('No active routes currently'.tr, style: AppStyle.title),
padding: const EdgeInsets.all(16), )
itemCount: c.currentOrgRoutes.length, : ListView.builder(
itemBuilder: (_, i) { padding: const EdgeInsets.all(16),
final r = c.currentOrgRoutes[i]; itemCount: c.currentOrgRoutes.length,
return Card( itemBuilder: (_, i) {
margin: const EdgeInsets.only(bottom: 10), final r = c.currentOrgRoutes[i];
color: AppColor.cardColor, return Card(
elevation: 0, margin: const EdgeInsets.only(bottom: 10),
shape: RoundedRectangleBorder( color: AppColor.cardColor,
borderRadius: BorderRadius.circular(14), elevation: 0,
side: BorderSide(color: AppColor.borderColor), shape: RoundedRectangleBorder(
), borderRadius: BorderRadius.circular(14),
child: ListTile( side: BorderSide(color: AppColor.borderColor),
leading: CircleAvatar( ),
backgroundColor: AppColor.accentColor.withOpacity(0.15), child: ListTile(
child: Icon(Icons.directions_bus, color: AppColor.accentColor), leading: CircleAvatar(
), backgroundColor: AppColor.accentColor.withOpacity(0.15),
title: Text(r.nameAr, style: AppStyle.title), child: Icon(Icons.directions_bus, color: AppColor.accentColor),
subtitle: Text('${r.stopCount} ${'Stops'.tr}', style: AppStyle.subtitle), ),
trailing: const Icon(Icons.arrow_forward_ios, size: 16), title: Text(r.nameAr, style: AppStyle.title),
onTap: () => Get.to( subtitle: Text('${r.stopCount} ${'Stops'.tr}', style: AppStyle.subtitle),
() => TransitLiveMapPage(routeId: r.id, routeName: r.nameAr), trailing: const Icon(Icons.arrow_forward_ios, size: 16),
), onTap: () => Get.to(
), () => TransitLiveMapPage(routeId: r.id, routeName: r.nameAr),
); ),
}, ),
), );
},
),
),
],
), ),
], ],
), ),