Commit a926c991 authored by Daniel Tefr's avatar Daniel Tefr
Browse files

Merge remote-tracking branch 'refs/remotes/origin/master' into code-refactoring

# Conflicts:
#	lib/search/search_page.dart
#	lib/signIn/sign_in_page.dart
#	lib/songPost/detail/song_comment.dart
#	lib/songPost/service/song_post_repository.dart
#	lib/user/profile_page.dart
#	lib/userInteraction/model/comment_DTO.dart
parents 0b0c8b18 89f9571a
Loading
Loading
Loading
Loading
+138 −107
Original line number Diff line number Diff line
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:harmonis/IOC/IOC_containter.dart';
import 'package:harmonis/songPost/post_type.dart';
import 'package:get_it/get_it.dart';
import 'package:harmonis/songPost/service/song_post_service.dart';
import 'package:harmonis/userInteraction/model/comment_DTO.dart';
import 'package:harmonis/common/comment_input_field.dart';

import '../../user/services/userService.dart';
import '../post_type.dart';

class SongComment extends StatefulWidget {
  final CommentDTO comment;
@@ -14,42 +13,69 @@ class SongComment extends StatefulWidget {
  final bool expanded;
  final VoidCallback onExpand;

  const SongComment({
    super.key,
  SongComment({
    Key? key,
    required this.comment,
    required this.songPostUid,
    required this.expanded,
    required this.onExpand,
  });
  }) : super(key: key);

  @override
  State<SongComment> createState() => _SongCommentState();
}

class _SongCommentState extends State<SongComment> {
  final TextEditingController _replyController = TextEditingController();
  final userService = getIt<UserService>();
  String? _authorName;
  final TextEditingController replyController = TextEditingController();
  final SongPostService songPostService = GetIt.instance<SongPostService>();
  final UserService userService = GetIt.instance<UserService>();

  String? authorName;

  @override
  void initState() {
    super.initState();
    _loadAuthorName();
    _fetchAuthorName();
  }

  @override
  void dispose() {
    _replyController.dispose();
    replyController.dispose();
    super.dispose();
  }

  Future<void> _loadAuthorName() async {
  Future<void> _fetchAuthorName() async {
    final user = await userService.getUser(widget.comment.authorUId);
    setState(() {
      _authorName = user?.name;
      authorName = user?.name;
    });
  }

  Future<void> _addReply(String commentId, String replyText) async {
    if (replyText.trim().isEmpty) return;

    final currentUser = FirebaseAuth.instance.currentUser;
    if (currentUser == null) {
      return;
    }

    final reply = CommentDTO(
      uid: null,
      text: replyText.trim(),
      authorUId: currentUser.uid,
      postType: PostType.comment,
      replies: [],
      timeStamp: DateTime.now(),
    );

    try {
      await songPostService.addReply(widget.songPostUid, commentId, reply);
      replyController.clear();
    } catch (e) {
      print('Failed to add reply: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
@@ -71,7 +97,27 @@ class _SongCommentState extends State<SongComment> {
                  radius: 20,
                ),
                const SizedBox(width: 12),
                _buildAuthorInfo(context),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        authorName ?? widget.comment.authorUId,
                        style: Theme.of(context)
                            .textTheme
                            .bodyMedium
                            ?.copyWith(fontWeight: FontWeight.normal),
                      ),
                      Text(
                        '${widget.comment.timeStamp.hour.toString().padLeft(2, '0')}:${widget.comment.timeStamp.minute.toString().padLeft(2, '0')} on ${widget.comment.timeStamp.day}/${widget.comment.timeStamp.month}/${widget.comment.timeStamp.year}',
                        style: Theme.of(context)
                            .textTheme
                            .bodySmall
                            ?.copyWith(color: Colors.grey[600]),
                      ),
                    ],
                  ),
                ),
                IconButton(
                  icon: Icon(
                    widget.expanded ? Icons.expand_less : Icons.expand_more,
@@ -88,101 +134,86 @@ class _SongCommentState extends State<SongComment> {
            ),
            if (widget.expanded) ...[
              const SizedBox(height: 8),
              _buildReplies(context),
              _buildReplyInputField(),
            ],
          ],
        ),
      ),
              StreamBuilder<List<CommentDTO>>(
                stream: songPostService.getReplies(widget.songPostUid, widget.comment.uid!),
                builder: (context, snapshot) {
                  if (snapshot.hasError) {
                    return Text(
                      'Error loading replies.',
                      style: TextStyle(color: Colors.red),
                    );
                  }

  Widget _buildAuthorInfo(BuildContext context) {
    return Expanded(
                  if (!snapshot.hasData) {
                    return Center(child: CircularProgressIndicator());
                  }
                  final replies = snapshot.data!;
                  if (replies.isEmpty) {
                    return Text(
                      'No replies yet',
                      style: TextStyle(color: Colors.grey[600]),
                    );
                  }
                  return Column(
                    children: replies.map((reply) {
                      return Padding(
                        padding: const EdgeInsets.only(bottom: 8.0, left: 4.0, right: 4.0),
                        child: Row(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Icon(Icons.reply, size: 16, color: Colors.grey),
                            const SizedBox(width: 8),
                            Expanded(
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
            _authorName ?? widget.comment.authorUId,
                                    reply.authorUId,
                                    style: Theme.of(context)
                                        .textTheme
                .bodyMedium
                ?.copyWith(fontWeight: FontWeight.normal),
                                        .bodySmall
                                        ?.copyWith(color: Colors.grey[600], fontWeight: FontWeight.normal),
                                  ),
                                  const SizedBox(height: 2),
                                  Text(
            _formatTimestamp(widget.comment.timeStamp),
                                    reply.text,
                                    style: Theme.of(context)
                                        .textTheme
                .bodySmall
                ?.copyWith(color: Colors.grey[600]),
          ),
        ],
                                        .bodyLarge
                                        ?.copyWith(color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.normal),
                                  ),
    );
  }

  String _formatTimestamp(DateTime timestamp) {
    return '${timestamp.hour.toString().padLeft(2, '0')}:${timestamp.minute.toString().padLeft(2, '0')} on ${timestamp.day}/${timestamp.month}/${timestamp.year}';
  }

  Widget _buildReplies(BuildContext context) {
    return Column(
      children: widget.comment.replies
          .map((reply) => Padding(
                padding: const EdgeInsets.only(bottom: 8.0),
                child: Row(
                  children: [
                    const Icon(Icons.reply, size: 16, color: Colors.grey),
                    const SizedBox(width: 8),
                    Expanded(
                      child: Text(
                        reply.text,
                                  const SizedBox(height: 2),
                                  Text(
                                    '${reply.timeStamp.hour.toString().padLeft(2, '0')}:${reply.timeStamp.minute.toString().padLeft(2, '0')} on ${reply.timeStamp.day}/${reply.timeStamp.month}/${reply.timeStamp.year}',
                                    style: Theme.of(context)
                                        .textTheme
                            .bodyLarge
                                        .bodySmall
                                        ?.copyWith(color: Colors.grey[600]),
                                  ),
                                  const SizedBox(height: 8),
                                ],
                              ),
                            ),
                          ],
                        ),
              ))
          .toList(),
                      );
  }

  Widget _buildReplyInputField() {
    return CommentInputField(
      controller: _replyController,
                    }).toList(),
                  );
                },
              ),
              const SizedBox(height: 8),
              CommentInputField(
                controller: replyController,
                onSend: () {
        final replyText = _replyController.text.trim();
                  final replyText = replyController.text.trim();
                  if (replyText.isNotEmpty) {
          _addReply(replyText);
          _replyController.clear();
                    _addReply(widget.comment.uid!, replyText);
                  }
                },
    );
  }

