fix: add icon_url in migration

This commit is contained in:
Ian Su 2022-08-08 22:19:05 +08:00
parent db19337609
commit d56e8c7673
9 changed files with 79 additions and 53 deletions

View File

@ -11,7 +11,8 @@ class UserService {
UserService({ UserService({
required this.userId, required this.userId,
}); });
Future<Either<UserProfilePB, FlowyError>> getUserProfile({required String userId}) { Future<Either<UserProfilePB, FlowyError>> getUserProfile(
{required String userId}) {
return UserEventGetUserProfile().send(); return UserEventGetUserProfile().send();
} }
@ -19,7 +20,7 @@ class UserService {
String? name, String? name,
String? password, String? password,
String? email, String? email,
String? icon, String? iconUrl,
}) { }) {
var payload = UpdateUserProfilePayloadPB.create()..id = userId; var payload = UpdateUserProfilePayloadPB.create()..id = userId;
@ -35,14 +36,15 @@ class UserService {
payload.email = email; payload.email = email;
} }
if (icon != null) { if (iconUrl != null) {
payload.icon = icon; payload.iconUrl = iconUrl;
} }
return UserEventUpdateUserProfile(payload).send(); return UserEventUpdateUserProfile(payload).send();
} }
Future<Either<Unit, FlowyError>> deleteWorkspace({required String workspaceId}) { Future<Either<Unit, FlowyError>> deleteWorkspace(
{required String workspaceId}) {
throw UnimplementedError(); throw UnimplementedError();
} }
@ -75,7 +77,8 @@ class UserService {
}); });
} }
Future<Either<WorkspacePB, FlowyError>> createWorkspace(String name, String desc) { Future<Either<WorkspacePB, FlowyError>> createWorkspace(
String name, String desc) {
final request = CreateWorkspacePayloadPB.create() final request = CreateWorkspacePayloadPB.create()
..name = name ..name = name
..desc = desc; ..desc = desc;

View File

@ -35,8 +35,8 @@ class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> {
); );
}); });
}, },
updateUserIcon: (String icon) { updateUserIcon: (String iconUrl) {
_userService.updateUserProfile(icon: icon).then((result) { _userService.updateUserProfile(iconUrl: iconUrl).then((result) {
result.fold( result.fold(
(l) => null, (l) => null,
(err) => Log.error(err), (err) => Log.error(err),
@ -60,7 +60,8 @@ class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> {
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) { void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
userProfileOrFailed.fold( userProfileOrFailed.fold(
(newUserProfile) => add(SettingsUserEvent.didReceiveUserProfile(newUserProfile)), (newUserProfile) =>
add(SettingsUserEvent.didReceiveUserProfile(newUserProfile)),
(err) => Log.error(err), (err) => Log.error(err),
); );
} }
@ -70,8 +71,10 @@ class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> {
class SettingsUserEvent with _$SettingsUserEvent { class SettingsUserEvent with _$SettingsUserEvent {
const factory SettingsUserEvent.initial() = _Initial; const factory SettingsUserEvent.initial() = _Initial;
const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName; const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName;
const factory SettingsUserEvent.updateUserIcon(String icon) = _UpdateUserIcon; const factory SettingsUserEvent.updateUserIcon(String iconUrl) =
const factory SettingsUserEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile; _UpdateUserIcon;
const factory SettingsUserEvent.didReceiveUserProfile(
UserProfilePB newUserProfile) = _DidReceiveUserProfile;
} }
@freezed @freezed
@ -81,7 +84,8 @@ class SettingsUserState with _$SettingsUserState {
required Either<Unit, String> successOrFailure, required Either<Unit, String> successOrFailure,
}) = _SettingsUserState; }) = _SettingsUserState;
factory SettingsUserState.initial(UserProfilePB userProfile) => SettingsUserState( factory SettingsUserState.initial(UserProfilePB userProfile) =>
SettingsUserState(
userProfile: userProfile, userProfile: userProfile,
successOrFailure: left(unit), successOrFailure: left(unit),
); );

View File

@ -40,7 +40,7 @@ class MenuUser extends StatelessWidget {
} }
Widget _renderAvatar(BuildContext context) { Widget _renderAvatar(BuildContext context) {
String icon = context.read<MenuUserBloc>().state.userProfile.icon; String iconUrl = context.read<MenuUserBloc>().state.userProfile.iconUrl;
return SizedBox( return SizedBox(
width: 25, width: 25,
@ -49,7 +49,7 @@ class MenuUser extends StatelessWidget {
borderRadius: Corners.s5Border, borderRadius: Corners.s5Border,
child: CircleAvatar( child: CircleAvatar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
child: svgWidget('emoji/$icon'), child: svgWidget('emoji/$iconUrl'),
)), )),
); );
} }

View File

@ -15,12 +15,17 @@ class SettingsUserView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider<SettingsUserViewBloc>( return BlocProvider<SettingsUserViewBloc>(
create: (context) => getIt<SettingsUserViewBloc>(param1: user)..add(const SettingsUserEvent.initial()), create: (context) => getIt<SettingsUserViewBloc>(param1: user)
..add(const SettingsUserEvent.initial()),
child: BlocBuilder<SettingsUserViewBloc, SettingsUserState>( child: BlocBuilder<SettingsUserViewBloc, SettingsUserState>(
builder: (context, state) => SingleChildScrollView( builder: (context, state) => SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [_renderUserNameInput(context), const VSpace(20), _renderCurrentIcon(context)], children: [
_renderUserNameInput(context),
const VSpace(20),
_renderCurrentIcon(context)
],
), ),
), ),
), ),
@ -33,8 +38,9 @@ class SettingsUserView extends StatelessWidget {
} }
Widget _renderCurrentIcon(BuildContext context) { Widget _renderCurrentIcon(BuildContext context) {
String icon = context.read<SettingsUserViewBloc>().state.userProfile.icon; String iconUrl =
return _CurrentIcon(icon); context.read<SettingsUserViewBloc>().state.userProfile.iconUrl;
return _CurrentIcon(iconUrl);
} }
} }
@ -53,19 +59,23 @@ class _UserNameInput extends StatelessWidget {
labelText: 'Name', labelText: 'Name',
), ),
onSubmitted: (val) { onSubmitted: (val) {
context.read<SettingsUserViewBloc>().add(SettingsUserEvent.updateUserName(val)); context
.read<SettingsUserViewBloc>()
.add(SettingsUserEvent.updateUserName(val));
}); });
} }
} }
class _CurrentIcon extends StatelessWidget { class _CurrentIcon extends StatelessWidget {
final String icon; final String iconUrl;
const _CurrentIcon(this.icon, {Key? key}) : super(key: key); const _CurrentIcon(this.iconUrl, {Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_setIcon(String icon) { _setIcon(String iconUrl) {
context.read<SettingsUserViewBloc>().add(SettingsUserEvent.updateUserIcon(icon)); context
.read<SettingsUserViewBloc>()
.add(SettingsUserEvent.updateUserIcon(iconUrl));
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
@ -78,7 +88,10 @@ class _CurrentIcon extends StatelessWidget {
builder: (BuildContext context) { builder: (BuildContext context) {
return SimpleDialog( return SimpleDialog(
title: const Text('Select an Icon'), title: const Text('Select an Icon'),
children: <Widget>[SizedBox(height: 300, width: 300, child: IconGallery(_setIcon))]); children: <Widget>[
SizedBox(
height: 300, width: 300, child: IconGallery(_setIcon))
]);
}, },
); );
}, },
@ -93,8 +106,9 @@ class _CurrentIcon extends StatelessWidget {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Container( child: Container(
margin: const EdgeInsets.all(5.0), margin: const EdgeInsets.all(5.0),
decoration: BoxDecoration(border: Border.all(color: Colors.grey)), decoration:
child: svgWithSize('emoji/$icon', const Size(60, 60)), BoxDecoration(border: Border.all(color: Colors.grey)),
child: svgWithSize('emoji/$iconUrl', const Size(60, 60)),
)), )),
])), ])),
); );
@ -106,16 +120,18 @@ class IconGallery extends StatelessWidget {
const IconGallery(this.setIcon, {Key? key}) : super(key: key); const IconGallery(this.setIcon, {Key? key}) : super(key: key);
Future<List<String>> _getIcons(BuildContext context) async { Future<List<String>> _getIcons(BuildContext context) async {
final manifestContent = await DefaultAssetBundle.of(context).loadString('AssetManifest.json'); final manifestContent =
await DefaultAssetBundle.of(context).loadString('AssetManifest.json');
final Map<String, dynamic> manifestMap = json.decode(manifestContent); final Map<String, dynamic> manifestMap = json.decode(manifestContent);
final icons = manifestMap.keys final iconUrls = manifestMap.keys
.where((String key) => key.startsWith('assets/images/emoji/') && key.endsWith('.svg')) .where((String key) =>
key.startsWith('assets/images/emoji/') && key.endsWith('.svg'))
.map((String key) => key.split('/').last.split('.').first) .map((String key) => key.split('/').last.split('.').first)
.toList(); .toList();
return icons; return iconUrls;
} }
@override @override
@ -127,8 +143,8 @@ class IconGallery extends StatelessWidget {
return GridView.count( return GridView.count(
padding: const EdgeInsets.all(20), padding: const EdgeInsets.all(20),
crossAxisCount: 5, crossAxisCount: 5,
children: (snapshot.data ?? []).map((String icon) { children: (snapshot.data ?? []).map((String iconUrl) {
return IconOption(icon, setIcon); return IconOption(iconUrl, setIcon);
}).toList(), }).toList(),
); );
} else { } else {
@ -142,10 +158,11 @@ class IconGallery extends StatelessWidget {
} }
class IconOption extends StatelessWidget { class IconOption extends StatelessWidget {
final String icon; final String iconUrl;
final Function setIcon; final Function setIcon;
IconOption(this.icon, this.setIcon, {Key? key}) : super(key: ValueKey(icon)); IconOption(this.iconUrl, this.setIcon, {Key? key})
: super(key: ValueKey(iconUrl));
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -153,9 +170,9 @@ class IconOption extends StatelessWidget {
color: Colors.transparent, color: Colors.transparent,
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
setIcon(icon); setIcon(iconUrl);
}, },
child: svgWidget('emoji/$icon'), child: svgWidget('emoji/$iconUrl'),
), ),
); );
} }

