Skip to content

Commit

Permalink
🎉 🎉 Complete upload avatar (#261)
Browse files Browse the repository at this point in the history
* use api get details account

* Update dev module add account service authenticated

* Complete upload avatar

* Fix lock user intergate profile screen when uploading
  • Loading branch information
tvc12 authored Jun 25, 2020
1 parent a129fd4 commit dfd6c9e
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 41 deletions.
10 changes: 6 additions & 4 deletions lib/authentication_bloc/authentication_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class AuthenticationBloc extends TBloc<AuthenticationEvent, AuthenticationState>
@protected
static final AccountService accountService = DI.get(AccountService);

static final AccountService accountServiceAuthenticated =
DI.get(DevModuleCore.account_service_authenticated);

@protected
static final PetCategoryService categoryService = DI.get(PetCategoryService);

Expand Down Expand Up @@ -59,8 +62,7 @@ class AuthenticationBloc extends TBloc<AuthenticationEvent, AuthenticationState>

case LoggedIn:
_clearData();
updateCurrentAccount(event);

await updateCurrentAccount();
await reloadPetCategory();
await reloadReportContent();
yield Authenticated();
Expand Down Expand Up @@ -96,8 +98,8 @@ class AuthenticationBloc extends TBloc<AuthenticationEvent, AuthenticationState>
Log.info('loaded report');
}

