Skip to content
This repository has been archived by the owner on Jan 26, 2021. It is now read-only.

feat: Offline support #133

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
21 changes: 19 additions & 2 deletions lib/auth/auth_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:mentorship_client/auth/bloc.dart';
import 'package:mentorship_client/remote/repositories/auth_repository.dart';

import 'bloc.dart';

class AuthBloc extends Bloc<AuthEvent, AuthState> {
class AuthBloc extends HydratedBloc<AuthEvent, AuthState> {
final AuthRepository userRepository;

AuthBloc(this.userRepository) : super(AuthUninitialized());
Expand Down Expand Up @@ -35,4 +35,21 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
yield AuthUnauthenticated(justLoggedOut: true);
}
}

@override
AuthState fromJson(Map<String, dynamic> json) {
try {
return AuthAuthenticated();
} catch (_) {
return null;
}
}

@override
Map<String, dynamic> toJson(AuthState state) {
if (state is AuthAuthenticated) {
return state.toJson();
}
return null;
}
}
11 changes: 10 additions & 1 deletion lib/auth/auth_state.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';

part 'auth_state.g.dart';

abstract class AuthState extends Equatable {
const AuthState();
Expand All @@ -9,7 +12,13 @@ abstract class AuthState extends Equatable {

class AuthUninitialized extends AuthState {}

class AuthAuthenticated extends AuthState {}
@JsonSerializable()
class AuthAuthenticated extends AuthState {
AuthAuthenticated();
factory AuthAuthenticated.fromJson(Map<String, dynamic> json) =>
_$AuthAuthenticatedFromJson(json);
Map<String, dynamic> toJson() => _$AuthAuthenticatedToJson(this);
}

/// Represents app state when the user is not signed in.
/// [justLoggedOut] signifies that a logout happened
Expand Down
14 changes: 14 additions & 0 deletions lib/auth/auth_state.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:logging/logging.dart';
import 'package:mentorship_client/auth/auth_bloc.dart';
import 'package:mentorship_client/auth/bloc.dart';
import 'package:mentorship_client/bloc_delegate.dart';
import 'package:mentorship_client/remote/repositories/auth_repository.dart';
import 'package:mentorship_client/screens/home/home_screen.dart';
import 'package:mentorship_client/screens/login/login_screen.dart';
import 'package:path_provider/path_provider.dart';
import 'package:toast/toast.dart';

void main() {
void main() async {
// Logs all BLoC transitions
Bloc.observer = SimpleBlocDelegate();
_setupLogging();

WidgetsFlutterBinding.ensureInitialized();
HydratedBloc.storage = await HydratedStorage.build(
storageDirectory: await getApplicationDocumentsDirectory(),
);
// Providing app-wide auth bloc, so that app state changes immediately when
// auth state changes.
runApp(
BlocProvider<AuthBloc>(
create: (context) => AuthBloc(AuthRepository.instance)..add(AppStarted()),
create: (context) => AuthBloc(AuthRepository.instance),
child: MentorshipApp(),
),
);
Expand Down
26 changes: 12 additions & 14 deletions lib/remote/models/home_stats.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import 'package:mentorship_client/remote/models/task.dart';
import 'package:json_annotation/json_annotation.dart';

part 'home_stats.g.dart';

/// This class represents statistics of the user actions on the app.
/// [name] the name of the user
/// [pendingRequests] number of pending requests
/// [acceptedRequests] number of accepted requests
/// [completedRelations] number of completed relations
/// [cancelledRelations] number of cancelled relations
/// [rejectedRequests] number of rejected requests
/// [pending_requests] number of pending requests
/// [accepted_requests] number of accepted requests
/// [completed_relations] number of completed relations
/// [cancelled_relations] number of cancelled relations
/// [rejected_requests] number of rejected requests
/// [achievements] a list of up-to 3 completed tasks

@JsonSerializable(fieldRename: FieldRename.snake)
class HomeStats {
final String name;
final int pendingRequests;
Expand All @@ -32,13 +37,6 @@ class HomeStats {
assert(cancelledRelations != null),
assert(rejectedRequests != null);

factory HomeStats.fromJson(Map<String, dynamic> json) => HomeStats(
name: json["name"],
pendingRequests: json["pending_requests"],
acceptedRequests: json["accepted_requests"],
completedRelations: json["completed_relations"],
cancelledRelations: json["cancelled_relations"],
rejectedRequests: json["rejected_requests"],
achievements: Task.fromAchievements(json["achievements"]),
);
factory HomeStats.fromJson(Map<String, dynamic> json) => _$HomeStatsFromJson(json);
Map<String, dynamic> toJson() => _$HomeStatsToJson(this);
}
32 changes: 32 additions & 0 deletions lib/remote/models/home_stats.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions lib/remote/models/relation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,29 @@ class Relation {
notes: json["notes"],
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['action_user_id'] = this.actionUserId;
data['sent_by_me'] = this.sentByMe;
data['mentor'] = this.mentor;
data['mentee'] = this.mentee;
data['creation_date'] = this.sentOn;
data['accept_date'] = this.acceptedOn;
data['start_date'] = this.startsOn;
data['end_date'] = this.endsOn;
data['state'] = this.state;
data['notes'] = this.notes;
return data;
}

static List<Relation> relations(List<dynamic> relationList) {
List<Relation> relations = [];
for (dynamic relationsJson in relationList) {
relations.add(Relation.fromJson(relationsJson));
}
return relations;
}
}

/// This data class represents partial information of user of the system.
Expand All @@ -55,4 +78,10 @@ class RelationUserResponse {
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
22 changes: 11 additions & 11 deletions lib/remote/models/task.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'package:json_annotation/json_annotation.dart';
part 'task.g.dart';

/// This data class represents a task related to a mentorship
/// relation.
///
Expand All @@ -6,6 +9,7 @@
/// [isDone] Represents whether this task has been completed
/// [createdAt] Unix timestamp of when this task was created
/// [completedAt] Unix timestamp of when this task was completed
@JsonSerializable(fieldRename: FieldRename.snake)
class Task {
final int id;
final String description;
Expand All @@ -23,19 +27,15 @@ class Task {
assert(description != null),
assert(isDone != null);

factory Task.fromJson(Map<String, dynamic> json) => Task(
id: json["id"],
description: json["description"],
isDone: json["is_done"],
createdAt: json["created_at"],
completedAt: json["completed_at"],
);
factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json);
Map<String, dynamic> toJson() => _$TaskToJson(this);


static List<Task> fromAchievements(List<dynamic> taskList) {
List<Task> achievements = [];
static List<Task> tasks(List<dynamic> taskList) {
List<Task> tasks = [];
for (dynamic taskJson in taskList) {
achievements.add(Task.fromJson(taskJson));
tasks.add(Task.fromJson(taskJson));
}
return achievements;
return tasks;
}
}
25 changes: 25 additions & 0 deletions lib/remote/models/task.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions lib/remote/models/user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,12 @@ class User {
data['available_to_mentor'] = this.availableToMentor;
return data;
}

static List<User> users(List<dynamic> userList) {
List<User> users = [];
for (dynamic usersJson in userList) {
users.add(User.fromJson(usersJson));
}
return users;
}
}
2 changes: 0 additions & 2 deletions lib/remote/repositories/relation_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ class RelationRepository {
Future<Relation> getCurrentRelation() async {
final body =
await ApiManager.callSafely(() => ApiManager.instance.relationService.getCurrentRelation());

// TODO: Make it cleanier and prettier
try {
return Relation.fromJson(body);
} on NoSuchMethodError catch (error) {
Expand Down
Loading