Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOC Integration #25

Closed
wants to merge 12 commits into from
4 changes: 2 additions & 2 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
# implicit-casts: false
# implicit-dynamic: false
errors:
# treat missing required parameters as a warning (not a hint)
missing_required_param: warning
Expand Down
14 changes: 13 additions & 1 deletion lib/app_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,22 @@ class RoutePaths {
static const String SearchView = 'search_view';
static const String CourseListView = 'course_list_view';
static const String Login = 'login';
static const String SearchDetail = 'search_detail';
}

class CalendarStyles {
static const double calendarHeaderHeight = 50;
static const double calendarTimeWidth = 35;
static const double calendarRowHeight = 60;
}
}

class ErrorConstants {
static const authorizedPostErrors = 'Failed to upload data: ';
static const authorizedPutErrors = 'Failed to update data: ';
static const invalidBearerToken = 'Invalid bearer token';
static const duplicateRecord =
'DioError [DioErrorType.response]: Http status error [409]';
static const invalidMedia =
'DioError [DioErrorType.response]: Http status error [415]';
static const silentLoginFailed = "Silent login failed";
}
156 changes: 156 additions & 0 deletions lib/app_networking.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import 'dart:async';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:webreg_mobile_flutter/app_constants.dart';
import 'package:webreg_mobile_flutter/app_styles.dart';

class NetworkHelper {
///TODO: inside each service that file place a switch statement to handle all
///TODO: different errors thrown by the Dio client DioErrorType.RESPONSE
const NetworkHelper();

static const int SSO_REFRESH_MAX_RETRIES = 3;
static const int SSO_REFRESH_RETRY_INCREMENT = 5000;
static const int SSO_REFRESH_RETRY_MULTIPLIER = 3;

Future<dynamic> fetchData(String url) async {
Dio dio = new Dio();
dio.options.connectTimeout = 20000;
dio.options.receiveTimeout = 20000;
dio.options.responseType = ResponseType.plain;
final _response = await dio.get(url);

if (_response.statusCode == 200) {
// If server returns an OK response, return the body
return _response.data;
} else {
///TODO: log this as a bug because the response was bad
// If that response was not OK, throw an error.
throw Exception('Failed to fetch data: ' + _response.data);
}
}

Future<dynamic> authorizedFetch(
String url, Map<String, String> headers) async {
Dio dio = new Dio();
dio.options.connectTimeout = 20000;
dio.options.receiveTimeout = 20000;
dio.options.responseType = ResponseType.plain;
dio.options.headers = headers;
final _response = await dio.get(
url,
);
if (_response.statusCode == 200) {
// If server returns an OK response, return the body
return _response.data;
} else {
///TODO: log this as a bug because the response was bad
// If that response was not OK, throw an error.

throw Exception('Failed to fetch data: ' + _response.data);
}
}

// Widget getSilentLoginDialog() {
// return AlertDialog(
// title: const Text(LoginConstants.silentLoginFailedTitle),
// content: Text(LoginConstants.silentLoginFailedDesc),
// actions: [
// TextButton(
// style: TextButton.styleFrom(
// primary: ucLabelColor,
// ),
// onPressed: () {
// Get.back(closeOverlays: true);
// },
// child: const Text('OK'),
// ),
// ],
// );
// }

Future<dynamic> authorizedPost(
String url, Map<String, String>? headers, dynamic body) async {
Dio dio = new Dio();
dio.options.connectTimeout = 20000;
dio.options.receiveTimeout = 20000;
dio.options.headers = headers;
final _response = await dio.post(url, data: body);
if (_response.statusCode == 200 || _response.statusCode == 201) {
// If server returns an OK response, return the body
return _response.data;
} else if (_response.statusCode == 400) {
// If that response was not OK, throw an error.
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.authorizedPostErrors + message);
} else if (_response.statusCode == 401) {
throw Exception(ErrorConstants.authorizedPostErrors +
ErrorConstants.invalidBearerToken);
} else if (_response.statusCode == 404) {
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.authorizedPostErrors + message);
} else if (_response.statusCode == 500) {
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.authorizedPostErrors + message);
} else if (_response.statusCode == 409) {
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.duplicateRecord + message);
} else {
throw Exception(ErrorConstants.authorizedPostErrors + 'unknown error');
}
}

Future<dynamic> authorizedPut(
String url, Map<String, String> headers, dynamic body) async {
Dio dio = new Dio();
dio.options.connectTimeout = 20000;
dio.options.receiveTimeout = 20000;
dio.options.headers = headers;
final _response = await dio.put(url, data: body);

if (_response.statusCode == 200 || _response.statusCode == 201) {
// If server returns an OK response, return the body
return _response.data;
} else if (_response.statusCode == 400) {
// If that response was not OK, throw an error.
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.authorizedPutErrors + message);
} else if (_response.statusCode == 401) {
throw Exception(ErrorConstants.authorizedPutErrors +
ErrorConstants.invalidBearerToken);
} else if (_response.statusCode == 404) {
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.authorizedPutErrors + message);
} else if (_response.statusCode == 500) {
String message = _response.data['message'] ?? '';
throw Exception(ErrorConstants.authorizedPutErrors + message);
} else {
throw Exception(ErrorConstants.authorizedPutErrors + 'unknown error');
}
}

Future<dynamic> authorizedDelete(
String url, Map<String, String> headers) async {
Dio dio = new Dio();
dio.options.connectTimeout = 20000;
dio.options.receiveTimeout = 20000;
dio.options.headers = headers;
try {
final _response = await dio.delete(url);
if (_response.statusCode == 200) {
// If server returns an OK response, return the body
return _response.data;
} else {
///TODO: log this as a bug because the response was bad
// If that response was not OK, throw an error.
throw Exception('Failed to delete data: ' + _response.data);
}
} on TimeoutException catch (e) {
// Display an alert - i.e. no internet
} catch (err) {
return null;
}
}
}
21 changes: 16 additions & 5 deletions lib/app_router.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:webreg_mobile_flutter/app_constants.dart';
import 'package:webreg_mobile_flutter/ui/search/search_view.dart';
import 'package:webreg_mobile_flutter/core/models/schedule_of_classes.dart';
import 'package:webreg_mobile_flutter/ui/list/course_list_view.dart';
import 'package:webreg_mobile_flutter/ui/navigator/bottom.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:webreg_mobile_flutter/ui/search/search_detail.dart';
import 'package:webreg_mobile_flutter/ui/search/search_view.dart';
import 'package:webreg_mobile_flutter/core/models/schedule_of_classes.dart';

// ignore: avoid_classes_with_only_static_members
class Router {
static Route<dynamic> generateRoute(RouteSettings settings) {
print('route' + settings.name);
switch (settings.name) {
case RoutePaths.Home:
return MaterialPageRoute<void>(builder: (_) => BottomNavigation());
case RoutePaths.SearchView:
return MaterialPageRoute<void>(builder: (_) => SearchView());
case RoutePaths.CourseListView:
return MaterialPageRoute<void>(builder: (_) => CourseListView());
case RoutePaths.SearchDetail:
final CourseData course = settings.arguments! as CourseData;
return MaterialPageRoute(builder: (_) {
return SearchDetail(data: course);
});

default:
return MaterialPageRoute<void>(builder: (_) => BottomNavigation());
}
}
}
}
Loading