Skip to content

Commit

Permalink
Merge pull request #1829 from kwgong/upgrade/occuspace-api
Browse files Browse the repository at this point in the history
Upgrade/occuspace api
  • Loading branch information
c3bryant authored Sep 19, 2022
2 parents 345b538 + 7f98bfa commit 0e5764d
Show file tree
Hide file tree
Showing 11 changed files with 345 additions and 172 deletions.
2 changes: 2 additions & 0 deletions lib/app_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class RoutePaths {
static const String ParkingLotsView = "parking/parking_lots_view";
static const String NeighborhoodsView = "parking/neighborhoods_view";
static const String NeighborhoodsLotsView = "parking/neighborhoods_lot_view";
static const String AvailabilityDetailedView = "availability/detailed_view";
}

class RouteTitles {
Expand Down Expand Up @@ -70,6 +71,7 @@ class RouteTitles {
'dining/dining_list_view': 'Dining',
'dining/dining_detail_view': 'Dining',
'dining/dining_nutrition_view': 'Dining',
'availability/detailed_view': 'Availability'
};
}

Expand Down
8 changes: 8 additions & 0 deletions lib/app_router.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import 'package:campus_mobile_experimental/app_constants.dart';
import 'package:campus_mobile_experimental/core/models/availability.dart';
import 'package:campus_mobile_experimental/core/models/dining.dart';
import 'package:campus_mobile_experimental/core/models/dining_menu.dart';
import 'package:campus_mobile_experimental/core/models/events.dart';
import 'package:campus_mobile_experimental/core/models/news.dart';
import 'package:campus_mobile_experimental/ui/availability/manage_availability_view.dart';
import 'package:campus_mobile_experimental/ui/availability/availability_detail_view.dart';
import 'package:campus_mobile_experimental/ui/classes/classes_list.dart';
import 'package:campus_mobile_experimental/ui/dining/dining_detail_view.dart';
import 'package:campus_mobile_experimental/ui/dining/dining_list.dart';
Expand Down Expand Up @@ -99,6 +101,12 @@ class Router {
Provider.of<CustomAppBar>(_).changeTitle(settings.name);
return ManageAvailabilityView();
});
case RoutePaths.AvailabilityDetailedView:
SubLocations subLocation = settings.arguments as SubLocations;
return MaterialPageRoute(builder: (_) {
Provider.of<CustomAppBar>(_).changeTitle(settings.name);
return AvailabilityDetailedView(subLocation: subLocation);
});
case RoutePaths.DiningViewAll:
return MaterialPageRoute(builder: (_) {
Provider.of<CustomAppBar>(_).changeTitle(settings.name);
Expand Down
145 changes: 113 additions & 32 deletions lib/core/models/availability.dart
Original file line number Diff line number Diff line change
@@ -1,48 +1,129 @@
// To parse this JSON data, do
//
// final availabilityStatus = availabilityStatusFromJson(jsonString);

import 'dart:convert';

List<AvailabilityModel> availabilityModelFromJson(String str) {
var jsonStr = json.decode(str)['data']['children'];
return List<AvailabilityModel>.from(
jsonStr.map((x) => AvailabilityModel.fromJson(x)));
AvailabilityStatus availabilityStatusFromJson(String str) =>
AvailabilityStatus.fromJson(json.decode(str));

String availabilityStatusToJson(AvailabilityStatus data) =>
json.encode(data.toJson());

class AvailabilityStatus {
AvailabilityStatus({
this.status,
this.data,
this.timestamp,
});

String? status;
List<AvailabilityModel>? data;
DateTime? timestamp;

factory AvailabilityStatus.fromJson(Map<String, dynamic> json) =>
AvailabilityStatus(
status: json["status"] == null ? null : json["status"],
data: json["data"] == null
? null
: List<AvailabilityModel>.from(
json["data"].map((x) => AvailabilityModel.fromJson(x))),
timestamp: json["timestamp"] == null
? null
: DateTime.parse(json["timestamp"]),
);

Map<String, dynamic> toJson() => {
"status": status == null ? null : status,
"data": data == null
? null
: List<dynamic>.from(data!.map((x) => x.toJson())),
"timestamp": timestamp == null ? null : timestamp!.toIso8601String(),
};
}

class AvailabilityModel {
int? locationId;
bool? isOpen;
bool? isError;
double? percent;
String? locationName;
List<AvailabilityModel>? subLocations;

AvailabilityModel(
{this.locationId,
this.isOpen,
this.isError,
this.percent,
this.locationName,
this.subLocations});
AvailabilityModel({
this.id,
this.name,
this.subLocations,
});

int? id;
String? name;
List<SubLocations>? subLocations;

factory AvailabilityModel.fromJson(Map<String, dynamic> json) =>
AvailabilityModel(
locationId: json["id"] == null ? null : json["id"],
isOpen: json["isOpen"] == null ? null : json["isOpen"],
isError: json["isError"] == null ? null : json["isError"],
locationName: json["name"] == null ? null : json["name"],
percent: json["percent"] == null ? null : json["percent"].toDouble(),
subLocations: json["children"] == null
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
subLocations: json["childCounts"] == null
? null
: List<AvailabilityModel>.from(
json["children"].map((x) => AvailabilityModel.fromJson(x))),
: List<SubLocations>.from(
json["childCounts"].map((x) => SubLocations.fromJson(x))),
);

Map<String, dynamic> toJson() => {
"locationId": locationId == null ? null : locationId,
"locationName": locationName == null ? null : locationName,
"isOpen": isOpen == null ? null : isOpen,
"isError": isError == null ? null : isError,
"percent": percent == null ? null : percent.toString(),
"children": subLocations == null
"id": id == null ? null : id,
"name": name == null ? null : name,
"childCounts": subLocations == null
? null
: List<dynamic>.from(subLocations!.map((x) => x.toJson())),
};
}

class SubLocations {
SubLocations(
{this.id, this.name, this.percentage, this.isActive, this.floors});

int? id;
String? name;
double? percentage;
bool? isActive;
List<Floor>? floors;

factory SubLocations.fromJson(Map<String, dynamic> json) => SubLocations(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
percentage:
json["percentage"] == null ? null : json["percentage"].toDouble(),
isActive: json["isActive"] == null ? null : json["isActive"],
floors: json["childCounts"] == null
? null
: List<Floor>.from(
json["childCounts"].map((x) => Floor.fromJson(x))));

Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"name": name == null ? null : name,
"percentage": percentage == null ? null : percentage,
"isActive": isActive == null ? null : isActive,
"floors": floors == null ? null : floors
};
}

class Floor {
Floor({this.id, this.name, this.count, this.percentage, this.isActive});

int? id;
String? name;
int? count;
double? percentage;
bool? isActive;

factory Floor.fromJson(Map<String, dynamic> json) => Floor(
id: json["id"] == null ? null : json["id"],
name: json["name"] == null ? null : json["name"],
count: json["count"] == null ? null : json["count"],
percentage:
json["percentage"] == null ? null : json["percentage"].toDouble(),
isActive: json["isActive"] == null ? null : json["isActive"],
);

Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"name": name == null ? null : name,
"percentage": percentage == null ? null : percentage,
"isActive": isActive == null ? null : isActive,
};
}
17 changes: 5 additions & 12 deletions lib/core/providers/availability.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:campus_mobile_experimental/app_constants.dart';
import 'package:campus_mobile_experimental/core/models/availability.dart';
import 'package:campus_mobile_experimental/core/providers/user.dart';
import 'package:campus_mobile_experimental/core/services/availability.dart';
Expand Down Expand Up @@ -45,20 +44,20 @@ class AvailabilityDataProvider extends ChangeNotifier {
if (await _availabilityService.fetchData()) {
/// setting the LocationViewState based on user data
for (AvailabilityModel model in _availabilityService.data!) {
newMapOfLots[model.locationName] = model;
newMapOfLots[model.name] = model;

/// if the user is logged out and has not put any preferences,
/// show all locations by default
if (_userDataProvider
.userProfileModel!.selectedOccuspaceLocations!.isEmpty) {
locationViewState[model.locationName] = true;
locationViewState[model.name] = true;
}

/// otherwise, LocationViewState should be true for all selectedOccuspaceLocations
else {
_locationViewState[model.locationName] = _userDataProvider
_locationViewState[model.name] = _userDataProvider
.userProfileModel!.selectedOccuspaceLocations!
.contains(model.locationName);
.contains(model.name);
}
}

Expand All @@ -70,12 +69,6 @@ class AvailabilityDataProvider extends ChangeNotifier {
_userDataProvider.userProfileModel!.selectedOccuspaceLocations);
_lastUpdated = DateTime.now();
} else {
if (_error != null &&
_error!.contains(ErrorConstants.invalidBearerToken)) {
if (await _availabilityService.getNewToken()) {
fetchAvailability();
}
}
_error = _availabilityService.error;
}
_isLoading = false;
Expand Down Expand Up @@ -164,7 +157,7 @@ class AvailabilityDataProvider extends ChangeNotifier {
List<String?> locationsToReturn = [];
for (AvailabilityModel model
in _availabilityModels as Iterable<AvailabilityModel>? ?? []) {
locationsToReturn.add(model.locationName);
locationsToReturn.add(model.name);
}
return locationsToReturn;
}
Expand Down
47 changes: 8 additions & 39 deletions lib/core/services/availability.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,63 +15,32 @@ class AvailabilityService {
List<AvailabilityModel>? get data => _data;

final NetworkHelper _networkHelper = NetworkHelper();
final Map<String, String> headers = {
"accept": "application/json",
};
final String endpoint =
"https://api-qa.ucsd.edu:8243/occuspace/v2.0/busyness";

Future<bool> fetchData() async {
_error = null;
_isLoading = true;
try {
/// fetch data
String _response =
await (_networkHelper.authorizedFetch(endpoint, headers));
String _response = await (_networkHelper.authorizedFetch(
"https://api-qa.ucsd.edu:8243/campusbusyness/v1/busyness", {
"Authorization":
"Basic djJlNEpYa0NJUHZ5akFWT0VRXzRqZmZUdDkwYTp2emNBZGFzZWpmaWZiUDc2VUJjNDNNVDExclVh"
}));

/// parse data
final data = availabilityModelFromJson(_response);
_isLoading = false;
final data = availabilityStatusFromJson(_response);

_data = data;
return true;
} catch (e) {
/// if the authorized fetch failed we know we have to refresh the
/// token for this service
if (e.toString().contains("401")) {
if (await getNewToken()) {
return await fetchData();
}
}
_error = e.toString();
_isLoading = false;
return false;
}
}

Future<bool> getNewToken() async {
final String tokenEndpoint = "https://api-qa.ucsd.edu:8243/token";
final Map<String, String> tokenHeaders = {
"content-type": 'application/x-www-form-urlencoded',
"Authorization":
"Basic djJlNEpYa0NJUHZ5akFWT0VRXzRqZmZUdDkwYTp2emNBZGFzZWpmaWZiUDc2VUJjNDNNVDExclVh"
};
try {
var response = await _networkHelper.authorizedPost(
tokenEndpoint, tokenHeaders, "grant_type=client_credentials");

headers["Authorization"] = "Bearer " + response["access_token"];

_data = data.data;
return true;
} catch (e) {
_error = e.toString();
_isLoading = false;
return false;
}
}

bool get isLoading => _isLoading;

String? get error => _error;

DateTime? get lastUpdated => _lastUpdated;
}
2 changes: 2 additions & 0 deletions lib/core/services/user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class UserProfileService {
final String _endpoint = 'https://api-qa.ucsd.edu:8243/mp-registration/1.0.0';

Future<bool> downloadUserProfile(Map<String, String> headers) async {
print("user headers:");
print(headers.toString());
_error = null;
_isLoading = true;
try {
Expand Down
34 changes: 29 additions & 5 deletions lib/ui/availability/availability_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:campus_mobile_experimental/app_constants.dart';
import 'package:campus_mobile_experimental/core/models/availability.dart';
import 'package:campus_mobile_experimental/core/providers/availability.dart';
import 'package:campus_mobile_experimental/core/providers/cards.dart';
import 'package:campus_mobile_experimental/ui/availability/availability_constants.dart';
import 'package:campus_mobile_experimental/ui/availability/availability_display.dart';
import 'package:campus_mobile_experimental/ui/common/card_container.dart';
import 'package:campus_mobile_experimental/ui/common/dots_indicator.dart';
Expand Down Expand Up @@ -43,16 +44,39 @@ class _AvailabilityCardState extends State<AvailabilityCard> {

Widget buildAvailabilityCard(List<AvailabilityModel?> data) {
List<Widget> locationsList = [];

// loop through all the models, adding each one to locationsList
for (AvailabilityModel? model in data) {
if (model != null) {
if (_availabilityDataProvider.locationViewState[model.locationName]!) {
locationsList.add(AvailabilityDisplay(
model: model,
));
if (_availabilityDataProvider.locationViewState[model.name]!) {
locationsList.add(AvailabilityDisplay(model: model));
}
}
}

// the user chose no location, so instead show "No Location to Display"
if (locationsList.length == 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Container(
child: Text(
"No Location to Display",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: LOCATION_FONT_SIZE,
),
),
padding: EdgeInsets.only(
bottom: TITLE_BOTTOM_PADDING,
),
),
Text("Add Locations via 'Manage Locations'"),
],
);
}

return Column(
children: <Widget>[
Flexible(
Expand Down Expand Up @@ -91,4 +115,4 @@ class _AvailabilityCardState extends State<AvailabilityCard> {
));
return actionButtons;
}
}
}
Loading

0 comments on commit 0e5764d

Please sign in to comment.