void updateCurrentAccount(LoggedIn event) {
_currentAccount = event.dataLogin.account;
Future updateCurrentAccount() async {
_currentAccount = await accountServiceAuthenticated.getDetails();
}

void _clearData() {
Expand Down
132 changes: 100 additions & 32 deletions lib/profile/screen/profile_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,53 @@ class ProfileScreen extends StatefulWidget {
}

class _ProfileScreenState extends TState<ProfileScreen> {
bool isLoading = false;
final authen = DI.get<AuthenticationBloc>(AuthenticationBloc);
@override
Widget build(BuildContext context) {
final spacer = SizedBox(height: 5);
final Account account = DI.get<AuthenticationBloc>(AuthenticationBloc).account;
final Account account = authen.account;
final image = account.user?.avatar?.url;
return Scaffold(
body: ListView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
children: <Widget>[
const SizedBox(height: 25),
ChooseAvatarWidget(
avatar: CircleColorWidget(
padding: const EdgeInsets.all(5),
child: AvatarWidget(
url: image,
paddingDefaultImage: const EdgeInsets.all(5),
body: Stack(
children: [
ListView(
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
children: <Widget>[
const SizedBox(height: 25),
ChooseAvatarWidget(
avatar: CircleColorWidget(
padding: const EdgeInsets.all(5),
child: AvatarWidget(
url: image,
paddingDefaultImage: const EdgeInsets.all(15),
),
),
onTapCamera: _handleOnTapCamera,
),
),
),
GestureDetector(
child: _buildName(context, account),
onTap: _onTapName,
),
_buildDarkMode(),
Divider(),
ProfileDetailWidget(
onTapMyPost: _onTapMyPost,
onTapPostLiked: _onTapPostLiked,
onTapProfile: _onTapProfile,
),
spacer,
Divider(),
BasicFunctionWidget(
onTapLogout: _onTapLogout,
onTapChangePassword: _onTapChangePassword,
onTapRating: _onTapRating,
onTapReport: _onTapReport,
GestureDetector(
child: _buildName(context, account),
onTap: _onTapName,
),
_buildDarkMode(),
Divider(),
ProfileDetailWidget(
onTapMyPost: _onTapMyPost,
onTapPostLiked: _onTapPostLiked,
onTapProfile: _onTapProfile,
),
spacer,
Divider(),
BasicFunctionWidget(
onTapLogout: _onTapLogout,
onTapChangePassword: _onTapChangePassword,
onTapRating: _onTapRating,
onTapReport: _onTapReport,
),
],
),
isLoading ? _buildLoading() : const SizedBox()
],
),
);
Expand Down Expand Up @@ -130,4 +138,64 @@ class _ProfileScreenState extends TState<ProfileScreen> {
screen: NewProfileScreen(),
);
}

void _handleOnTapCamera() {
chooseImage()
.whenComplete(() => setState(() => isLoading = true))
.then((value) => uploadImage(value))
.then((value) => updateProfile(image: value))
.then((value) => authen.account.user = value)
.catchError((ex) => Log.error('ChooseImageError ${ex.toString()}'))
.whenComplete(() => setState(() => isLoading = false));
}

Future<File> chooseImage() {
return showModalBottomSheet<File>(
backgroundColor: Colors.transparent,
context: context,
builder: (_) => ImageChoosePopup(),
).then((File file) {
if (file != null) {
return Future.value(file);
} else {
return retrieveLostData();
}
}).then((value) {
if (value == null) {
throw Exception('Can\'t get image');
} else
return value;
});
}

Future<PetImage> uploadImage(File value) async {
// TODO(TVC12): Move to bloc in the feature
final ImageService imageService = DI.get(ImageService);
final petImages = await imageService.upload([value.absolute.path]);
if (petImages?.isNotEmpty == true) {
return petImages.first;
} else {
throw PetException('Can\'t upload image');
}
}

Future<User> updateProfile({PetImage image}) {
// TODO(TVC12): Move to bloc in the feature
final UserService userService = DI.get(UserService);
final AuthenticationBloc authenBloc = DI.get(AuthenticationBloc);
final userId = authenBloc.account.user?.id;
final oldAvatar = authenBloc.account.user?.avatar?.id;
if (userId != null) {
return userService.updateAvatar(userId, image.id, deleteImage: oldAvatar);
} else {
throw PetException('Can\t update profile');
}
}

Widget _buildLoading() {
return Scaffold(
backgroundColor: TColors.transparent,
body: Center(child: CircularProgressIndicator()),
);
}
}
3 changes: 3 additions & 0 deletions lib/profile/screen/screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
library petisland.profile.screen;

import 'dart:io';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
Expand All @@ -10,6 +12,7 @@ import 'package:flutter_template/common/common.dart';
import 'package:flutter_template/common/widgets/widgets.dart';
import 'package:flutter_template/new_profile/screen/new_profile_screen.dart';
import 'package:flutter_template/pet_feed/widget/widget.dart';
import 'package:flutter_template/post/post_edit/post_edit.dart';
import 'package:flutter_template/profile/bloc/bloc.dart';
import 'package:flutter_template/profile/widget/favorite_post_component.dart';
import 'package:flutter_template/profile/widget/widget.dart';
Expand Down
6 changes: 4 additions & 2 deletions lib/register/widget/register_account_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class _RegisterAccountWidgetState extends TState<RegisterAccountWidget> {
),
LocationSelectorWidget(
isRequired: true,
onSelected: _onTextChanged,
onSelected: _onLocationChanged,
padding: EdgeInsets.zero,
selectedItem: locationController.text.isNotEmpty ? locationController.text : null,
)
Expand Down Expand Up @@ -211,8 +211,10 @@ class _RegisterAccountWidgetState extends TState<RegisterAccountWidget> {
bool get isValid =>
usernameController.text.isNotEmpty & passwordController.text.isNotEmpty;

void _onTextChanged(String str) {
void _onLocationChanged(String str) {
locationController.text = str;
}
void _onTextChanged(String str) {
setState(() {});
}
}
3 changes: 1 addition & 2 deletions petisland_core/lib/domain/login_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class LoginData extends BaseModel {

LoginData.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
token = json['token'];
account =
json['account'] != null ? Account.fromJson(json['account']) : null;
account = json['account'] != null ? Account.fromJson(json['account']) : null;
}

@override
Expand Down
16 changes: 16 additions & 0 deletions petisland_core/lib/module/dev_module_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class DevModuleCore extends AbstractModule {
static const String api_client = 'api_client';
static const String api_upload_image = 'api_upload_image';
static const String opencagedata_api = 'opencagedata_api';
static const String account_service_authenticated = 'account_service_authenticated';

@override
void init() async {
Expand All @@ -26,6 +27,7 @@ class DevModuleCore extends AbstractModule {
bind(opencagedata_api).to(_buildOpencagedataApi());

bind(AccountService).to(_buildAccountService());
bind(account_service_authenticated).to(_buildAccountServiceAuthenticated());
bind(DIKeys.cache_image).to(await _buildCacheImage());
bind(ImageService).to(_buildImageService());
bind(PetCategoryService).to(_buildPetCategoryService());
Expand All @@ -37,6 +39,7 @@ class DevModuleCore extends AbstractModule {
bind(LocationService).to(_buildLocationService());
bind(RescueRepository).to(_buildRescueRepository());
bind(RescueService).to(_buildRescueService());
bind(UserService).to(_buildUserService());
}

Future<LocalStorageService> _buildLocalService() async {
Expand Down Expand Up @@ -145,6 +148,12 @@ class DevModuleCore extends AbstractModule {
return AccountServiceImpl(repository);
}

AccountService _buildAccountServiceAuthenticated() {
final HttpClient client = get<HttpClient>(api_client);
final AccountRepository repository = AccountReposityImpl(client);
return AccountServiceImpl(repository);
}

ImageService _buildImageService() {
final HttpClient client = get(api_upload_image);
final ImageRepository repository = ImageRepositoryImpl(client);
Expand Down Expand Up @@ -202,4 +211,11 @@ class DevModuleCore extends AbstractModule {

return RescueServiceImpl(repository);
}

UserService _buildUserService() {
final HttpClient client = get<HttpClient>(api_client);

final userRepository = UserRepositoryImpl(client);
return UserServiceImpl(userRepository);
}
}
9 changes: 9 additions & 0 deletions petisland_core/lib/repository/account_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ abstract class AccountRepository {
Future<bool> requireForgotPasswordCode(String email);

Future<Account> forgotPassword(String email, String code, String password);

Future<Account> getDetails();
}

class AccountReposityImpl extends AccountRepository {
Expand Down Expand Up @@ -96,4 +98,11 @@ class AccountReposityImpl extends AccountRepository {
.get<Map<String, dynamic>>('$path/forgot-password/require-code', params: params)
.then((_) => true);
}

@override
Future<Account> getDetails() {
return client
.get<Map<String, dynamic>>('$path/details')
.then((json) => Account.fromJson(json));
}
}
14 changes: 13 additions & 1 deletion petisland_core/lib/repository/user_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ part of petisland_core.repository;

abstract class UserRepository {
Future<User> createUser(User user);
// User getUser();
Future<User> updateAvatar(String userId, String newImage, {String deleteImage});
}

class UserRepositoryImpl extends UserRepository {
Expand All @@ -18,4 +18,16 @@ class UserRepositoryImpl extends UserRepository {
.post<Map<String, dynamic>>('/api/user', body)
.then((Map<String, dynamic> json) => User.fromJson(json));
}

@override
Future<User> updateAvatar(String userId, String newImage, {String deleteImage}) {
final body = {
'avatar': {'newImage': newImage, 'deleteImage': deleteImage}
..removeWhere((key, value) => value == null)
};

return client
.put<Map<String, dynamic>>('/api/user/${userId}', body)
.then((json) => User.fromJson(json));
}
}
7 changes: 7 additions & 0 deletions petisland_core/lib/service/account_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ abstract class AccountService {
Future<bool> requireForgotPasswordCode(String email);

Future<Account> forgotPassword(String email, String code, String password);

Future<Account> getDetails();
}

class AccountServiceImpl extends AccountService {
Expand Down Expand Up @@ -58,4 +60,9 @@ class AccountServiceImpl extends AccountService {
Future<bool> requireForgotPasswordCode(String email) {
return repository.requireForgotPasswordCode(email);
}

@override
Future<Account> getDetails() {
return repository.getDetails();
}
}
6 changes: 6 additions & 0 deletions petisland_core/lib/service/user_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ part of petisland_core.service;

abstract class UserService {
Future<User> createUser(User user);
Future<User> updateAvatar(String userId, String newImage, {String deleteImage});
}

class UserServiceImpl extends UserService {
Expand All @@ -14,4 +15,9 @@ class UserServiceImpl extends UserService {
Future<User> createUser(User user) {
return repository.createUser(user);
}

@override
Future<User> updateAvatar(String userId, String newImage, {String deleteImage}) {
return repository.updateAvatar(userId, newImage, deleteImage: deleteImage);
}
}

0 comments on commit dfd6c9e

Please sign in to comment.