Skip to content

Commit

Permalink
chore: add fetch survey detail
Browse files Browse the repository at this point in the history
  • Loading branch information
markgravity committed Jun 29, 2021
1 parent ba47934 commit 8c281fa
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 26 deletions.
6 changes: 6 additions & 0 deletions lib/configs/factories.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ final Map<Type, Function> _factories = {
UserInfo: () => UserInfo(),
AuthTokenInfo: () => AuthTokenInfo(),
SurveyInfo: () => SurveyInfo(),
ApiRawResponse: () => ApiRawResponse(),
ApiRawObject: () => ApiRawObject(),
DetailedSurveyInfo: () => DetailedSurveyInfo(),
SurveyQuestionInfo: () => SurveyQuestionInfo(),
SurveyQuestionDisplayType: (v) => SurveyQuestionDisplayType(v as String),
SurveyQuestionPickType: (v) => SurveyQuestionPickType(v as String),
};
3 changes: 3 additions & 0 deletions lib/gen/configs.gen.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import 'package:survey/gen/flavors.gen.dart';
import 'package:flutter/widgets.dart';
import 'package:survey/models/auth_token_info.dart';
import 'package:survey/models/detailed_survey_info.dart';
import 'package:survey/models/survey_info.dart';
import 'package:survey/models/survey_question_info.dart';
import 'package:survey/models/user_info.dart';
import 'package:survey/modules/forgot_password/forgot_password_module.dart';
import 'package:survey/modules/home/home_module.dart';
import 'package:survey/modules/landing/landing_module.dart';
import 'package:survey/modules/login/login_module.dart';
import 'package:survey/modules/side_menu/side_menu_module.dart';
import 'package:survey/modules/survey_detail/survey_detail_module.dart';
import 'package:survey/services/api/api_service.dart';

part 'package:survey/configs/app.dart';
part 'package:survey/configs/factories.dart';
Expand Down
12 changes: 7 additions & 5 deletions lib/models/auth_token_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ class AuthTokenInfo with Mappable {

@override
void mapping(Mapper map) {
map<String>("access_token", accessToken, (v) => accessToken = v as String);
map<String>("token_type", tokenType, (v) => tokenType = v as String);
map<DateTime>("expires_in", expiresIn, (v) => expiresIn = v as DateTime,
DateTransform());
map<String>("attributes.access_token", accessToken,
(v) => accessToken = v as String);
map<String>(
"refresh_token", refreshToken, (v) => refreshToken = v as String);
"attributes.token_type", tokenType, (v) => tokenType = v as String);
map<DateTime>("attributes.expires_in", expiresIn,
(v) => expiresIn = v as DateTime, const DateTransform());
map<String>("attributes.refresh_token", refreshToken,
(v) => refreshToken = v as String);
}
}
7 changes: 7 additions & 0 deletions lib/models/detailed_survey_info.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:survey/models/survey_info.dart';
import 'package:survey/models/survey_question_info.dart';

// ignore: must_be_immutable
class DetailedSurveyInfo extends SurveyInfo {
late List<SurveyQuestionInfo> questions;
}
9 changes: 6 additions & 3 deletions lib/models/survey_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import 'package:equatable/equatable.dart';

