Skip to content

Commit

Permalink
Show all buses in bottom sheet edit mode (0.3.0)
Browse files Browse the repository at this point in the history
This commit allows the user to see all
buses going to a bus stop, so as to allow
them to pin/unpin them even when they are
not in service.

It also introduces several bug fixes and
code refactoring as outlined below.

Also:
- Fixes alignment problems with long bus
  stop names
- Resets bus stops names upon unfavoriting them
- Syncs the bus stop star state properly
  between the list tile and bottom sheet in
  the search page
- Fixes padding for bus services with letters
- Improves bottom sheet opening animations'
  realism by using Rubber's launchTo method
  instead of animateTo
- Refactors BusAPI methods returning service
  numbers to return BusService objects
- Fix bottom sheet padding
  • Loading branch information
jeffsieu authored Nov 24, 2019
1 parent afcdd12 commit 8e311ee
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 238 deletions.
5 changes: 3 additions & 2 deletions lib/routes/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class StopsApp extends StatelessWidget {
brightness: Brightness.light,
textTheme: TextTheme(
display1: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, letterSpacing: 3, color: Colors.orangeAccent),
headline: TextStyle(fontWeight: FontWeight.w300, fontSize: 28.0),
headline: TextStyle(fontWeight: FontWeight.w300, fontSize: 28),
),
),
darkTheme: ThemeData(
Expand All @@ -39,7 +39,7 @@ class StopsApp extends StatelessWidget {
brightness: Brightness.dark,
textTheme: TextTheme(
display1: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, letterSpacing: 3, color: Colors.orangeAccent),
headline: TextStyle(fontWeight: FontWeight.w300, fontSize: 28.0),
headline: TextStyle(fontWeight: FontWeight.w300, fontSize: 28),
),
),
home: HomePage(),
Expand Down Expand Up @@ -89,6 +89,7 @@ class _HomePageState extends BottomSheetPageState<HomePage> {

return Scaffold(
body: bottomSheetContainer,
resizeToAvoidBottomInset: false,
);
}

Expand Down
1 change: 1 addition & 0 deletions lib/utils/bus_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class BusAPI {
static const int _kRefreshInterval = 30;

static const String kNoBusesError = 'No buses in service';
static const String kNoPinnedBusesError = 'No pinned buses in service';
static const String kNoInternetError = 'No internet connection';
static const String kLoadingMessage = 'Loading buses...';

Expand Down
13 changes: 13 additions & 0 deletions lib/utils/bus_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,17 @@ class BusService {
'operator': operator,
};
}

@override
bool operator ==(dynamic other) {
if (other.runtimeType != runtimeType)
return false;
final BusService otherBusService = other;
return number == otherBusService.number && operator == otherBusService.operator;
}

@override
int get hashCode {
return number.hashCode ^ operator.hashCode;
}
}
58 changes: 39 additions & 19 deletions lib/utils/database_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:sqflite/sqflite.dart';
import 'package:stops_sg/utils/bus_api.dart';
import 'package:stops_sg/utils/bus_route.dart';
import 'package:stops_sg/utils/bus_utils.dart';

import 'bus_service.dart';
import 'bus_stop.dart';

/* Called when bus stop name is changed */
typedef BusStopChangeListener = Function(BusStop busStop);
/* Called when bus stop is followed/un-followed */
/* Called when a bus stop is modified */
typedef BusStopChangeListener = void Function(BusStop busStop);
/* Called when bus is followed/un-followed */
typedef BusFollowStatusListener = void Function(String stop, String bus, bool isFollowed);
/* Called when bus service is pinned/unpinned for a bus stop*/
typedef BusPinStatusListener = void Function(String stop, String bus, bool isPinned);
Expand Down Expand Up @@ -101,14 +102,12 @@ Future<void> starBusStop(BusStop busStop) async {
whereArgs: <dynamic>[busStop.code],
);

if (_busStopListeners[busStop] != null)
for (BusStopChangeListener listener in _busStopListeners[busStop]) {
listener(busStop);
}
_updateBusStopListeners(busStop);
}

Future<void> unstarBusStop(BusStop busStop) async {
final Database database = await _accessDatabase();
busStop.displayName = busStop.defaultName;
final Map<String, dynamic> map = busStop.toMap();
map['starred'] = 0;
await database.update(
Expand All @@ -117,6 +116,8 @@ Future<void> unstarBusStop(BusStop busStop) async {
where: 'code = ?',
whereArgs: <dynamic>[busStop.code],
);

_updateBusStopListeners(busStop);
}

Future<bool> isBusStopStarred(BusStop busStop) async {
Expand All @@ -139,6 +140,13 @@ void unregisterBusStopListener(BusStop busStop, BusStopChangeListener listener)
}
}

void _updateBusStopListeners(BusStop busStop) {
if (_busStopListeners[busStop] != null)
for (BusStopChangeListener listener in _busStopListeners[busStop]) {
listener(busStop);
}
}

Future<void> followBus({@required String stop, @required String bus}) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('$_isBusFollowedKey$stop$bus', true);
Expand Down Expand Up @@ -257,12 +265,8 @@ Future<void> cacheBusStops(List<BusStop> busStops) async {
}
await batch.commit(noResult: true);

getCachedBusStops().then((List<BusStop> bs) {
assert(bs.length == busStops.length);
SharedPreferences.getInstance().then((SharedPreferences prefs) {
prefs.setBool(_areBusStopsCachedKey, true);
});
});
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool(_areBusStopsCachedKey, true);
}

void _cacheBusStop(BusStop busStop, Batch batch) {
Expand Down Expand Up @@ -420,13 +424,29 @@ Future<bool> isBusServicePinned(BusStop busStop, BusService busService) async {
return result.isNotEmpty;
}

Future<List<String>> getPinnedBusServiceNumbersIn(BusStop busStop) async {
Future<List<BusService>> getPinnedServicesIn(BusStop busStop) async {
final Database database = await _accessDatabase();
final List<Map<String, dynamic>> result = await database.query(
'pinned_bus_service',
where: 'busStopCode = ?',
whereArgs: <String>[busStop.code],
final List<Map<String, dynamic>> result = await database.rawQuery(
'SELECT * FROM pinned_bus_service INNER JOIN bus_service '
'ON pinned_bus_service.busServiceNumber = bus_service.number '
'WHERE pinned_bus_service.busStopCode = ?',
<String>[busStop.code],
);

final List<BusService> services = result.map(BusService.fromMap).toList(growable: false);
services.sort((BusService a, BusService b) => compareBusNumber(a.number, b.number));
return services;
}

Future<List<BusService>> getServicesIn(BusStop busStop) async {
final Database database = await _accessDatabase();
final List<Map<String, dynamic>> result = await database.rawQuery(
'SELECT * FROM (SELECT DISTINCT(serviceNumber) FROM bus_route WHERE busStopCode = ?) INNER JOIN bus_service '
'ON serviceNumber = bus_service.number',
<String>[busStop.code],
);

return result.map((Map<String, dynamic> json) => json['busServiceNumber'].toString()).toList(growable: false);
final List<BusService> services = result.map(BusService.fromMap).toList(growable: false);
services.sort((BusService a, BusService b) => compareBusNumber(a.number, b.number));
return services;
}
Loading

0 comments on commit 8e311ee

Please sign in to comment.