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