  void _addReply(String replyText) {
    if (replyText.trim().isEmpty) return;

    final newReply = _createReply(replyText.trim());
    getIt<SongPostService>()
        .addReply(widget.songPostUid, widget.comment.uid!, newReply);

    setState(() {
      widget.comment.replies.add(newReply);
    });
  }

  CommentDTO _createReply(String replyText) {
    return CommentDTO(
      uid: DateTime.now().toString(),
      text: replyText,
      authorUId: FirebaseAuth.instance.currentUser!.uid,
      postType: PostType.songPost,
      replies: [],
      timeStamp: DateTime.now(),
              ),
            ],
          ],
        ),
      ),
    );
  }
}
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ class AddSongPostPage extends StatelessWidget {

    return PageTemplate(
      body: Padding(
          padding: const EdgeInsets.all(16.0),
          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
+20 −0
Original line number Diff line number Diff line
@@ -150,4 +150,24 @@ class SongPostRepository extends ApiRepository<SongPostDTO> {
  SongPostDTO fromJson(Map<String, dynamic> json) {
    return SongPostDTO.fromJson(json);
  }

  Stream<List<CommentDTO>> getRepliesForComment(String songPostId, String commentId) {
    return fireStore
        .collection('songPosts')
        .doc(songPostId)
        .collection('comments')
        .doc(commentId)
        .collection('replies')
        .orderBy('timeStamp', descending: false)
        .snapshots()
        .map((snapshot) {
      return snapshot.docs.map((doc) {
        final data = doc.data();
        return CommentDTO.fromJson(data).copyWith(uid: doc.id);
      }).toList();
    }).handleError((error) {
      print('Error fetching replies for comment $commentId: $error');
      return [];
    });
  }
}
+6 −2
Original line number Diff line number Diff line
@@ -91,6 +91,10 @@ class SongPostService {
    }
  }

  Stream<List<CommentDTO>> getReplies(String songPostId, String commentId) {
    return songPostRepository.getRepliesForComment(songPostId, commentId);
  }

  Stream<Comments> getComments(String postUid) {
    return songPostRepository.getCommentsForSongPost(postUid);
  }
@@ -126,8 +130,8 @@ class SongPostService {
    return false;
  }

  void addReply(String postId, String commentId, CommentDTO reply) {
    songPostRepository.addReplyToComment(postId, commentId, reply);
  Future<void> addReply(String postId, String commentId, CommentDTO reply) async {
    await songPostRepository.addReplyToComment(postId, commentId, reply);
  }

  Future<void> deleteSongPost(String postId) async {