lemmur-app-android/lib/widgets/user_profile.dart

287 lines
10 KiB
Dart

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:intl/intl.dart';
import 'package:lemmy_api_client/lemmy_api_client.dart';
import 'package:timeago/timeago.dart' as timeago;
import '../util/api_extensions.dart';
import '../util/goto.dart';
import '../util/intl.dart';
import '../util/text_color.dart';
import 'badge.dart';
class UserProfile extends HookWidget {
final Future<UserView> _userView;
final String instanceUrl;
// TODO: add `.fromUser` constructor
UserProfile({@required int userId, @required this.instanceUrl})
: _userView = LemmyApi(instanceUrl)
.v1
.getUserDetails(
userId: userId, savedOnly: true, sort: SortType.active)
.then((res) => res.user);
UserProfile.fromUserView(UserView userView)
: _userView = Future.value(userView),
instanceUrl = userView.instanceUrl;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorOnTopOfAccentColor =
textColorBasedOnBackground(theme.accentColor);
final userViewSnap = useFuture(_userView, preserveState: false);
Widget bio = () {
if (userViewSnap.hasData) {
if (userViewSnap.data.bio != null) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text(userViewSnap.data.bio),
);
} else {
return Center(
child: Text(
'no bio',
style: const TextStyle(fontStyle: FontStyle.italic),
),
);
}
} else {
return Center(child: CircularProgressIndicator());
}
}();
Widget tabs() => DefaultTabController(
length: 3,
child: Column(
children: [
TabBar(
labelColor: theme.textTheme.bodyText1.color,
tabs: [
Tab(text: 'Posts'),
Tab(text: 'Comments'),
Tab(text: 'About'),
],
),
Expanded(
child: TabBarView(
children: [
Center(
child: Text(
'Posts',
style: const TextStyle(fontSize: 36),
),
),
Center(
child: Text(
'Comments',
style: const TextStyle(fontSize: 36),
),
),
bio,
],
),
)
],
),
);
return Center(
child: Stack(
children: [
if (userViewSnap.data?.banner != null)
CachedNetworkImage(
imageUrl: userViewSnap.data.banner,
errorWidget: (_, __, ___) => Container(),
)
else
Container(
width: double.infinity,
height: double.infinity,
color: theme.primaryColor,
),
Container(
height: 200,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: FractionalOffset.topCenter,
end: FractionalOffset.bottomCenter,
colors: [
Colors.black26,
Colors.transparent,
],
),
),
),
SafeArea(
child: Padding(
padding: const EdgeInsets.only(top: 60),
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(40),
topLeft: Radius.circular(40),
),
color: theme.scaffoldBackgroundColor,
),
),
),
),
),
SafeArea(
child: Column(
children: [
if (userViewSnap.data?.avatar != null)
SizedBox(
width: 80,
height: 80,
child: Container(
// clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(blurRadius: 6, color: Colors.black54)
],
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(color: Colors.white, width: 3),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(12)),
child: CachedNetworkImage(
imageUrl: userViewSnap.data.avatar,
errorWidget: (_, __, ___) => Container(),
),
),
),
),
Padding(
padding: userViewSnap.data?.avatar != null
? const EdgeInsets.only(top: 8.0)
: const EdgeInsets.only(top: 70),
child: Padding(
padding: EdgeInsets.only(
top: userViewSnap.data?.avatar == null ? 10 : 0),
child: Text(
userViewSnap.data?.preferredUsername ??
userViewSnap.data?.name ??
'',
style: theme.textTheme.headline6,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'@${userViewSnap.data?.name ?? ''}@',
style: theme.textTheme.caption,
),
InkWell(
onTap: () => goToInstance(context, instanceUrl),
child: Text(
'$instanceUrl',
style: theme.textTheme.caption,
),
)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Badge(
child: Row(
children: [
Icon(
Icons.comment, // TODO: should be article icon
size: 15,
color: colorOnTopOfAccentColor,
),
Padding(
padding: const EdgeInsets.only(left: 4.0),
child: Text(
'''
${userViewSnap.hasData ? compactNumber(userViewSnap.data.numberOfPosts) : '-'} Post${pluralS(userViewSnap.data?.numberOfPosts ?? 0)}''',
style:
TextStyle(color: colorOnTopOfAccentColor),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 16.0),
child: Badge(
child: Row(
children: [
Icon(
Icons.comment,
size: 15,
color: colorOnTopOfAccentColor,
),
Padding(
padding: const EdgeInsets.only(left: 4.0),
child: Text(
'''
${userViewSnap.hasData ? compactNumber(userViewSnap.data.numberOfComments) : '-'} Comment${pluralS(userViewSnap.data?.numberOfComments ?? 0)}''',
style:
TextStyle(color: colorOnTopOfAccentColor),
),
),
],
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
'''
Joined ${userViewSnap.hasData ? timeago.format(userViewSnap.data.published) : ''}''',
style: theme.textTheme.bodyText1,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.cake,
size: 13,
),
Padding(
padding: const EdgeInsets.only(left: 4.0),
child: Text(
userViewSnap.hasData
? DateFormat('MMM dd, yyyy')
.format(userViewSnap.data.published)
: '',
style: theme.textTheme.bodyText1,
),
),
],
),
),
Expanded(child: tabs())
],
),
),
],
),
);
}
}