View File

@ -0,0 +1 @@
ALTER TABLE user_table DROP COLUMN icon_url;

View File

@ -0,0 +1 @@
ALTER TABLE user_table ADD COLUMN icon_url TEXT NOT NULL DEFAULT '';

View File

@ -87,8 +87,8 @@ table! {
name -> Text, name -> Text,
token -> Text, token -> Text,
email -> Text, email -> Text,
icon -> Text,
workspace -> Text, workspace -> Text,
icon_url -> Text,
} }
} }

View File

@ -27,7 +27,7 @@ pub struct UserProfilePB {
pub token: String, pub token: String,
#[pb(index = 5)] #[pb(index = 5)]
pub icon: String, pub icon_url: String,
} }
#[derive(ProtoBuf, Default)] #[derive(ProtoBuf, Default)]
@ -45,7 +45,7 @@ pub struct UpdateUserProfilePayloadPB {
pub password: Option<String>, pub password: Option<String>,
#[pb(index = 5, one_of)] #[pb(index = 5, one_of)]
pub icon: Option<String>, pub icon_url: Option<String>,
} }
impl UpdateUserProfilePayloadPB { impl UpdateUserProfilePayloadPB {
@ -71,8 +71,8 @@ impl UpdateUserProfilePayloadPB {
self self
} }
pub fn icon(mut self, icon: &str) -> Self { pub fn icon_url(mut self, icon_url: &str) -> Self {
self.icon = Some(icon.to_owned()); self.icon_url = Some(icon_url.to_owned());
self self
} }
} }
@ -92,7 +92,7 @@ pub struct UpdateUserProfileParams {
pub password: Option<String>, pub password: Option<String>,
#[pb(index = 5, one_of)] #[pb(index = 5, one_of)]
pub icon: Option<String>, pub icon_url: Option<String>,
} }
impl UpdateUserProfileParams { impl UpdateUserProfileParams {
@ -102,7 +102,7 @@ impl UpdateUserProfileParams {
name: None, name: None,
email: None, email: None,
password: None, password: None,
icon: None, icon_url: None,
} }
} }
@ -121,8 +121,8 @@ impl UpdateUserProfileParams {
self self
} }
pub fn icon(mut self, icon: &str) -> Self { pub fn icon_url(mut self, icon_url: &str) -> Self {
self.icon = Some(icon.to_owned()); self.icon_url = Some(icon_url.to_owned());
self self
} }
} }
@ -148,9 +148,9 @@ impl TryInto<UpdateUserProfileParams> for UpdateUserProfilePayloadPB {
Some(password) => Some(UserPassword::parse(password)?.0), Some(password) => Some(UserPassword::parse(password)?.0),
}; };
let icon = match self.icon { let icon_url = match self.icon_url {
None => None, None => None,
Some(icon) => Some(UserIcon::parse(icon)?.0), Some(icon_url) => Some(UserIcon::parse(icon_url)?.0),
}; };
Ok(UpdateUserProfileParams { Ok(UpdateUserProfileParams {
@ -158,7 +158,7 @@ impl TryInto<UpdateUserProfileParams> for UpdateUserProfilePayloadPB {
name, name,
email, email,
password, password,
icon, icon_url,
}) })
} }
} }

