Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Post page UI foundation #143

Merged
merged 39 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e77a0e1
feat(post-page): add navigation to sample post page
CHOOSEIT Apr 20, 2024
5071444
feat(post_page): add comment and entire post widget
CHOOSEIT Apr 20, 2024
eda6a9f
feat(post_page): add bottom bar in post page
CHOOSEIT Apr 20, 2024
a9a9951
fix(post-page): remove unused import
CHOOSEIT Apr 20, 2024
34005a0
Merge branch 'main' into post-page
CHOOSEIT Apr 24, 2024
d1d0843
feat(post_page): abstract comments data and UI creation
CHOOSEIT Apr 24, 2024
9d75ca0
feat(post_page): abstract app bar content
CHOOSEIT Apr 24, 2024
13eaf6d
refactor(comment_list): move out CommentList widget
CHOOSEIT Apr 24, 2024
6da4675
fix(post_page): remove insignificant paddings
CHOOSEIT Apr 24, 2024
68b3aed
test(post_age): add key to post page widgets
CHOOSEIT Apr 24, 2024
c49f90c
refactor(post_page): refactor to complete post widget
CHOOSEIT Apr 24, 2024
b060f01
test(post_page): add static test for non-comment widgets post page
CHOOSEIT Apr 24, 2024
74cefd2
feat(post_page): close keyboard upon clicking on send button
CHOOSEIT Apr 24, 2024
e8c1259
fix(post_page): fix comments post widget key duplicate issue
CHOOSEIT Apr 24, 2024
acd14c7
test(comments): add a list of mock comments
CHOOSEIT Apr 24, 2024
a7d6ba3
feat(post_page): add comment list provider
CHOOSEIT Apr 24, 2024
47d7bec
test(post_page): add comments widget test
CHOOSEIT Apr 24, 2024
a7c5653
test(comment_post): test hash and equality
CHOOSEIT Apr 24, 2024
73a13a8
test(comment_post_test): add inequality tests
CHOOSEIT Apr 24, 2024
9ad1f9c
feat(post_page): add todo comment
CHOOSEIT Apr 24, 2024
d1b130c
Merge branch 'main' into post-page
CHOOSEIT Apr 24, 2024
b1458bc
Merge branch 'votes-viewmodel' into post-page
CHOOSEIT Apr 24, 2024
468f984
fix(post-page): adapt to new base
CHOOSEIT Apr 24, 2024
fe1b718
Merge branch 'votes-viewmodel' into post-page
CHOOSEIT Apr 24, 2024
6fc0a8f
Merge branch 'votes-viewmodel' into post-page
CHOOSEIT Apr 24, 2024
f04788f
Merge branch 'votes-viewmodel' into post-page
CHOOSEIT Apr 25, 2024
37c9cb2
Merge branch 'votes-viewmodel' into post-page
gruvw Apr 25, 2024
e529067
fix(format): apply dart format suggestion
gruvw Apr 25, 2024
290bd09
fix(post_page): extract string to named constant
CHOOSEIT Apr 25, 2024
6e857c9
Merge branch 'votes-viewmodel' into post-page
CHOOSEIT Apr 25, 2024
7ed005d
fix(post_page): remove unnecessary Center and Row widget.
CHOOSEIT Apr 25, 2024
e732790
Merge branch 'main' into post-page
CHOOSEIT Apr 25, 2024
52b9eaa
doc(post_page): move comments for better readability.
CHOOSEIT Apr 25, 2024
31377ab
refactor(post_page): remove unnecessary complexity caused by a comma
CHOOSEIT Apr 25, 2024
4d7f081
test(post_page): add test for post displayed information & replace ho…
CHOOSEIT Apr 25, 2024
9e33554
fix(post_page_test): remove unused import
CHOOSEIT Apr 25, 2024
ebb6c71
test(post_page_test): add test to check correct displayed username on…
CHOOSEIT Apr 25, 2024
f5ba930
Merge branch 'main' into post-page
CHOOSEIT Apr 25, 2024
23369bb
test(post_page): remove small typo widgetswidgets
CHOOSEIT Apr 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/models/ui/comment_post.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import "package:flutter/foundation.dart";

@immutable
class CommentPost {
final String content;
final String ownerDisplayName;

const CommentPost({
required this.content,
required this.ownerDisplayName,
});

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is CommentPost &&
other.content == content &&
other.ownerDisplayName == ownerDisplayName;
}