// ignore: must_be_immutable
class SurveyInfo extends Equatable with Mappable {
String? id;
String? title;
String? description;
String? coverImageUrl;

@override
void mapping(Mapper map) {
map<String>("title", title, (v) => title = v as String?);
map<String>("description", description, (v) => description = v as String?);
map<String>("cover_image_url", coverImageUrl, (v) {
map<String>("id", id, (v) => id = v as String?);
map<String>("attributes.title", title, (v) => title = v as String?);
map<String>("attributes.description", description,
(v) => description = v as String?);
map<String>("attributes.cover_image_url", coverImageUrl, (v) {
final url = v as String?;
coverImageUrl = url != null ? "${url}l" : null;
});
Expand Down
87 changes: 87 additions & 0 deletions lib/models/survey_question_info.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:object_mapper/object_mapper.dart';

class SurveyQuestionInfo with Mappable {
String? id;
String? content;
int? displayOrder;
SurveyQuestionPickType? pickType;
SurveyQuestionDisplayType? displayType;
bool? isMandatory;
String? coverImageUrl;
double? coverImageOpacity;

@override
void mapping(Mapper map) {
map<String>(
"id",
id,
(v) => id = v as String,
);
map<String>(
"attributes.text",
content,
(v) => content = v as String,
);
map<int>(
"attributes.display_order",
displayOrder,
(v) => displayOrder = v as int,
);
map<SurveyQuestionPickType>(
"attributes.pick",
pickType,
(v) => pickType = v as SurveyQuestionPickType?,
const EnumTransform<SurveyQuestionPickType, String>(),
);
map<SurveyQuestionDisplayType>(
"attributes.display_type",
displayType,
(v) => displayType = v as SurveyQuestionDisplayType?,
const EnumTransform<SurveyQuestionDisplayType, String>(),
);
map<bool>(
"attributes.is_mandatory",
isMandatory,
(v) => isMandatory = v as bool,
);
map<String>(
"attributes.cover_image_url",
coverImageUrl,
(v) => coverImageUrl = v as String?,
);
map<double>(
"attributes.cover_image_opacity",
coverImageOpacity,
(v) => coverImageOpacity = v as double?,
);
}
}

// ignore: avoid_implementing_value_types
class SurveyQuestionDisplayType extends Enumerable<String> {
const SurveyQuestionDisplayType(this.rawValue);

@override
final String rawValue;

static const intro = SurveyQuestionDisplayType("intro");
static const star = SurveyQuestionDisplayType("star");
static const heart = SurveyQuestionDisplayType("heart");
static const smiley = SurveyQuestionDisplayType("smiley");
static const choice = SurveyQuestionDisplayType("choice");
static const nps = SurveyQuestionDisplayType("NPS");
static const textarea = SurveyQuestionDisplayType("textarea");
static const textField = SurveyQuestionDisplayType("textfield");
static const outro = SurveyQuestionDisplayType("outro");
}

class SurveyQuestionPickType extends Enumerable<String> {
const SurveyQuestionPickType(this.rawValue);

@override
final String rawValue;

static const none = SurveyQuestionDisplayType("none");
static const one = SurveyQuestionDisplayType("one");
static const any = SurveyQuestionDisplayType("any");
}
4 changes: 2 additions & 2 deletions lib/models/user_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class UserInfo with Mappable {

@override
void mapping(Mapper map) {
map("email", email, (v) => email = v as String);
map("avatar_url", avatarUrl, (v) => avatarUrl = v as String);
map("attributes.email", email, (v) => email = v as String);
map("attributes.avatar_url", avatarUrl, (v) => avatarUrl = v as String);
}
}
9 changes: 9 additions & 0 deletions lib/repositories/survey_repository.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:survey/models/detailed_survey_info.dart';
import 'package:survey/models/survey_info.dart';
import 'package:survey/services/api/survey/survey_api_service.dart';
import 'package:survey/services/local_storage/local_storage_service.dart';
Expand All @@ -11,6 +12,8 @@ abstract class SurveyRepository {
Future<List<SurveyInfo>> fetchSurveysFromCached();

Future<List<SurveyInfo>> fetchSurveysFromRemote();

Future<DetailedSurveyInfo> fetchDetailedSurvey(String id);
}

class SurveyRepositoryImpl implements SurveyRepository {
Expand Down Expand Up @@ -45,4 +48,10 @@ class SurveyRepositoryImpl implements SurveyRepository {

return list.items;
}

@override
Future<DetailedSurveyInfo> fetchDetailedSurvey(String id) {
final params = SurveyInfoParams(id: id);
return _surveyApiService.info(params: params);
}
}
30 changes: 30 additions & 0 deletions lib/services/api/api_raw_response.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
part of 'api_service.dart';

class ApiRawResponse with Mappable {
ApiRawObject? data;
Map<String, dynamic>? meta;
List<ApiRawObject>? included;

@override
void mapping(Mapper map) {
map<ApiRawObject>("data", data, (v) => data = v as ApiRawObject?);
map<Map<String, dynamic>>(
"meta", meta, (v) => meta = v as Map<String, dynamic>?);
map<ApiRawObject>(
"included", included, (v) => included = v as List<ApiRawObject>?);
}
}

class ApiRawObject with Mappable {
String? id;
String? type;
Map<String, dynamic>? attributes;

@override
void mapping(Mapper map) {
map<String>("id", id, (v) => id = v as String);
map<String>("type", type, (v) => type = v as String);
map<Map<String, dynamic>>("attributes", attributes,
(v) => attributes = v as Map<String, dynamic>);
}
}
16 changes: 9 additions & 7 deletions lib/services/api/api_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ part 'api_service_register.dart';

part 'api_list_object.dart';

part 'api_raw_response.dart';

abstract class ApiService {
Future<T> call<T>({
required HttpMethod method,
Expand Down Expand Up @@ -146,17 +148,19 @@ class ApiServiceImpl implements ApiService {
}

T _convertResponseToObject<T>(Map<String, dynamic> response) {
if (T == ApiRawResponse) {
return Mapper.fromJson(response).toObject<T>()!;
}

if (response["data"] == null && T.toString() == "void") {
return null as T;
}

if (response["data"] is! Map<String, dynamic> ||
response["data"]["attributes"] is! Map<String, dynamic>) {
if (response["data"] is! Map<String, dynamic>) {
throw ApiException.invalidResponseStructure;
}

return Mapper.fromJson(
response["data"]["attributes"] as Map<String, dynamic>)
return Mapper.fromJson(response["data"] as Map<String, dynamic>)
.toObject<T>()!;
}

Expand All @@ -167,9 +171,7 @@ class ApiServiceImpl implements ApiService {
}

final items = (response["data"] as List<dynamic>)
.where((e) => e["attributes"] is Map<String, dynamic>)
.map((e) => Mapper.fromJson(e["attributes"] as Map<String, dynamic>)
.toObject<T>()!)
.map((e) => Mapper.fromJson(e as Map<String, dynamic>).toObject<T>()!)
.toList();

return ApiListObject<T>(items: items);
Expand Down
24 changes: 21 additions & 3 deletions lib/services/api/survey/survey_api_service.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:object_mapper/object_mapper.dart';
import 'package:survey/models/detailed_survey_info.dart';
import 'package:survey/models/survey_info.dart';
import 'package:survey/models/survey_question_info.dart';
import 'package:survey/services/api/api_service.dart';
import 'package:survey/services/http/http_service.dart';
import 'package:survey/services/locator/locator_service.dart';
Expand All @@ -11,19 +13,35 @@ part 'params/survey_info_params.dart';
abstract class SurveyApiService {
static const endpoint = "/surveys";

Future<SurveyInfo> info({required SurveyInfoParams params});
Future<DetailedSurveyInfo> info({required SurveyInfoParams params});

Future<ApiListObject<SurveyInfo>> list({required SurveyListParams params});
}

class SurveyApiServiceImpl implements SurveyApiService {
final ApiService _apiService = locator.get();

@override
Future<SurveyInfo> info({required SurveyInfoParams params}) {
return _apiService.call(
Future<DetailedSurveyInfo> info({required SurveyInfoParams params}) async {
final rawResponse = await _apiService.call<ApiRawResponse>(
method: HttpMethod.get,
endpoint: "${SurveyApiService.endpoint}/${params.id}",
);

final info = Mapper.fromJson(rawResponse.data!.toJson())
.toObject<DetailedSurveyInfo>()!;

final questions = List<SurveyQuestionInfo>.empty(growable: true);
final included = (rawResponse.included ?? [])
.where((element) => element.type == "question");

for (final ApiRawObject rawObject in included) {
questions.add(
Mapper.fromJson(rawObject.toJson()).toObject<SurveyQuestionInfo>()!);
}
info.questions = questions;

return info;
}

@override
Expand Down
6 changes: 3 additions & 3 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ packages:
name: object_mapper
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
package_config:
dependency: transitive
description:
Expand Down Expand Up @@ -685,7 +685,7 @@ packages:
name: skeletor
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2"
version: "0.0.3"
sky_engine:
dependency: transitive
description: flutter
Expand Down Expand Up @@ -732,7 +732,7 @@ packages:
name: streams_provider
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
version: "0.1.1"
string_scanner:
dependency: transitive
description:
Expand Down
6 changes: 3 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ dependencies:
get_it: ^7.0.0
json_annotation: ^4.0.1
enumerated_class: ^0.0.1+1
object_mapper: ^1.1.0
streams_provider: ^0.1.0
object_mapper: ^1.2.0
streams_provider: ^0.1.1
shared_preferences: ^2.0.5
modal_progress_hud_nsn: ^0.1.0-nullsafety-1
adaptive_dialog: ^0.10.0+5
async: ^2.5.0
carousel_slider: ^4.0.0-nullsafety.0
skeletor: ^0.0.2
skeletor: ^0.0.3
simple_gesture_detector: ^0.2.0
equatable: ^2.0.2
tuple: ^2.0.0
Expand Down

0 comments on commit 8c281fa

Please sign in to comment.