View File

@ -81,8 +81,8 @@ pub struct UserTable {
pub(crate) name: String, pub(crate) name: String,
pub(crate) token: String, pub(crate) token: String,
pub(crate) email: String, pub(crate) email: String,
pub(crate) icon: String,
pub(crate) workspace: String, // deprecated pub(crate) workspace: String, // deprecated
pub(crate) icon_url: String,
} }
impl UserTable { impl UserTable {
@ -92,7 +92,7 @@ impl UserTable {
name, name,
email, email,
token, token,
icon: "".to_owned(), icon_url: "".to_owned(),
workspace: "".to_owned(), workspace: "".to_owned(),
} }
} }
@ -122,7 +122,7 @@ impl std::convert::From<UserTable> for UserProfilePB {
email: table.email, email: table.email,
name: table.name, name: table.name,
token: table.token, token: table.token,
icon: table.icon, icon_url: table.icon_url,
} }
} }
} }
@ -134,7 +134,7 @@ pub struct UserTableChangeset {
pub workspace: Option<String>, // deprecated pub workspace: Option<String>, // deprecated
pub name: Option<String>, pub name: Option<String>,
pub email: Option<String>, pub email: Option<String>,
pub icon: Option<String>, pub icon_url: Option<String>,
} }
impl UserTableChangeset { impl UserTableChangeset {
@ -144,7 +144,7 @@ impl UserTableChangeset {
workspace: None, workspace: None,
name: params.name, name: params.name,
email: params.email, email: params.email,
icon: params.icon, icon_url: params.icon_url,
} }
} }
} }