Skip to content

Commit

Permalink
Implement fetch album collection statuses when user enter album detai…
Browse files Browse the repository at this point in the history
…l page #112
  • Loading branch information
up2code committed Mar 13, 2021
1 parent 6389db1 commit badc7c9
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 14 deletions.
1 change: 1 addition & 0 deletions lib/models.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
library models;

export 'src/models/album_collection_status_model.dart';
export 'src/models/album_disc_model.dart';
export 'src/models/album_model.dart';
export 'src/models/album_user_model.dart';
Expand Down
28 changes: 22 additions & 6 deletions lib/src/controllers/album_detail_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import 'package:vocadb_app/repositories.dart';
import 'package:vocadb_app/services.dart';

class AlbumDetailController extends GetxController {
final collected = false.obs;
final collectionStatus = AlbumCollectionStatusModel().obs;

final initialLoading = true.obs;

final statusLoading = true.obs;

final album = AlbumModel().obs;

final AlbumRepository albumRepository;
Expand All @@ -23,6 +25,7 @@ class AlbumDetailController extends GetxController {
@override
void onInit() {
initArgs();
checkAlbumCollectionStatus();
fetchApis();
super.onInit();
}
Expand All @@ -42,18 +45,31 @@ class AlbumDetailController extends GetxController {
.then(album)
.then(initialLoadingDone);

checkAlbumCollectionStatus() {
int userId = authService.currentUser().id;

if (userId == null) {
return;
Future<void> checkAlbumCollectionStatus() {
if (authService.currentUser == null ||
authService.currentUser().id == null) {
return Future.value();
}

//TODO: Wait for API backend implementation
return userRepository
.getCurrentUserAlbumCollection(album().id)
.then((AlbumCollectionStatusModel model) {
return (model == null)
? AlbumCollectionStatusModel()
: collectionStatus(model);
})
.then((artist) => debounce(
collectionStatus, (_) => updateAlbumCollection(),
time: Duration(seconds: 1)))
.then(statusLoadingDone);
}

updateAlbumCollection() {
//TODO: Wait for API backend implementation
}

initialLoadingDone(_) => initialLoading(false);

statusLoadingDone(_) => statusLoading(false);
}
23 changes: 23 additions & 0 deletions lib/src/models/album_collection_status_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:vocadb_app/models.dart';

class AlbumCollectionStatusModel {
AlbumModel album;
String mediaType;
String purchaseStatus;
int rating;

AlbumCollectionStatusModel(
{this.album, this.mediaType, this.purchaseStatus, this.rating});

AlbumCollectionStatusModel.fromJson(Map<String, dynamic> json)
: album = (json.containsKey('album'))
? AlbumModel.fromJson(json['album'])
: null,
mediaType = json['mediaType'],
purchaseStatus = json['purchaseStatus'],
rating = json['rating'];

get label => (purchaseStatus != null) ? purchaseStatus : 'Add';

get isCollected => (purchaseStatus != null && purchaseStatus != 'Nothing');
}
2 changes: 1 addition & 1 deletion lib/src/models/user_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class UserModel extends Equatable {
String name;
MainPictureModel mainPicture;

UserModel();
UserModel({this.id});

UserModel.fromJson(Map<String, dynamic> json)
: id = json['id'],
Expand Down
19 changes: 12 additions & 7 deletions lib/src/pages/album_detail_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,18 @@ class AlbumDetailPageView extends StatelessWidget {

List<Widget> buttons = [];

buttons.add(ActiveFlatButton(
icon: Icon(Icons.favorite),
label: 'collect'.tr,
active: controller.collected.value,
onPressed: (authService.currentUser().id == null)
? null
: this._onTapCollectButton,
buttons.add(Obx(
() => ActiveFlatButton(
icon: Icon(Icons.favorite),
label: (controller.collectionStatus.value.isCollected)
? controller.collectionStatus.value.purchaseStatus
: 'collect'.tr,
active: controller.collectionStatus.value.isCollected,
onPressed: (authService.currentUser().id == null ||
controller.statusLoading.value)
? null
: this._onTapCollectButton,
),
));

buttons.add(FlatButton(
Expand Down
10 changes: 10 additions & 0 deletions lib/src/repositories/user_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,14 @@ class UserRepository extends RestApiRepository {
? null
: ArtistModel.fromJson(v['artist']));
}

/// Gets currently logged in user's album collection status
Future<AlbumCollectionStatusModel> getCurrentUserAlbumCollection(
int albumId) {
return httpService
.get('/api/users/current/album-collection-statuses/$albumId', null)
.then((v) => (v == null || v['album'] == null)
? null
: AlbumCollectionStatusModel.fromJson(v));
}
}
43 changes: 43 additions & 0 deletions test/controllers/album_detail_controller_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
import 'package:mockito/mockito.dart';
import 'package:vocadb_app/controllers.dart';
import 'package:vocadb_app/models.dart';
import 'package:vocadb_app/repositories.dart';
import 'package:vocadb_app/services.dart';

class MockAlbumRepository extends Mock implements AlbumRepository {}

class MockUserRepository extends Mock implements UserRepository {}

class MockAuthService extends Mock implements AuthService {}

void main() {
final MockAlbumRepository mockAlbumRepository = MockAlbumRepository();
final MockUserRepository mockUserRepository = MockUserRepository();
final MockAuthService mockAuthService = MockAuthService();

test('should get album collection status success', () async {
final AlbumCollectionStatusModel mockCollectionStatus =
AlbumCollectionStatusModel(purchaseStatus: 'Wishlisted');

final mockUserModel = Rx<UserModel>();
mockUserModel(UserModel(id: 1));

when(mockAuthService.currentUser).thenReturn(mockUserModel);

when(mockUserRepository.getCurrentUserAlbumCollection(1))
.thenAnswer((_) => Future.value(mockCollectionStatus));

final AlbumDetailController controller = AlbumDetailController(
userRepository: mockUserRepository,
albumRepository: mockAlbumRepository,
authService: mockAuthService);

controller.album(AlbumModel(id: 1));

await controller.checkAlbumCollectionStatus();

expect(controller.collectionStatus.value.purchaseStatus, "Wishlisted");
});
}
33 changes: 33 additions & 0 deletions test/models/album_collection_status_model_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:vocadb_app/models.dart';

void main() {
group('Album collection status model', () {
test('should parse from json correctly', () {
const mockJson = {
"album": {
"artistString": "Harry, Teruaki Tanahashi, ELS feat. Hatsune Miku",
"id": 23848,
"name": "A HUNDRED MILLION LIGHTS",
},
"mediaType": "Other",
"purchaseStatus": "Wishlisted",
"rating": 5
};

AlbumCollectionStatusModel result =
AlbumCollectionStatusModel.fromJson(mockJson);
expect(result.album.id, 23848);
expect(result.mediaType, 'Other');
expect(result.purchaseStatus, 'Wishlisted');
expect(result.rating, 5);
});

test('should not thrown exception when input empty json', () {
AlbumCollectionStatusModel result =
AlbumCollectionStatusModel.fromJson({});
expect(result, isNotNull);
expect(result.album, isNull);
});
});
}
39 changes: 39 additions & 0 deletions test/repositories/user_repository_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:vocadb_app/models.dart';
import 'package:vocadb_app/repositories.dart';
import 'package:vocadb_app/services.dart';

class MockHttpService extends Mock implements HttpService {}

void main() {
test('should return AlbumCollectionStatusModel', () async {
final Map<String, dynamic> mockResponse = {
"album": {
"artistString": "Harry, Teruaki Tanahashi, ELS feat. Hatsune Miku",
"id": 23848,
"name": "A HUNDRED MILLION LIGHTS",
},
"mediaType": "Other",
"purchaseStatus": "Wishlisted",
"rating": 5
};
final MockHttpService mockHttpService = MockHttpService();
final UserRepository userRepository =
UserRepository(httpService: mockHttpService);
final AlbumCollectionStatusModel expectModel =
AlbumCollectionStatusModel.fromJson(mockResponse);
final String url = '/api/users/current/album-collection-statuses/1';

when(mockHttpService.get(url, null))
.thenAnswer((_) => Future.value(mockResponse));

final AlbumCollectionStatusModel actualModel =
await userRepository.getCurrentUserAlbumCollection(1);

expect(actualModel.album.id, expectModel.album.id);
expect(actualModel.mediaType, expectModel.mediaType);
expect(actualModel.purchaseStatus, expectModel.purchaseStatus);
expect(actualModel.rating, expectModel.rating);
});
}

0 comments on commit badc7c9

Please sign in to comment.