@override
int get hashCode {
return Object.hash(
content,
ownerDisplayName,
);
}
}
7 changes: 7 additions & 0 deletions lib/viewmodels/post_view_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:proxima/models/ui/comment_post.dart";

// This provider is used to store the list of comments that are displayed in the post page.
final commentListProvider = Provider<List<CommentPost>>((ref) {
return List.empty();
});
13 changes: 8 additions & 5 deletions lib/views/home_content/feed/post_card/post_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "package:proxima/models/ui/post_overview.dart";
import "package:proxima/views/home_content/feed/post_card/comment_widget.dart";
import "package:proxima/views/home_content/feed/post_card/user_bar_widget.dart";
import "package:proxima/views/home_content/feed/post_card/votes_widget.dart";
import "package:proxima/views/navigation/routes.dart";

/// This widget is used to display the post card in the home feed.
/// It contains the post title, description, votes, comments
Expand All @@ -23,6 +24,10 @@ class PostCard extends StatelessWidget {
required this.postOverview,
});

void _onPostSelect(BuildContext context, PostOverview post) {
Navigator.pushNamed(context, Routes.post.name, arguments: post);
}

@override
Widget build(BuildContext context) {
final postBody = ListTile(
Expand Down Expand Up @@ -53,8 +58,7 @@ class PostCard extends StatelessWidget {
customBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
//TODO: Implement the logic to navigate to the post
onTap: () => {},
onTap: () => _onPostSelect(context, postOverview),
child: CommentWidget(
key: postCardCommentsKey,
commentNumber: postOverview.commentNumber,
Expand All @@ -69,13 +73,12 @@ class PostCard extends StatelessWidget {
key: postCardKey,
clipBehavior: Clip.hardEdge,
child: InkWell(
//TODO: Implement the logic to navigate to the post
onTap: () => {},
onTap: () => _onPostSelect(context, postOverview),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 16, right: 0.8, top: 8),
padding: const EdgeInsets.only(left: 16, top: 8),
child: UserBarWidget(
key: postCardUserKey,
posterUsername: postOverview.ownerDisplayName,
Expand Down
7 changes: 6 additions & 1 deletion lib/views/home_content/feed/post_card/user_bar_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import "package:flutter/material.dart";
/// This widget is used to display the user bar in the post card.
/// It contains the user's profile picture and username.
class UserBarWidget extends StatelessWidget {
static const displayNameTextKey = Key("displayNameText");

const UserBarWidget({
super.key,
required this.posterUsername,
Expand All @@ -21,7 +23,10 @@ class UserBarWidget extends StatelessWidget {
),
Padding(
padding: const EdgeInsets.only(left: 8),
child: Text(posterUsername),
child: Text(
key: displayNameTextKey,
posterUsername,
),
),
],
);
Expand Down
2 changes: 1 addition & 1 deletion lib/views/home_content/feed/post_card/votes_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class VotesWidget extends HookConsumerWidget {
child: Padding(
padding: const EdgeInsets.all(3),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.start,
children: [
upvote,
downvote,
Expand Down
13 changes: 12 additions & 1 deletion lib/views/navigation/routes.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import "package:flutter/material.dart";
import "package:proxima/models/ui/post_overview.dart";
import "package:proxima/views/pages/create_account_page.dart";
import "package:proxima/views/pages/home/home_page.dart";
import "package:proxima/views/pages/login/login_page.dart";
import "package:proxima/views/pages/new_post/new_post_page.dart";
import "package:proxima/views/pages/post/post_page.dart";
import "package:proxima/views/pages/profile/profile_page.dart";

enum Routes {
home("home"),
login("login"),
profile("profile"),
newPost("new post"),
createAccount("createAccount");
createAccount("createAccount"),
post("post");

final String name;

Expand All @@ -32,6 +35,14 @@ enum Routes {
return const NewPostPage();
case createAccount:
return const CreateAccountPage();
case post:
if (args is PostOverview) {
return PostPage(
postOverview: args,
);
} else {
throw Exception("PostOverview object required");
}
}
}
}
Expand Down
83 changes: 83 additions & 0 deletions lib/views/pages/post/post_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import "package:flutter/material.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:proxima/models/ui/post_overview.dart";
import "package:proxima/viewmodels/post_view_model.dart";
import "package:proxima/views/navigation/leading_back_button/leading_back_button.dart";
import "package:proxima/views/pages/post/post_page_widget/bottom_bar_add_comment.dart";
import "package:proxima/views/pages/post/post_page_widget/comment_list.dart";
import "package:proxima/views/pages/post/post_page_widget/complete_post_widget.dart";

class PostPage extends HookConsumerWidget {
static const postDistanceKey = Key("postDistance");
static const completePostWidgetKey = Key("completePostWidget");
static const commentListWidgetKey = Key("commentListWidget");
static const bottomBarAddCommentKey = Key("bottomBarAddComment");

static const _appBarTitle = "Post";

const PostPage({
super.key,
required this.postOverview,
});

final PostOverview postOverview;

@override
Widget build(BuildContext context, WidgetRef ref) {
ThemeData themeData = Theme.of(context);

final comments = ref.watch(commentListProvider);

List<Widget> appBarContent = [
const Text(_appBarTitle),
Text(
key: postDistanceKey,
//TODO: Add distance to post
"50m away",
style: themeData.textTheme.titleSmall,
),
];

List<Widget> bodyChildren = [
CompletePostWidget(
key: completePostWidgetKey,
post: postOverview,
),
const SizedBox(height: 10),
CommentList(
key: commentListWidgetKey,
comments: comments,
),
];

return Scaffold(
appBar: AppBar(
leading: const LeadingBackButton(),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: appBarContent,
),
),
body: Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8),
child: Center(
child: ListView(
children: bodyChildren,
),
),
),
persistentFooterButtons: [
Padding(
padding:
// This is necessary to prevent the keyboard from covering the bottom bar
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: const BottomBarAddComment(
key: bottomBarAddCommentKey,
//TODO: Replace with actual username
currentDisplayName: "Username",
),
),
],
);
}
}
58 changes: 58 additions & 0 deletions lib/views/pages/post/post_page_widget/bottom_bar_add_comment.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import "package:flutter/material.dart";

class BottomBarAddComment extends StatelessWidget {
static const commentUserAvatarKey = Key("commentUserAvatar");
static const addCommentTextFieldKey = Key("addCommentTextField");
static const postCommentButtonKey = Key("postCommentButton");

static const _textFieldHintAddComment = "Add a comment";

final String currentDisplayName;

const BottomBarAddComment({
super.key,
required this.currentDisplayName,
});

@override
Widget build(BuildContext context) {
return Row(
// Align items to the start of the cross axis
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(right: 8),
child: CircleAvatar(
key: commentUserAvatarKey,
radius: 22,
child: Text(currentDisplayName.substring(0, 1)),
),
CHOOSEIT marked this conversation as resolved.
Show resolved Hide resolved
),
const Expanded(
child: TextField(
key: addCommentTextFieldKey,
minLines: 1,
maxLines: 5,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
border: OutlineInputBorder(),
hintText: _textFieldHintAddComment,
),
),
),
Align(
// Keeps the IconButton centered in the cross axis
alignment: Alignment.center,
child: IconButton(
key: postCommentButtonKey,
icon: const Icon(Icons.send),
onPressed: () {
//TODO: handle add comment
FocusManager.instance.primaryFocus?.unfocus();
},
),
),
],
);
}
}
25 changes: 25 additions & 0 deletions lib/views/pages/post/post_page_widget/comment_list.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import "package:flutter/material.dart";
import "package:proxima/models/ui/comment_post.dart";
import "package:proxima/views/pages/post/post_page_widget/comment_post_widget.dart";

class CommentList extends StatelessWidget {
const CommentList({
super.key,
required this.comments,
});

final List<CommentPost> comments;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 16, right: 16),
child: Wrap(
runSpacing: 15,
children: comments
.map((comment) => CommentPostWidget(commentPost: comment))
.toList(),
),
);
}
}
38 changes: 38 additions & 0 deletions lib/views/pages/post/post_page_widget/comment_post_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import "package:flutter/material.dart";
import "package:proxima/models/ui/comment_post.dart";

import "package:proxima/views/home_content/feed/post_card/user_bar_widget.dart";

class CommentPostWidget extends StatelessWidget {
static const commentWidgetKey = Key("commentWidget");
static const commentUserWidgetKey = Key("commentUserWidget");
static const commentContentKey = Key("commentContent");

final CommentPost commentPost;

const CommentPostWidget({
super.key,
required this.commentPost,
});

@override
Widget build(BuildContext context) {
return Column(
key: commentWidgetKey,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
UserBarWidget(
key: commentUserWidgetKey,
posterUsername: commentPost.ownerDisplayName,
),
Padding(
padding: const EdgeInsets.only(left: 32, top: 8),
child: Text(
key: commentContentKey,
commentPost.content,
),
),
],
);
}
}
Loading