diff --git a/backend/src/main/java/com/backend/backend/fightGame/Dto/FightGameDto.java b/backend/src/main/java/com/backend/backend/fightGame/Dto/FightGameDto.java new file mode 100644 index 0000000..622a4d8 --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/Dto/FightGameDto.java @@ -0,0 +1,29 @@ +package com.backend.backend.fightGame.Dto; + +import com.backend.backend.fightGame.FightGame.Move; +import com.backend.backend.user.Dto.UserDto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FightGameDto { + private Long id; + private Integer winnerID; + private Long requesterID; + private UserDto user1; + private UserDto user2; + private Integer user1HP; + private Integer user2HP; + private List user1Moves; + private List user2Moves; +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/Dto/UserMoveDto.java b/backend/src/main/java/com/backend/backend/fightGame/Dto/UserMoveDto.java new file mode 100644 index 0000000..70d3b8a --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/Dto/UserMoveDto.java @@ -0,0 +1,15 @@ +package com.backend.backend.fightGame.Dto; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import com.backend.backend.fightGame.FightGame.Move; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class UserMoveDto { + private Long userID; + Move move; +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/FightGame.java b/backend/src/main/java/com/backend/backend/fightGame/FightGame.java new file mode 100644 index 0000000..222566a --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/FightGame.java @@ -0,0 +1,110 @@ +package com.backend.backend.fightGame; +import jakarta.persistence.CascadeType; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKeyColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import com.backend.backend.user.User; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "fight_games") +public class FightGame { + + public enum Move { + ATTACK, + DEFENSE, + MAGIC, + NONE + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // Until someone wins: 0 + // If they draw: -1 + @Column(name = "winner_id") + private Integer winnerID; + + @Column(name = "requester_id") + private Long requesterID; + + @ManyToOne + @JoinColumn(name = "fight_game_session_user_1") + private User user1; + + @ManyToOne + @JoinColumn(name = "fight_game_session_user_2") + private User user2; + + // Starts at 5? + @Column(name = "user_1_hp") + private Integer user1HP; + + @Column(name = "user_2_hp") + private Integer user2HP; + + @ElementCollection(targetClass = Move.class) + @CollectionTable(name = "game_user_1_moves", joinColumns = @JoinColumn(name = "game_id")) + @Column(name = "user_1_move") + @Enumerated(EnumType.STRING) + private List user1Moves; + + @ElementCollection(targetClass = Move.class) + @CollectionTable(name = "game_user_2_moves", joinColumns = @JoinColumn(name = "game_id")) + @Enumerated(EnumType.STRING) + @Column(name = "user_2_move") + private List user2Moves; + + @PrePersist + protected void onCreate() { + this.winnerID = 0; + this.user1HP = 5; + this.user2HP = 5; + this.user1Moves = Arrays.asList(Move.NONE); + this.user2Moves = Arrays.asList(Move.NONE); + } + + public Boolean doesMoveHit(Move user1Move, Move user2Move) { + if (user1Move != Move.DEFENSE) { + if (user1Move == user2Move) { + return true; + } + if (user1Move == Move.ATTACK && user2Move == Move.MAGIC) { + return true; + } + if (user1Move == Move.MAGIC && user2Move == Move.DEFENSE) { + return true; + } + } + return false; + } +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/FightGameController.java b/backend/src/main/java/com/backend/backend/fightGame/FightGameController.java new file mode 100644 index 0000000..db78979 --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/FightGameController.java @@ -0,0 +1,69 @@ +package com.backend.backend.fightGame; + +import com.backend.backend.fightGame.Dto.FightGameDto; +import com.backend.backend.friendrequest.FriendRequestDto; +import com.backend.backend.fightGame.FightGame.Move; +import com.backend.backend.fightGame.FightGameService; +import com.backend.backend.user.User; +import com.backend.backend.user.UserMapper; +import com.backend.backend.user.Dto.UserDto; +import com.backend.backend.fightGame.Dto.UserMoveDto; + +import java.util.List; +import java.util.Map; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@RestController +@RequestMapping("/api/fightgames") +@AllArgsConstructor +@CrossOrigin(origins = "*") +public class FightGameController { + private FightGameService fightGameService; + + @PostMapping + public ResponseEntity createFightGame(@RequestBody FightGameDto fightGameDto) { + Long user1 = fightGameDto.getUser1().getId(); + Long user2 = fightGameDto.getUser2().getId(); + Long requesterID = fightGameDto.getRequesterID(); + FightGameDto savedFightGame = fightGameService.createFightGame(user1, user2, requesterID); + return new ResponseEntity<>(savedFightGame, HttpStatus.CREATED); + } + + @GetMapping("{user1ID}/{user2ID}") + public ResponseEntity getFightGame(@PathVariable("user1ID") Long user1ID, @PathVariable("user2ID") Long user2ID) { + FightGameDto fightGameDto = fightGameService.getFightGame(user1ID, user2ID); + return new ResponseEntity<>(fightGameDto, HttpStatus.OK); + } + + @PutMapping("{id}/setMove") + public ResponseEntity setMove(@PathVariable("id") Long id, @RequestBody UserMoveDto userMoveDto) { + FightGameDto updatedGame = fightGameService.setMove(id, userMoveDto); + return new ResponseEntity<>(updatedGame, HttpStatus.OK); + } + + @PutMapping("newTurn") + public ResponseEntity setNewTurn(@RequestBody FightGameDto fightGameDto) { + long id = fightGameDto.getId(); + FightGameDto updatedGame = fightGameService.setNewTurn(id); + return new ResponseEntity<>(updatedGame, HttpStatus.OK); + } + + @PutMapping("{id}/winner") + public ResponseEntity declareWinner(@PathVariable("id") Long id) { + FightGameDto updatedGame = fightGameService.declareWinner(id); + return new ResponseEntity<>(updatedGame, HttpStatus.OK); + } + +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/FightGameMapper.java b/backend/src/main/java/com/backend/backend/fightGame/FightGameMapper.java new file mode 100644 index 0000000..b4465a8 --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/FightGameMapper.java @@ -0,0 +1,44 @@ +package com.backend.backend.fightGame; + +import java.util.stream.Collectors; + +import com.backend.backend.fightGame.Dto.FightGameDto; +import com.backend.backend.fightGame.Dto.UserMoveDto; +import com.backend.backend.user.UserMapper; +import com.backend.backend.user.Dto.UserDto; +import com.backend.backend.user.User; +import java.util.List; + +public class FightGameMapper { + public static FightGameDto mapToFightGameDto(FightGame fightGame) { + UserDto user1 = UserMapper.mapToUserDto(fightGame.getUser1()); + UserDto user2 = UserMapper.mapToUserDto(fightGame.getUser2()); + return new FightGameDto( + fightGame.getId(), + fightGame.getWinnerID(), + fightGame.getRequesterID(), + user1, + user2, + fightGame.getUser1HP(), + fightGame.getUser2HP(), + fightGame.getUser1Moves(), + fightGame.getUser2Moves() + ); + } + + public static FightGame mapToFightGame(FightGameDto fightGameDto) { + User user1 = UserMapper.mapToUser(fightGameDto.getUser1()); + User user2 = UserMapper.mapToUser(fightGameDto.getUser2()); + return new FightGame( + fightGameDto.getId(), + fightGameDto.getWinnerID(), + fightGameDto.getRequesterID(), + user1, + user2, + fightGameDto.getUser1HP(), + fightGameDto.getUser2HP(), + fightGameDto.getUser1Moves(), + fightGameDto.getUser2Moves() + ); + } +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/FightGameRepository.java b/backend/src/main/java/com/backend/backend/fightGame/FightGameRepository.java new file mode 100644 index 0000000..6e93a0b --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/FightGameRepository.java @@ -0,0 +1,12 @@ +package com.backend.backend.fightGame; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import com.backend.backend.user.User; +import java.util.Optional; +import java.util.List; + +@Repository +public interface FightGameRepository extends JpaRepository { + List findByUser1AndUser2(User user1, User user2); +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/FightGameService.java b/backend/src/main/java/com/backend/backend/fightGame/FightGameService.java new file mode 100644 index 0000000..0e992da --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/FightGameService.java @@ -0,0 +1,17 @@ +package com.backend.backend.fightGame; + +import java.util.List; +import java.util.Map; + +import com.backend.backend.fightGame.FightGame.Move; +import com.backend.backend.fightGame.Dto.FightGameDto; +import com.backend.backend.fightGame.Dto.UserMoveDto; + +public interface FightGameService { + FightGameDto createFightGame(long user1, long user2, long requesterID); + FightGameDto getFightGame(long user1ID, long user2ID); + FightGameDto declareWinner(long id); + FightGameDto setMove(long id, UserMoveDto userMoveDto); + Boolean doesMoveHit(Move user1Move, Move user2Move); + FightGameDto setNewTurn(long id); +} diff --git a/backend/src/main/java/com/backend/backend/fightGame/FightGameServiceImpl.java b/backend/src/main/java/com/backend/backend/fightGame/FightGameServiceImpl.java new file mode 100644 index 0000000..5aa0d64 --- /dev/null +++ b/backend/src/main/java/com/backend/backend/fightGame/FightGameServiceImpl.java @@ -0,0 +1,203 @@ +package com.backend.backend.fightGame; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.backend.backend.ResourceNotFoundException; +import com.backend.backend.chatroom.ChatroomRepository; +import com.backend.backend.chatroom.ChatroomService; +import com.backend.backend.chatroom.Dto.ChatroomDto; +import com.backend.backend.fightGame.FightGame; +import com.backend.backend.user.UserMapper; +import com.backend.backend.user.UserRepository; +import com.backend.backend.user.UserService; +import com.backend.backend.user.User; +import com.backend.backend.user.Dto.FriendDto; +import com.backend.backend.user.Dto.UserDto; +import com.backend.backend.friendrequest.FriendRequest; +import com.backend.backend.friendrequest.FriendRequestMapper; + +import lombok.AllArgsConstructor; + +import com.backend.backend.fightGame.Dto.FightGameDto; +import com.backend.backend.fightGame.Dto.UserMoveDto; +import com.backend.backend.user.Dto.GamerScoreDto; +import com.backend.backend.friendrequest.FriendRequestRepository; +import com.backend.backend.friendrequest.FriendRequestService; +import com.backend.backend.fightGame.FightGame.Move; + +@Service +@AllArgsConstructor +public class FightGameServiceImpl implements FightGameService{ + private FightGameRepository fightGameRepository; + private FriendRequestRepository friendRequestRepository; + private FriendRequestService friendRequestService; + private UserRepository userRepository; + private UserService userService; + private ChatroomService chatroomService; + + // START OF ALL CREATE + + @Override + public FightGameDto createFightGame(long user1ID, long user2ID, long requesterID) { + User user1 = userRepository.findById(user1ID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + user1ID)); + User user2 = userRepository.findById(user2ID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + user2ID)); + if (requesterID != 0 && requesterID != user1ID && requesterID != user2ID) { + throw new ResourceNotFoundException("A faulty request id was given"); + } + FightGame fightGame = new FightGame(); + fightGame.setUser1(user1); + fightGame.setUser2(user2); + fightGame.setRequesterID(requesterID); + FightGame savedGame = fightGameRepository.save(fightGame); + userService.addGameSession(user1ID, user2ID, FightGameMapper.mapToFightGameDto(fightGame)); + return FightGameMapper + .mapToFightGameDto(savedGame); + } + + @Override + public FightGameDto getFightGame(long user1ID, long user2ID) { + User user1 = userRepository.findById(user1ID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + user1ID)); + User user2 = userRepository.findById(user2ID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + user2ID)); + List fightGames = fightGameRepository.findByUser1AndUser2(user1, user2); + if (fightGames.isEmpty()) { + fightGames = fightGameRepository.findByUser1AndUser2(user2, user1); + if (fightGames.isEmpty()) { + throw new ResourceNotFoundException("FightGame not found " + user1ID + " " + user2ID); + } + } + FightGame fightGame = fightGames.get(fightGames.size()-1); + return FightGameMapper.mapToFightGameDto(fightGame); + } + + @Override + public FightGameDto setMove(long id, UserMoveDto userMove) { + FightGame fightGame = fightGameRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Game not found " + id)); + List moves; + if (userMove.getUserID() == fightGame.getUser1().getId()) { + moves = fightGame.getUser1Moves(); + } + else if (userMove.getUserID() == fightGame.getUser2().getId()) { + moves = fightGame.getUser2Moves(); + } + else { + throw new ResourceNotFoundException(userMove.getUserID() + " Is not a member of game " + id); + } + if (userMove.getMove() == null) { + throw new ResourceNotFoundException("Bad move was given"); + } + moves.set(moves.size() - 1, userMove.getMove()); + if (userMove.getUserID() == fightGame.getUser1().getId()) { + fightGame.setUser1Moves(moves); + } + else { + fightGame.setUser2Moves(moves); + } + FightGame savedGame = fightGameRepository.save(fightGame); + return FightGameMapper + .mapToFightGameDto(savedGame); + } + + @Override + public Boolean doesMoveHit(Move user1Move, Move user2Move) { + if (user1Move != Move.DEFENSE) { + if (user1Move == user2Move) { + return true; + } + if (user1Move == Move.ATTACK && user2Move == Move.MAGIC) { + return true; + } + if (user1Move == Move.MAGIC && user2Move == Move.DEFENSE) { + return true; + } + } + return false; + } + + @Override + public FightGameDto setNewTurn(long id) { + FightGame fightGame = fightGameRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Game not found " + id)); + Move user1Move = fightGame.getUser1Moves().get(fightGame.getUser1Moves().size()-1); + Move user2Move = fightGame.getUser2Moves().get(fightGame.getUser2Moves().size()-1); + if (user1Move == Move.NONE || user2Move == Move.NONE) { + throw new ResourceNotFoundException("The turn is not over"); + } + else { + if (user1Move != Move.DEFENSE && fightGame.doesMoveHit(user1Move, user2Move)) { + fightGame.setUser2HP(fightGame.getUser2HP() - 1); + } + if (user2Move != Move.DEFENSE && fightGame.doesMoveHit(user2Move, user1Move)) { + fightGame.setUser1HP(fightGame.getUser1HP() - 1); + } + List user1Moves = fightGame.getUser1Moves(); + List user2Moves = fightGame.getUser2Moves(); + user1Moves.add(Move.NONE); + user2Moves.add(Move.NONE); + fightGame.setUser1Moves(user1Moves); + fightGame.setUser2Moves(user2Moves); + FightGame savedGame = fightGameRepository.save(fightGame); + return FightGameMapper + .mapToFightGameDto(savedGame); + } + } + + @Override + public FightGameDto declareWinner(long id) { + FightGame fightGame = fightGameRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Game not found" + id)); + if (fightGame.getWinnerID() != 0) { + throw new ResourceNotFoundException("Winner was already declared for game " + id); + } + if (fightGame.getUser1HP() == 0 || fightGame.getUser2HP() == 0) { + if (fightGame.getUser1HP() == 0 && fightGame.getUser2HP() != 0) { + fightGame.setWinnerID(fightGame.getUser2().getId().intValue()); + } + else if (fightGame.getUser1HP() != 0 && fightGame.getUser2HP() == 0) { + fightGame.setWinnerID(fightGame.getUser1().getId().intValue()); + } + else { + fightGame.setWinnerID(-1); + } + if (fightGame.getRequesterID() != 0) { + if (fightGame.getWinnerID() == fightGame.getRequesterID().intValue()) { + + userService.addFriend(fightGame.getRequesterID(), new FriendDto(fightGame.getUser1().getId().intValue() == fightGame.getWinnerID() ? fightGame.getUser2().getId() : fightGame.getUser1().getId())); + List users = Arrays.asList(UserMapper.mapToUserDto(fightGame.getUser1()), UserMapper.mapToUserDto(fightGame.getUser2())); + ChatroomDto chatroom = new ChatroomDto(); + FriendRequest incoming = friendRequestRepository.findByFromUserIDAndToUserID(Long.valueOf(fightGame.getWinnerID()) == fightGame.getUser1().getId() ? + fightGame.getUser2().getId() : fightGame.getUser1().getId(), fightGame.getRequesterID()) + .orElseThrow(() -> new ResourceNotFoundException("FriendRequest not found " + + (Long.valueOf(fightGame.getWinnerID()) == fightGame.getUser1().getId() ? fightGame.getUser2().getId() : fightGame.getUser1().getId()) + + " " + fightGame.getRequesterID())); + friendRequestService.acceptFriendRequest(incoming.getId()); + chatroom.setUsers(users); + chatroomService.createChatroom(chatroom); + } + else { + FriendRequest incoming = friendRequestRepository.findByFromUserIDAndToUserID(fightGame.getRequesterID(), Long.valueOf(fightGame.getWinnerID())) + .orElseThrow(() -> new ResourceNotFoundException("FriendRequest not found " + fightGame.getRequesterID() + " " + Long.valueOf(fightGame.getWinnerID()))); + friendRequestService.rejectFriendRequest(incoming.getId()); + } + } + if (fightGame.getWinnerID() != -1) { + User winnerUser = userRepository.findById(Long.valueOf(fightGame.getWinnerID())) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + fightGame.getWinnerID())); + userService.updateGamerScore(Long.valueOf(fightGame.getWinnerID()), new GamerScoreDto(winnerUser.getGamerScore()+ 1)); + } + FightGame savedGame = fightGameRepository.save(fightGame); + return FightGameMapper.mapToFightGameDto(savedGame); + } + else { + throw new ResourceNotFoundException("The game is not finished."); + } + } +} diff --git a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestController.java b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestController.java index 59b74ea..60c53f5 100644 --- a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestController.java +++ b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestController.java @@ -1,5 +1,6 @@ package com.backend.backend.friendrequest; +import java.util.ArrayList; import java.util.List; import org.springframework.http.HttpStatus; @@ -33,10 +34,12 @@ public ResponseEntity sendFriendRequest(@RequestBody FriendReq } @PutMapping("accept") - public ResponseEntity acceptFriendRequest(@RequestBody FriendRequestDto friendRequestDto) { + public ResponseEntity> acceptFriendRequest(@RequestBody FriendRequestDto friendRequestDto) { Long friendRequestID = friendRequestDto.getId(); - FriendRequestDto friendRequest = friendRequestService.acceptFriendRequest(friendRequestID); - return new ResponseEntity<>(friendRequest, HttpStatus.OK); + List requestPair = new ArrayList<>(); + requestPair.add(friendRequestService.acceptFriendRequest(friendRequestID)); + requestPair.add(friendRequestService.sendFriendRequest(requestPair.get(0).getToUserID(), requestPair.get(0).getFromUserID())); + return new ResponseEntity<>(requestPair, HttpStatus.OK); } @PutMapping("reject") @@ -52,4 +55,16 @@ public ResponseEntity> getAllFriendRequestForUser(@PathVa return new ResponseEntity<>(friendRequests, HttpStatus.OK); } + @GetMapping("{userID}/sent") + public ResponseEntity> getAllFriendRequestFromUser(@PathVariable("userID") Long userID) { + List friendRequests = friendRequestService.getAllFriendRequestFromUser(userID); + return new ResponseEntity<>(friendRequests, HttpStatus.OK); + } + + @GetMapping("{fromUserID}/{toUserID}") + public ResponseEntity getFriendRequestBetween(@PathVariable("fromUserID") Long fromUserID, @PathVariable("toUserID") Long toUserID) { + FriendRequestDto friendRequest = friendRequestService.getFriendRequestBetween(fromUserID, toUserID); + return new ResponseEntity<>(friendRequest, HttpStatus.OK); + } + } diff --git a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestRepository.java b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestRepository.java index 8c59e64..59a4c59 100644 --- a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestRepository.java +++ b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestRepository.java @@ -5,6 +5,8 @@ import com.backend.backend.friendrequest.FriendRequest.Status; +import java.util.Optional; + import java.util.List; @@ -13,4 +15,5 @@ public interface FriendRequestRepository extends JpaRepository findByFromUserID(Long fromUserID); List findByToUserID(Long toUserID); List findByFromUserIDAndToUserIDAndStatus(Long fromUserID, Long toUserID, Status rejected); + Optional findByFromUserIDAndToUserID(Long fromUserID, Long toUserID); } diff --git a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestService.java b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestService.java index dc0741c..98775e2 100644 --- a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestService.java +++ b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestService.java @@ -5,6 +5,8 @@ public interface FriendRequestService { FriendRequestDto sendFriendRequest(Long fromUserID, Long toUserID); List getAllFriendRequestForUser(Long userID); + List getAllFriendRequestFromUser(Long userID); + FriendRequestDto getFriendRequestBetween(Long fromUserID, Long toUserID); FriendRequestDto acceptFriendRequest(Long requestID); FriendRequestDto rejectFriendRequest(Long requestID); } diff --git a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestServiceImpl.java b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestServiceImpl.java index c6107a2..4e6a8f5 100644 --- a/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestServiceImpl.java +++ b/backend/src/main/java/com/backend/backend/friendrequest/FriendRequestServiceImpl.java @@ -23,7 +23,7 @@ public class FriendRequestServiceImpl implements FriendRequestService { @Override - public FriendRequestDto sendFriendRequest(Long fromUserID, Long toUserID) {//in the future add implementation for checking dupes + public FriendRequestDto sendFriendRequest(Long fromUserID, Long toUserID) { User fromUser = userRepository.findById(fromUserID) .orElseThrow(() -> new ResourceNotFoundException("User not found" + fromUserID)); User toUser = userRepository.findById(toUserID) @@ -54,18 +54,25 @@ public List getAllFriendRequestForUser(Long userID) { return friendRequests.stream().map((friendRequest) -> FriendRequestMapper.mapToFriendRequestDto(friendRequest)).collect(Collectors.toList()); } + @Override + public List getAllFriendRequestFromUser(Long userID) { + userRepository.findById(userID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + userID)); + List friendRequests = friendRequestRepository.findByFromUserID(userID); + return friendRequests.stream().map((friendRequest) -> FriendRequestMapper.mapToFriendRequestDto(friendRequest)).collect(Collectors.toList()); + } + @Override public FriendRequestDto acceptFriendRequest(Long requestID) { FriendRequest friendRequest = friendRequestRepository.findById(requestID) .orElseThrow(() -> new ResourceNotFoundException("FriendRequest not found" + requestID)); friendRequest.setStatus(FriendRequest.Status.ACCEPTED); - List friendRequestViceVersa = friendRequestRepository.findByFromUserID(friendRequest.getToUserID()); - if(friendRequestViceVersa.size() != 0) { - friendRequestViceVersa.get(0).setStatus(FriendRequest.Status.ACCEPTED); - friendRequestRepository.save(friendRequestViceVersa.get(0)); - } + /* List friendRequestViceVersa = friendRequestRepository.findByFromUserID(friendRequest.getToUserID()); + if(friendRequestViceVersa.size() == 0) { + sendFriendRequest(friendRequest.getToUserID(), friendRequest.getFromUserID()); + } */ friendRequestRepository.save(friendRequest); - userService.addFriend(friendRequest.getFromUserID(), new FriendDto(friendRequest.getToUserID())); + // userService.addFriend(friendRequest.getFromUserID(), new FriendDto(friendRequest.getToUserID())); return FriendRequestMapper.mapToFriendRequestDto(friendRequest); } @@ -82,5 +89,11 @@ public FriendRequestDto rejectFriendRequest(Long requestID) { //needs to be twea friendRequestRepository.save(friendRequest); return FriendRequestMapper.mapToFriendRequestDto(friendRequest); } - + + @Override + public FriendRequestDto getFriendRequestBetween(Long fromUserID, Long toUserID) {//in the future add implementation for checking dupes + FriendRequest friendRequest = friendRequestRepository.findByFromUserIDAndToUserID(fromUserID, toUserID) + .orElseThrow(() -> new ResourceNotFoundException("FriendRequest not found " + fromUserID + " " + toUserID)); + return FriendRequestMapper.mapToFriendRequestDto(friendRequest); + } } diff --git a/backend/src/main/java/com/backend/backend/user/Dto/UserDto.java b/backend/src/main/java/com/backend/backend/user/Dto/UserDto.java index 30e2685..5d13122 100644 --- a/backend/src/main/java/com/backend/backend/user/Dto/UserDto.java +++ b/backend/src/main/java/com/backend/backend/user/Dto/UserDto.java @@ -2,10 +2,13 @@ import java.util.List; +import com.backend.backend.fightGame.Dto.FightGameDto; + import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.ArrayList; @Getter @@ -26,6 +29,7 @@ public class UserDto { private Long theme; private List unlockedThemes; private List friends; //changed to list long + private List gameSessions; private String email; private String password; diff --git a/backend/src/main/java/com/backend/backend/user/User.java b/backend/src/main/java/com/backend/backend/user/User.java index 2a9a991..22af58a 100644 --- a/backend/src/main/java/com/backend/backend/user/User.java +++ b/backend/src/main/java/com/backend/backend/user/User.java @@ -8,17 +8,23 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; import jakarta.persistence.PrePersist; import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; +import java.util.Collections; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import com.backend.backend.fightGame.FightGame; + @Getter @Setter @@ -70,6 +76,11 @@ public class User { @Column(name = "friend_id") private List friends; //storing just the id of the friends not the user + @ElementCollection + @CollectionTable(name = "user_game_sessions", joinColumns = @JoinColumn(name = "user_id")) + @Column(name = "game_id") + private List gameSessions; + @Column(name = "email", nullable = false, unique = true) private String email; @@ -83,7 +94,10 @@ public class User { protected void onCreate() { this.dateCreated = System.currentTimeMillis(); this.unlockedProfilePictures = Arrays.asList(Long.valueOf(0)); - this.unlockedThemes = Arrays.asList(Long.valueOf(0)); + this.unlockedThemes = Arrays.asList(Long.valueOf(0), Long.valueOf(1)); + this.gameSessions = new ArrayList<>(); + this.theme = Long.valueOf(0); + this.profilePicture = Long.valueOf(0); } } diff --git a/backend/src/main/java/com/backend/backend/user/UserController.java b/backend/src/main/java/com/backend/backend/user/UserController.java index f0db65c..c1be4a9 100644 --- a/backend/src/main/java/com/backend/backend/user/UserController.java +++ b/backend/src/main/java/com/backend/backend/user/UserController.java @@ -10,6 +10,7 @@ import com.backend.backend.user.Dto.FriendDto; import com.backend.backend.user.Dto.GamerScoreDto; import com.backend.backend.user.Dto.StatsDto; +import com.backend.backend.fightGame.Dto.FightGameDto; import com.backend.backend.user.Dto.ProfilePictureDto; import com.backend.backend.user.Dto.ThemeDto; import com.backend.backend.user.Dto.UserDto; @@ -112,6 +113,18 @@ public ResponseEntity> getFriends(@PathVariable("id") Long id) { return new ResponseEntity<>(friends, HttpStatus.OK); } + @GetMapping("{id}/games") + public ResponseEntity> getDoneGames(@PathVariable("id") Long id) { + List doneGames = userService.getDoneGames(id); + return new ResponseEntity<>(doneGames, HttpStatus.OK); + } + + @GetMapping("{id}/vs") + public ResponseEntity> getActiveGames(@PathVariable("id") Long id) { + List activeGames = userService.getActiveGames(id); + return new ResponseEntity<>(activeGames, HttpStatus.OK); + } + @GetMapping("{id}/suggestedFriends") public ResponseEntity> getSuggestedFriends(@PathVariable("id") Long id) { List suggestedFriends = userService.getSuggestedFriends(id); diff --git a/backend/src/main/java/com/backend/backend/user/UserMapper.java b/backend/src/main/java/com/backend/backend/user/UserMapper.java index 14929f2..b15944c 100644 --- a/backend/src/main/java/com/backend/backend/user/UserMapper.java +++ b/backend/src/main/java/com/backend/backend/user/UserMapper.java @@ -1,6 +1,12 @@ package com.backend.backend.user; +import java.util.List; +import java.util.stream.Collectors; + import com.backend.backend.user.Dto.UserDto; +import com.backend.backend.fightGame.FightGameMapper; +import com.backend.backend.fightGame.FightGame; +import com.backend.backend.fightGame.Dto.FightGameDto; public class UserMapper { public static UserDto mapToUserDto(User user) { @@ -16,7 +22,8 @@ public static UserDto mapToUserDto(User user) { user.getUnlockedProfilePictures(), user.getTheme(), user.getUnlockedThemes(), - user.getFriends(), + user.getFriends(), + user.getGameSessions(), user.getEmail(), user.getPassword() ); @@ -35,7 +42,8 @@ public static User mapToUser(UserDto userDto) { userDto.getUnlockedProfilePictures(), userDto.getTheme(), userDto.getUnlockedThemes(), - userDto.getFriends(), + userDto.getFriends(), + userDto.getGameSessions(), userDto.getEmail(), userDto.getPassword() ); diff --git a/backend/src/main/java/com/backend/backend/user/UserService.java b/backend/src/main/java/com/backend/backend/user/UserService.java index ad88c1d..1e7928c 100644 --- a/backend/src/main/java/com/backend/backend/user/UserService.java +++ b/backend/src/main/java/com/backend/backend/user/UserService.java @@ -2,6 +2,7 @@ import java.util.List; +import com.backend.backend.fightGame.Dto.FightGameDto; import com.backend.backend.user.Dto.FriendDto; import com.backend.backend.user.Dto.GamerScoreDto; import com.backend.backend.user.Dto.StatsDto; @@ -33,10 +34,16 @@ public interface UserService { //Add a friend so update friends list UserDto addFriend(Long id, FriendDto friendId); + UserDto addGameSession(Long user1ID, Long user2ID, FightGameDto fightGameDto); + void deleteFriend(Long id, FriendDto friendId); List getFriends(Long id); + List getDoneGames(Long id); + + List getActiveGames(Long id); + List getSuggestedFriends(Long id); //Remove a user *Future //Edit a user *Future diff --git a/backend/src/main/java/com/backend/backend/user/UserServiceImpl.java b/backend/src/main/java/com/backend/backend/user/UserServiceImpl.java index cfbafd1..9e07b97 100644 --- a/backend/src/main/java/com/backend/backend/user/UserServiceImpl.java +++ b/backend/src/main/java/com/backend/backend/user/UserServiceImpl.java @@ -12,6 +12,11 @@ import com.backend.backend.user.Dto.StatsDto; import com.backend.backend.user.Dto.ThemeDto; import com.backend.backend.user.Dto.UserDto; +import com.backend.backend.fightGame.Dto.FightGameDto; +import com.backend.backend.fightGame.FightGame; +import com.backend.backend.fightGame.FightGameRepository; +import com.backend.backend.fightGame.FightGameMapper; + import lombok.AllArgsConstructor; @@ -20,6 +25,7 @@ public class UserServiceImpl implements UserService { private UserRepository userRepository; + private FightGameRepository fightGameRepository; // START OF ALL CREATE @@ -70,6 +76,34 @@ public List getSuggestedFriends(Long id) { return suggestedFriends; } + @Override + public List getDoneGames(Long id) { + User user = userRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + id)); + List gameHistory = user.getGameSessions().stream().map((game) -> fightGameRepository.findById(game).orElseThrow(() -> new ResourceNotFoundException("User not found" + game))).collect(Collectors.toList()); + List doneGames = new ArrayList<>(); + for(FightGame game : gameHistory){ + if(game.getWinnerID() != 0){ + doneGames.add(FightGameMapper.mapToFightGameDto(game)); + } + } + return doneGames; + } + + @Override + public List getActiveGames(Long id) { + User user = userRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + id)); + List gameHistory = user.getGameSessions().stream().map((game) -> fightGameRepository.findById(game).orElseThrow(() -> new ResourceNotFoundException("User not found" + game))).collect(Collectors.toList()); + List doneGames = new ArrayList<>(); + for(FightGame game : gameHistory){ + if(game.getWinnerID() == 0){ + doneGames.add(FightGameMapper.mapToFightGameDto(game)); + } + } + return doneGames; + } + // END OF ALL GET // ============================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== // START OF ALL UPDATE @@ -131,6 +165,21 @@ public UserDto addFriend(Long id, FriendDto friendDto){ return UserMapper.mapToUserDto(savedUser); } + @Override + public UserDto addGameSession(Long user1ID, Long user2ID, FightGameDto fightGameDto){ + User user1 = userRepository.findById(user1ID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + user1ID)); + User user2 = userRepository.findById(user2ID) + .orElseThrow(() -> new ResourceNotFoundException("User not found" + user2ID)); + FightGame fightGame = fightGameRepository.findById(fightGameDto.getId()) + .orElseThrow(() -> new ResourceNotFoundException("Game not found" + fightGameDto.getId())); + user1.getGameSessions().add(fightGame.getId()); + user2.getGameSessions().add(fightGame.getId()); + User savedUser = userRepository.save(user1); + userRepository.save(user2); + return UserMapper.mapToUserDto(savedUser); + } + @Override public UserDto addProfilePicture(Long id, ProfilePictureDto profilePicture) { User user = userRepository.findById(id) diff --git a/fightme_webapp/assets/images/default-avatar.png b/fightme_webapp/assets/images/default-avatar.png index 77a3fb1..9f34e14 100644 Binary files a/fightme_webapp/assets/images/default-avatar.png and b/fightme_webapp/assets/images/default-avatar.png differ diff --git a/fightme_webapp/lib/Models/fight_game_session.dart b/fightme_webapp/lib/Models/fight_game_session.dart index 040dd0a..7cb582a 100644 --- a/fightme_webapp/lib/Models/fight_game_session.dart +++ b/fightme_webapp/lib/Models/fight_game_session.dart @@ -6,24 +6,66 @@ enum Move {attack, defense, magic, none} class FightGameSession { int id = 0; int winnerID = 0; + int requesterID = 0; User user1 = User(""); int user1hp = 5; - Move user1move = Move.none; + List user1moves = [Move.none]; User user2 = User(""); int user2hp = 5; - Move user2move = Move.none; - int turn = 1; + List user2moves = [Move.none]; + + FightGameSession.fromJson(Map json) { + id = json['id']; + winnerID = json['winnerID']; + requesterID = json['requesterID']; + user1 = User.fromJson(json['user1']); + user2 = User.fromJson(json['user2']); + user1hp = json['user1HP']; + user1moves = []; + for (var move in json['user1Moves']) { + user1moves.add((move == 'ATTACK') ? Move.attack : (move == 'DEFENSE') + ? Move.defense : (move == 'MAGIC') ? Move.magic : Move.none); + } + user2hp = json['user2HP']; + user2moves = []; + for (var move in json['user2Moves']) { + user2moves.add((move == 'ATTACK') ? Move.attack : (move == 'DEFENSE') + ? Move.defense : (move == 'MAGIC') ? Move.magic : Move.none); + } + } + + Map toJson(){ + List user1MovesToJson= []; + List user2MovesToJson= []; + for(var move in user1moves){ + user1MovesToJson.add(move.name.toString().toUpperCase()); + } + for(var move in user2moves){ + user2MovesToJson.add(move.name.toString().toUpperCase()); + } + return{ + 'id': id, + 'winnerID': winnerID, + 'requesterID': requesterID, + 'user1': user1.toJson(), + 'user2': user2.toJson(), + 'user1HP': user1hp, + 'user2HP': user2hp, + 'user1Moves': user1MovesToJson, + 'user2Moves': user2MovesToJson + }; + } FightGameSession(User curUser, otherUser) { id = 0; winnerID = 0; + requesterID = 0; user1 = curUser; user1hp = 5; - user1move = Move.none; + user1moves = [Move.none]; user2 = otherUser; user2hp = 5; - user2move = Move.none; - turn = 1; + user2moves = [Move.none]; } FightGameSession.practice(User curUser) { @@ -31,14 +73,74 @@ class FightGameSession { winnerID = 0; user1 = curUser; user1hp = 5; - user1move = Move.none; + user1moves = [Move.none]; + requesterID = 0; user2 = User("Dummy"); user2.pfp = 1; user2.attackScore = curUser.attackScore; user2.defenseScore = curUser.defenseScore; user2.magicScore = curUser.magicScore; user2hp = 5; - user2move = Move.none; - turn = 1; + user2moves = [Move.none]; + } + + int getUserHp(int userID) { + if (userID == user1.id) { + return user1hp; + } + else if (userID == user2.id){ + return user2hp; + } + else { + return -1; + } + } + + int getOtherUserHp(int userID) { + if (userID != user1.id && userID != user2.id) { + return -1; + } + else if (userID != user1.id) { + return user1hp; + } + else { + return user2hp; + } + } + + List getUserMoves(int userID) { + if (userID == user1.id) { + return user1moves; + } + else if (userID == user2.id){ + return user2moves; + } + else { + return List.empty(); + } + } + + List getOtherUserMoves(int userID) { + if (userID != user1.id && userID != user2.id) { + return List.empty(); + } + else if (userID != user1.id) { + return user1moves; + } + else { + return user2moves; + } + } + + User getOtherUser(int userID) { + if (userID != user1.id && userID != user2.id) { + return User("All work"); + } + else if (userID != user1.id) { + return user1; + } + else { + return user2; + } } } \ No newline at end of file diff --git a/fightme_webapp/lib/Models/httpservice.dart b/fightme_webapp/lib/Models/httpservice.dart index e40a78b..873190d 100644 --- a/fightme_webapp/lib/Models/httpservice.dart +++ b/fightme_webapp/lib/Models/httpservice.dart @@ -5,6 +5,8 @@ import 'chatroom.dart'; import 'user.dart'; import 'message.dart'; import 'friend_request.dart'; +import 'package:fightme_webapp/globals.dart' as globals; +import 'fight_game_session.dart'; class HttpService { final String springbootUserURL = "http://localhost:8080/api/users/"; @@ -14,6 +16,7 @@ class HttpService { "http://localhost:8080/api/friendrequests"; final String springbootLoginURL = "http://localhost:8080/api/login"; final String springbootSignupURL = "http://localhost:8080/api/signup"; + final String springbootFightGamesURL = "http://localhost:8080/api/fightgames"; //retrieve a list of users from springboot Future> getUsers() async { @@ -55,6 +58,30 @@ class HttpService { } } + Future> getDoneGames(int id) async { + Response res = await get(Uri.parse("$springbootUserURL$id/games")); + if (res.statusCode == 200) { + List body = jsonDecode(res.body); + List doneGames = + body.map((dynamic item) => FightGameSession.fromJson(item)).toList(); + return doneGames; + } else { + throw "Unable to retrieve user data."; + } + } + + Future> getActiveGames(int id) async { + Response res = await get(Uri.parse("$springbootUserURL$id/vs")); + if (res.statusCode == 200) { + List body = jsonDecode(res.body); + List activeGames = + body.map((dynamic item) => FightGameSession.fromJson(item)).toList(); + return activeGames; + } else { + throw "Unable to retrieve user data."; + } + } + Future signupUser(String username, String email, String password) async { Map input = { 'name': username, @@ -67,7 +94,7 @@ class HttpService { body: jsonEncode(input), ); print(res.body); - if (res.statusCode == 200) { + if (res.statusCode == 201) { print("User registered."); return int.parse(res.body); } else { @@ -177,7 +204,33 @@ class HttpService { body.map((dynamic item) => FriendRequest.fromJson(item)).toList(); return friendRequests; } else { - throw "Unable to retrieve friend request data for user $userID"; + print("Unable to retrieve friend request data for user $userID"); + return List.empty(); + } + } + + Future> getAllSentRequests(int userID) async { + Response res = await get(Uri.parse("$springbootFriendRequestURL/$userID/sent")); + if (res.statusCode == 200) { + List body = jsonDecode(res.body); + List friendRequests = + body.map((dynamic item) => FriendRequest.fromJson(item)).toList(); + return friendRequests; + } else { + print("Unable to retrieve friend request data for user $userID"); + return List.empty(); + } + } + + Future getFriendRequest(int fromUserID, int toUserID) async { + Response res = await get(Uri.parse("$springbootFriendRequestURL/$fromUserID/$toUserID")); + if (res.statusCode == 200) { + dynamic body = jsonDecode(res.body); + FriendRequest friendRequest = FriendRequest.fromJson(body); + return friendRequest; + } else { + print("Unable to retrieve friend request."); + return FriendRequest.empty(); } } @@ -284,4 +337,69 @@ class HttpService { throw "Unable to add user theme."; } } + + Future postFightGame(User user1, User user2, int requesterID) async { + Response res = await post(Uri.parse(springbootFightGamesURL), + headers: {"Content-Type": "application/json"}, + body: jsonEncode({"user1": user1.toJson(), "user2": user2.toJson(), "requesterID": requesterID})); + print(res.body); + if (res.statusCode == 201) { + print("Game created successfully."); + dynamic body = jsonDecode(res.body); + FightGameSession fightGameSession = FightGameSession.fromJson(body); + return fightGameSession; + } else { + print("Unable to create game session."); + return FightGameSession.practice(globals.curUser); + } + } + + Future getFightGame(int user1ID, int user2ID) async { + Response res = await get(Uri.parse("$springbootFightGamesURL/$user1ID/$user2ID")); + if (res.statusCode == 200) { + print(res.body); + dynamic body = jsonDecode(res.body); + FightGameSession fightGameSession = FightGameSession.fromJson(body); + print("${fightGameSession.id}"); + return fightGameSession; + } else { + print("Unable to retrieve game session."); + return FightGameSession.practice(globals.curUser); + } + } + + Future setMove(int gameID, int userID, Move move) async { + Response res = await put(Uri.parse("$springbootFightGamesURL/$gameID/setMove"), + headers: {"Content-Type": "application/json"}, + body: jsonEncode({"userID": userID, "move": move.name.toString().toUpperCase()})); + if (res.statusCode == 200) { + print("Move set successfully."); + } else { + print(move.name.toString()); + print("$userID"); + throw "Unable to set move."; + } + } + + Future setNewTurn(FightGameSession game) async { + Response res = await put(Uri.parse("$springbootFightGamesURL/newTurn"), + headers: {"Content-Type": "application/json"}, + body: jsonEncode(game.toJson())); + if (res.statusCode == 200) { + print("New turn set successfully."); + } else { + throw "Unable to set new turn."; + } + } + + Future declareWinner(int gameID) async { + Response res = await put(Uri.parse("$springbootFightGamesURL/$gameID/winner"), + headers: {"Content-Type": "application/json"}); + if (res.statusCode == 200) { + print("Winner set successfully."); + } else { + throw "Unable to set a winner."; + } + } } + diff --git a/fightme_webapp/lib/Widgets/fightButton.dart b/fightme_webapp/lib/Widgets/fightButton.dart index 89f340c..30b322e 100644 --- a/fightme_webapp/lib/Widgets/fightButton.dart +++ b/fightme_webapp/lib/Widgets/fightButton.dart @@ -1,16 +1,19 @@ import 'package:fightme_webapp/Cosmetics/profile_pictures.dart'; +import 'package:fightme_webapp/Models/httpservice.dart'; import 'package:flutter/material.dart'; import 'dart:math'; +import 'package:fightme_webapp/Models/friend_request.dart'; +import 'package:fightme_webapp/globals.dart' as globals; import 'package:fightme_webapp/Models/fight_game_session.dart'; List randomMove = [Move.attack, Move.defense, Move.magic]; -Color moveColor(String move) { - if (move == "assets/images/attack.png") { +Color moveColor(Move move) { + if (move == Move.attack) { return Colors.red; } - else if (move == "assets/images/defense.png") { + else if (move == Move.defense) { return Colors.blue; } else { @@ -57,37 +60,81 @@ bool doesUserHit(Move move1, Move move2) { return false; } -void buildFightButton(BuildContext context, FightGameSession game) { +Future buildFightButton(BuildContext context, FightGameSession game) async { + if (globals.uid != game.user1.id && globals.uid != game.user2.id) { + showDialog( + context: context, + builder: (BuildContext context) => + AlertDialog( + title: const Text( + "There was an error."), + content: const Text( + "You are not a part of this game." + ), + actionsAlignment: MainAxisAlignment.center, + actions: [ + TextButton( + onPressed: () => + Navigator.pop( + context, 'OK'), + child: const Text('OK'), + ), + ], + ), + ); + } final random = Random(); - String whatUser1Did = ""; - String whatUser2Did = ""; List colors = [Colors.red, Colors.orangeAccent, Colors.amberAccent, Colors.yellowAccent[100]!, Colors.lightGreenAccent[400]!/*Why in God's name would this be Color? ?*/]; showDialog( context: context, builder: (BuildContext context) => StatefulBuilder( builder: (context, setState) { - if (game.user1move != Move.none) { + if (game.user1moves.last != Move.none) { if (game.user2.id == 0) { - game.user2move = randomMove[random.nextInt(randomMove.length)]; + game.user2moves.last = randomMove[random.nextInt(randomMove.length)]; } - if (game.user2move != Move.none) { - if (doesUserHit(game.user1move, game.user2move)) { - game.user2hp--; + if (game.user2moves.last != Move.none) { + if (game.id != 0) { + HttpService().setNewTurn(game).then((result) { + setState(() { + if (doesUserHit( + game.user1moves.last, game.user2moves.last)) { + game.user2hp--; + } + if (doesUserHit( + game.user2moves.last, game.user1moves.last)) { + game.user1hp--; + } + game.user1moves.add(Move.none); + game.user2moves.add(Move.none); + }); + return; + }); } - if (doesUserHit(game.user2move, game.user1move)) { - game.user1hp--; + else { + if (doesUserHit( + game.user1moves.last, game.user2moves.last)) { + game.user2hp--; + } + if (doesUserHit( + game.user2moves.last, game.user1moves.last)) { + game.user1hp--; + } + game.user1moves.add(Move.none); + game.user2moves.add(Move.none); } - whatUser1Did = move(game.user1move); - whatUser2Did = move(game.user2move); - game.turn++; - game.user1move = Move.none; - game.user2move = Move.none; } } if (game.user1hp == 0 || game.user2hp == 0) { + if (game.id != 0) { + HttpService().declareWinner(game.id).then(( + result) { //this could be an issue because of the curUser id + return; + }); + } return AlertDialog( - title: Text(endMessage(game.user1hp, game.user2hp)), + title: Text(endMessage(game.getUserHp(globals.uid), game.getOtherUserHp(globals.uid))), actionsAlignment: MainAxisAlignment.center, content: Image.asset(game.user1hp != 0 ? profilePictures[game.user1.pfp] : profilePictures[game.user2.pfp], width: 60, height: 60), actions: [ @@ -103,7 +150,7 @@ void buildFightButton(BuildContext context, FightGameSession game) { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const CloseButton(), - Text("Turn ${game.turn}"), + Text("Turn ${game.user1moves.length}"), IconButton( onPressed: () => showDialog( @@ -141,7 +188,7 @@ void buildFightButton(BuildContext context, FightGameSession game) { content: Column( mainAxisSize: MainAxisSize.min, children: [ - Text(game.user2.name, + Text(game.getOtherUser(globals.uid).name, style: const TextStyle(fontSize: 20)), Row( mainAxisAlignment: MainAxisAlignment @@ -151,14 +198,14 @@ void buildFightButton(BuildContext context, FightGameSession game) { children: [ const Text("ATK", style: TextStyle( backgroundColor: Colors.red)), - Text("${game.user2.attackScore}"), + Text("${game.getOtherUser(globals.uid).attackScore}"), ] ), Column( children: [ const Text("DEF", style: TextStyle( backgroundColor: Colors.blue)), - Text("${game.user2.defenseScore}"), + Text("${game.getOtherUser(globals.uid).defenseScore}"), ] ), Column( @@ -166,7 +213,7 @@ void buildFightButton(BuildContext context, FightGameSession game) { const Text("MP", style: TextStyle( backgroundColor: Colors .yellow)), - Text("${game.user2.magicScore}"), + Text("${game.getOtherUser(globals.uid).magicScore}"), ] ), ] @@ -177,11 +224,11 @@ void buildFightButton(BuildContext context, FightGameSession game) { Row( children: [ for (int i = 1; i <= 5; i++) - i > 5 - game.user2hp ? Expanded( + i > 5 - game.getOtherUserHp(globals.uid) ? Expanded( child: Container( height: 15.0, decoration: BoxDecoration( - color: colors[game.user2hp - 1], + color: colors[game.getOtherUserHp(globals.uid) - 1], border: Border.all( color: Colors.black, width: 0.0), @@ -204,14 +251,21 @@ void buildFightButton(BuildContext context, FightGameSession game) { ), Align( alignment: Alignment.centerRight, - child: Image.asset(profilePictures[game.user2.pfp], width: 60, height: 60), + child: Image.asset(profilePictures[game.getOtherUser(globals.uid).pfp], width: 60, height: 60), + ), + const SizedBox( + height: 5, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (whatUser1Did != "" && whatUser2Did != "")...[ - Image.asset(whatUser1Did, width: 30, height: 30, color: moveColor(whatUser1Did)), - Image.asset(whatUser2Did, width: 30, height: 30, color: moveColor(whatUser2Did)), + if (game.user1moves.length > 1 && game.user2moves.length > 1)...[ + Image.asset(move(game.getUserMoves(globals.uid).elementAt(game.getUserMoves(globals.uid).length - 2)), + width: 30, height: 30, + color: moveColor(game.getUserMoves(globals.uid).elementAt(game.getUserMoves(globals.uid).length - 2))), + Image.asset(move(game.getOtherUserMoves(globals.uid).elementAt(game.getOtherUserMoves(globals.uid).length - 2)), + width: 30, height: 30, + color: moveColor(game.getOtherUserMoves(globals.uid).elementAt(game.getOtherUserMoves(globals.uid).length - 2))), ] else...[ const SizedBox( @@ -220,14 +274,20 @@ void buildFightButton(BuildContext context, FightGameSession game) { ] ] ), + const SizedBox( + height: 5, + ), Align( alignment: Alignment.centerLeft, child: Transform( alignment: Alignment.center, transform: Matrix4.rotationY(pi), - child: Image.asset(profilePictures[game.user1.pfp], width: 60, height: 60), + child: Image.asset(profilePictures[globals.curUser.pfp], width: 60, height: 60), ), ), + const SizedBox( + height: 5, + ), Row( children: [ const Text("HP"), @@ -235,11 +295,11 @@ void buildFightButton(BuildContext context, FightGameSession game) { width: 5, ), for (int i = 1; i <= 5; i++) - i <= game.user1hp ? Expanded( + i <= game.getUserHp(globals.uid) ? Expanded( child: Container( height: 15.0, decoration: BoxDecoration( - color: colors[game.user1hp - 1], + color: colors[game.getUserHp(globals.uid) - 1], border: Border.all( color: Colors.black, width: 0.0), @@ -257,13 +317,17 @@ void buildFightButton(BuildContext context, FightGameSession game) { ), actionsAlignment: MainAxisAlignment.center, actions: [ - game.user1move == Move.none ? Row( + game.getUserMoves(globals.uid).last == Move.none ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ FloatingActionButton( - onPressed: () { + onPressed: () async { + if (game.id != 0) { + await HttpService().setMove( + game.id, globals.uid, Move.attack); + } setState(() { - game.user1move = Move.attack; + game.getUserMoves(globals.uid).last = Move.attack; }); }, backgroundColor: Colors.red, @@ -271,14 +335,18 @@ void buildFightButton(BuildContext context, FightGameSession game) { mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Attack'), - Text("${game.user1.attackScore}"), + Text("${globals.curUser.attackScore}"), ] ), ), FloatingActionButton( - onPressed: () { + onPressed: () async { + if (game.id != 0) { + await HttpService().setMove( + game.id, globals.uid, Move.defense); + } setState(() { - game.user1move = Move.defense; + game.getUserMoves(globals.uid).last = Move.defense; }); }, backgroundColor: Colors.blue, @@ -287,14 +355,18 @@ void buildFightButton(BuildContext context, FightGameSession game) { .center, children: [ const Text('Defense'), - Text("${game.user1.defenseScore}"), + Text("${globals.curUser.defenseScore}"), ] ), ), FloatingActionButton( - onPressed: () { + onPressed: () async { + if (game.id != 0) { + await HttpService().setMove( + game.id, globals.uid, Move.magic); + } setState(() { - game.user1move = Move.magic; + game.getUserMoves(globals.uid).last = Move.magic; }); }, backgroundColor: Colors.yellow, @@ -303,7 +375,7 @@ void buildFightButton(BuildContext context, FightGameSession game) { .center, children: [ const Text('Magic'), - Text("${game.user1.magicScore}"), + Text("${globals.curUser.magicScore}"), ] ), ), diff --git a/fightme_webapp/lib/Widgets/friend_request_button.dart b/fightme_webapp/lib/Widgets/friend_request_button.dart index 6be69b3..47c8b87 100644 --- a/fightme_webapp/lib/Widgets/friend_request_button.dart +++ b/fightme_webapp/lib/Widgets/friend_request_button.dart @@ -2,16 +2,16 @@ import 'package:flutter/material.dart'; import 'package:fightme_webapp/Models/httpservice.dart'; import 'package:fightme_webapp/chat_page.dart'; import 'package:fightme_webapp/Models/friend_request.dart'; +import 'package:fightme_webapp/Models/fight_game_session.dart'; import 'package:fightme_webapp/Models/user.dart'; import 'package:fightme_webapp/Models/chatroom.dart'; +import 'fightButton.dart'; Future buildFriendButton(BuildContext context, VoidCallback update, User otherUser, User curUser) async { HttpService http = HttpService(); - List myRequests = await http.getAllFriendRequests(curUser.id); - List otherRequests = await http.getAllFriendRequests(otherUser.id); - FriendRequest? outgoing = otherRequests.firstWhere((element) => element.fromUserID == curUser.id, orElse: () => FriendRequest.empty()); - FriendRequest? incoming = myRequests.firstWhere((element) => element.fromUserID == otherUser.id, orElse: () => FriendRequest.empty()); + FriendRequest incoming = await http.getFriendRequest(otherUser.id, curUser.id); + FriendRequest outgoing = await http.getFriendRequest(curUser.id, otherUser.id); // TODO: Figure out how to get this value initialized only when accepted conditions are met. late Chatroom chat; http.getChatroomsByUserId(curUser.id).then((result) { @@ -46,13 +46,9 @@ Future buildFriendButton(BuildContext context, VoidCallback update, User http.acceptFriendRequest(incoming.id).then((result){ // final FriendsProvider friendsProvider = Provider.of(context, listen: false); // friendsProvider.addFriend(otherUser); - return; - }); - http.updateUserGamerScore(curUser.id, curUser.gamerScore + 1).then((result){ //this could be an issue because of the curUser id - return; - }); - List userIDs = [curUser.id, otherUser.id]; - http.postChatroom(userIDs).then((result){ + http.postFightGame(curUser, otherUser, otherUser.id).then((result){ + return; + }); return; }); update(); @@ -81,12 +77,32 @@ Future buildFriendButton(BuildContext context, VoidCallback update, User child: const Text('rejected'), ); + FightGameSession fightGame = FightGameSession(curUser, otherUser); + http.getFightGame(curUser.id, otherUser.id).then((result) { + fightGame = result; + }); + Widget fight = FilledButton.tonal( + onPressed: () { + if (fightGame.id != 0) { + buildFightButton( + context, fightGame); + } + }, + child: const Text('Fight!') + ); + // isEmpty is the closest I can get to is null. // The bulk of the case section is based not on accessing when there isn't a friend request. if (!incoming.isEmpty() && !outgoing.isEmpty()) { if (incoming.status == Status.accepted && outgoing.status == Status.accepted) { return friends; } + else if (incoming.status == Status.accepted && outgoing.status == Status.pending) { + return fight; + } + else if (incoming.status == Status.pending && outgoing.status == Status.accepted) { + return fight; + } else if (incoming.status == Status.rejected && outgoing.status == Status.pending) { return pending; } diff --git a/fightme_webapp/lib/chat_page_web_socket.dart b/fightme_webapp/lib/chat_page_web_socket.dart index b92de33..d91ee50 100644 --- a/fightme_webapp/lib/chat_page_web_socket.dart +++ b/fightme_webapp/lib/chat_page_web_socket.dart @@ -36,6 +36,7 @@ class ChatPageState extends State { late TextEditingController textEditControl; late List messages = []; late int randomNumber; + late Future game; @override void initState() { @@ -45,6 +46,7 @@ class ChatPageState extends State { messages = value; }); }); + game = HttpService().getFightGame(widget.currentUID, widget.otherUID); textEditControl = TextEditingController(); @@ -123,13 +125,44 @@ class ChatPageState extends State { body: Center( child: Column( children: [ - ElevatedButton( - onPressed: () => buildFightButton( - context, - FightGameSession(widget.currentUser, widget.otherUser), - ), - child: const Text('Fight!'), - ), + FutureBuilder(future: game, builder: (BuildContext context, AsyncSnapshot wid) { + if (wid.hasData) { + if (wid.data!.id == 0 || (wid.data!.id != 0 && wid.data!.winnerID != 0)) { + return ElevatedButton( + onPressed: () async { + FightGameSession game = await HttpService().postFightGame(widget.currentUser, widget.otherUser, 0); + if (game.id == 0) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + duration: Duration(seconds: 3), + content: Text('The game could not be created.'), + ) + ); + } + else { + await buildFightButton( + context, + game, + ); + } + }, + child: const Text('Fight!'), + ); + } + else { + return FilledButton.tonal( + onPressed: () async { + await buildFightButton( + context, + wid.data!, + ); + }, + child: const Text('Fight!'), + ); + } + } + return const CircularProgressIndicator(); + }), Expanded( child: ListView.builder( itemCount: messages.length, diff --git a/fightme_webapp/lib/dashboard.dart b/fightme_webapp/lib/dashboard.dart index 2676e4f..8de03ed 100644 --- a/fightme_webapp/lib/dashboard.dart +++ b/fightme_webapp/lib/dashboard.dart @@ -1,7 +1,9 @@ +import 'package:fightme_webapp/vs_page.dart'; import 'package:flutter/material.dart'; import 'Models/chatroom.dart'; import 'Models/user.dart'; import 'package:fightme_webapp/Models/httpservice.dart'; +import 'package:fightme_webapp/gamerscore_shop.dart'; import 'pending_requests.dart'; import 'globals.dart' as globals; @@ -30,7 +32,24 @@ class DashboardPageState extends State { body: Center( child: Column( children: [ - + ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const VsPage())); + }, + child: const Text("VS"), + ), + ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GamerscoreShop(curUser: widget.curUser),)); + }, + child: const Icon(Icons.shopping_bag_outlined), + ) ], ), ), diff --git a/fightme_webapp/lib/game_history_page.dart b/fightme_webapp/lib/game_history_page.dart new file mode 100644 index 0000000..cb26fa4 --- /dev/null +++ b/fightme_webapp/lib/game_history_page.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'Models/fight_game_session.dart'; +import 'Models/user.dart'; +import 'package:fightme_webapp/Models/httpservice.dart'; +import 'Widgets/fightButton.dart'; +import 'Cosmetics/profile_pictures.dart'; +import 'globals.dart' as globals; + +class GameHistoryPage extends StatefulWidget { + + const GameHistoryPage({super.key}); + + @override + State createState() => GameHistoryPageState(); +} + + +class GameHistoryPageState extends State { + late Future> _list = Future.value([]); + + Future> _buildList() async { + HttpService http = HttpService(); + List list = List.empty(growable: true); + List myFights = await http.getDoneGames(globals.uid); + for (var fight in myFights) { + User user = fight.getOtherUser(globals.uid); + list.add( + TextButton( + onPressed: () { + buildFightButton(context, fight); + }, + child: ListTile( + leading: ClipRRect( + borderRadius: BorderRadius.circular(60.0), + child: Image.asset(profilePictures[user.pfp], fit: BoxFit.cover, width: 60, height: 60), + ), + title: user.id != 0 ? Text(user.name) : const Text("Group"), + tileColor: fight.winnerID == globals.uid ? Colors.green : Colors.red, + ), + ) + ); + } + return list; + } + + @override + void initState() { + super.initState(); + _list = _buildList(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme + .of(context) + .colorScheme + .primary, + centerTitle: true, + title: const Text("Previous games"), + ), + body: Center( + child: Column( + children: [ + FutureBuilder(future: _list, builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + if (snapshot.data!.isEmpty) { + return const Text( + "No games available. Go fight some people."); + } + else { + return ListView( + scrollDirection: Axis.vertical, + shrinkWrap: true, + children: snapshot.data! + ); + } + } + else { + return const CircularProgressIndicator(); + } + }), + ], + ), + ), + ); + } +} \ No newline at end of file diff --git a/fightme_webapp/lib/gamerscore_shop.dart b/fightme_webapp/lib/gamerscore_shop.dart index 08d32f8..79cec98 100644 --- a/fightme_webapp/lib/gamerscore_shop.dart +++ b/fightme_webapp/lib/gamerscore_shop.dart @@ -1,5 +1,4 @@ import 'package:fightme_webapp/Models/user.dart'; -import 'package:fightme_webapp/main.dart'; import 'package:flutter/material.dart'; import 'Cosmetics/profile_pictures.dart'; import 'Cosmetics/themes.dart'; @@ -95,9 +94,10 @@ class _GamerscoreShopState extends State { onPressed: () async { await _httpService.updateUserGamerScore(globals.uid, widget.curUser.gamerScore - buyableProfilePictures[index][1]); await _httpService.addUserProfilePicture(globals.uid, buyableProfilePictures[index][0]); + statsProvider.updateGamerscore(statsProvider.gamerscore - buyableProfilePictures[index][1]); + // statsProvider.updateStats(statsProvider.attack, statsProvider.magic + 1, statsProvider.defense); setState(() { widget.curUser.unlockedpfps.add(buyableProfilePictures[index][0]); - widget.curUser.gamerScore = widget.curUser.gamerScore - buyableProfilePictures[index][1]; }); Navigator.pop(context, 'Yes'); }, @@ -204,9 +204,10 @@ class _GamerscoreShopState extends State { onPressed: () async { await _httpService.updateUserGamerScore(globals.uid, widget.curUser.gamerScore - buyableThemes[index][1]); await _httpService.addUserTheme(globals.uid, buyableThemes[index][0]); + statsProvider.updateGamerscore(statsProvider.gamerscore - buyableThemes[index][1]); + //statsProvider.updateStats(statsProvider.attack, statsProvider.magic + 1, statsProvider.defense); setState(() { widget.curUser.unlockedThemes.add(buyableThemes[index][0]); - widget.curUser.gamerScore = widget.curUser.gamerScore - buyableThemes[index][1]; }); Navigator.pop(context, 'Yes'); }, @@ -251,7 +252,7 @@ class _GamerscoreShopState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("${buyableProfilePictures[index][1]}", style: const TextStyle( + Text("${buyableThemes[index][1]}", style: const TextStyle( fontSize: 30)), const Icon(Icons.monetization_on, color: Colors.yellow, size: 30,), ] diff --git a/fightme_webapp/lib/home.dart b/fightme_webapp/lib/home.dart index 5790606..c2d78dd 100644 --- a/fightme_webapp/lib/home.dart +++ b/fightme_webapp/lib/home.dart @@ -259,6 +259,7 @@ class _SignUpState extends State { if (userId > 0) { globals.curUser = await HttpService().getUserByID(userId); globals.loggedIn = true; + globals.uid = userId; await _saveUserData(userId); Navigator.pushAndRemoveUntil( context, @@ -357,7 +358,19 @@ class _SignUpState extends State { ), const SizedBox(height: 16.0), ElevatedButton( - onPressed: signUpUser, + onPressed: ( () { + if (_passwordController.text.length < 8) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + duration: Duration(seconds: 3), + content: Text('Password must be 8 characters or longer.'), + ) + ); + } + else { + signUpUser(); + } + }), style: ElevatedButton.styleFrom( minimumSize: Size(double.infinity, 40), shape: RoundedRectangleBorder( diff --git a/fightme_webapp/lib/navbar.dart b/fightme_webapp/lib/navbar.dart index 8646c96..0867999 100644 --- a/fightme_webapp/lib/navbar.dart +++ b/fightme_webapp/lib/navbar.dart @@ -1,4 +1,4 @@ -import 'package:fightme_webapp/gamerscore_shop.dart'; +import 'package:fightme_webapp/dashboard.dart'; import 'package:fightme_webapp/chats_master_page.dart'; import 'package:fightme_webapp/training_area_page.dart'; import 'package:fightme_webapp/profile_page.dart'; @@ -33,7 +33,7 @@ class _BottomNavigationBarExampleState extends State { @override Widget build(BuildContext context) { final List _widgetOptions = [ - GamerscoreShop(curUser: widget.curUser), + DashboardPage(curUser: widget.curUser), ChatsMasterPage(curUser: widget.curUser), TrainingAreaPage(curUser: widget.curUser), ProfilePage(curUser: widget.curUser, userViewed: widget.curUser), @@ -47,8 +47,8 @@ class _BottomNavigationBarExampleState extends State { type: BottomNavigationBarType.fixed, items: const [ BottomNavigationBarItem( - icon: Icon(Icons.shopping_bag_outlined), - label: 'Shop', + icon: Icon(Icons.home), + label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.chat), diff --git a/fightme_webapp/lib/pending_requests.dart b/fightme_webapp/lib/pending_requests.dart index 4b25a27..f7f835e 100644 --- a/fightme_webapp/lib/pending_requests.dart +++ b/fightme_webapp/lib/pending_requests.dart @@ -18,70 +18,143 @@ class PendingRequestsPage extends StatefulWidget { class PendingRequestsPageState extends State { - late Future> _list; + late Future> _recvlist; + late Future> _sentlist; late User curUser; - Future> _buildList() async { + Future> _buildReceivedList() async { HttpService http = HttpService(); List list = List.empty(growable: true); List myRequests = await http.getAllFriendRequests(globals.uid); myRequests.removeWhere((element) => element.status == Status.rejected); for (var request in myRequests) { - User user = await http.getUserByID(request.fromUserID); - list.add( - TextButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ProfilePage( - curUser: curUser, - userViewed: user))); - }, - child: ListTile( + FriendRequest otherRequest = await http.getFriendRequest(request.toUserID, request.fromUserID); + if (otherRequest.isEmpty() || (otherRequest.id != 0 && otherRequest.status == Status.pending)) { + User user = await http.getUserByID(request.fromUserID); + FightGameSession game = await http.getFightGame(globals.uid, user.id); + list.add( + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ProfilePage( + curUser: curUser, + userViewed: user))); + }, + child: ListTile( leading: ClipRRect( borderRadius: BorderRadius.circular(60.0), - child: Image.asset(profilePictures[user.pfp], fit: BoxFit.cover, width: 60, height: 60), + child: Image.asset( + profilePictures[user.pfp], fit: BoxFit.cover, + width: 60, + height: 60), ), - title: user.id != 0 ? Text(user.name) : const Text("Group"), - trailing: request.status == Status.pending ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - FilledButton.tonal( - onPressed: () { - http.acceptFriendRequest(request.id).then((result){ - return; - }); - List userIDs = [curUser.id, user.id]; - http.postChatroom(userIDs).then((result){ - return; - }); - setState(() { - _list = _buildList(); - }); - }, - child: const Text("accept"), - ), - FilledButton.tonal( - onPressed: () { - http.rejectFriendRequest(request.id).then((result){ - return; - }); - setState(() { - _list = _buildList(); - }); - }, - child: const Text("reject"), - ) - ] - ) : ElevatedButton( - onPressed: () => - buildFightButton(context, FightGameSession(curUser, user)), - child: const Text('Fight!') - ), - ) - ) - ); + title: user.id != 0 ? Text(user.name) : const Text("Group"), + trailing: request.status == Status.pending ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + FilledButton.tonal( + onPressed: () { + http.acceptFriendRequest(request.id).then((result) { + return; + }); + setState(() { + _recvlist = _buildReceivedList(); + }); + }, + child: const Text("accept"), + ), + FilledButton.tonal( + onPressed: () { + http.rejectFriendRequest(request.id).then((result) { + return; + }); + setState(() { + _recvlist = _buildReceivedList(); + }); + }, + child: const Text("reject"), + ) + ] + ) : FilledButton.tonal( + onPressed: () { + if (game.id != 0) { + buildFightButton( + context, game); + } + else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + duration: Duration(seconds: 3), + content: Text('There was an error retrieving the request.'), + ) + ); + } + }, + child: const Text('Fight!') + ), + ) + ) + ); + } + } + return list; + } + + Future> _buildSentList() async { + HttpService http = HttpService(); + List list = List.empty(growable: true); + List myRequests = await http.getAllSentRequests(globals.uid); + myRequests.removeWhere((element) => element.status == Status.rejected); + for (var request in myRequests) { + FriendRequest otherRequest = await http.getFriendRequest(request.toUserID, request.fromUserID); + if (otherRequest.isEmpty() || (otherRequest.id != 0 && otherRequest.status == Status.pending)) { + User user = await http.getUserByID(request.toUserID); + FightGameSession game = await http.getFightGame(globals.uid, user.id); + list.add( + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ProfilePage( + curUser: curUser, + userViewed: user))); + }, + child: ListTile( + leading: ClipRRect( + borderRadius: BorderRadius.circular(60.0), + child: Image.asset( + profilePictures[user.pfp], fit: BoxFit.cover, + width: 60, + height: 60), + ), + title: user.id != 0 ? Text(user.name) : const Text("Group"), + trailing: request.status == Status.pending ? const SizedBox.shrink() + : FilledButton.tonal( + onPressed: () { + if (game.id != 0) { + buildFightButton( + context, game); + } + else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + duration: Duration(seconds: 3), + content: Text('There was an error retrieving the request.'), + ) + ); + } + }, + child: const Text('Fight!') + ), + ) + ) + ); + } } return list; } @@ -92,7 +165,8 @@ class PendingRequestsPageState extends State { HttpService().getUserByID(globals.uid).then((result) { curUser = result; }); - _list = _buildList(); + _recvlist = _buildReceivedList(); + _sentlist = _buildSentList(); } @override @@ -100,16 +174,51 @@ class PendingRequestsPageState extends State { return Scaffold( appBar: AppBar( title: const Text("Pending Requests"), + backgroundColor: Theme + .of(context) + .colorScheme + .primary, + centerTitle: true, ), body: Center( child: Column( children: [ - FutureBuilder(future: _list, builder: (BuildContext context, AsyncSnapshot> snapshot) { + const Text("Received Requests", style: TextStyle( + fontSize: 40)), + FutureBuilder(future: _recvlist, builder: (BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.hasData) { if (snapshot.data!.isEmpty) { return const Text( "No pending requests."); } + else { + return Expanded( + child: ListView.builder( + scrollDirection: Axis.vertical, + shrinkWrap: true, + itemCount: snapshot.data!.length, + itemBuilder: (context, index) { + return Column(children: [ + snapshot.data![index] + ]); + }) + ); + } + } + else { + return const CircularProgressIndicator(); + } + }), + const Text("Outgoing Requests", style: TextStyle( + fontSize: 40)), + SizedBox( + height: MediaQuery.of(context).size.height / 2.25, + child: FutureBuilder(future: _sentlist, builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + if (snapshot.data!.isEmpty) { + return const Text( + "No outgoing requests."); + } else { return ListView.builder( scrollDirection: Axis.vertical, @@ -126,6 +235,7 @@ class PendingRequestsPageState extends State { return const CircularProgressIndicator(); } }), + ), ], ), ), diff --git a/fightme_webapp/lib/profile_page.dart b/fightme_webapp/lib/profile_page.dart index 3f5c1d1..9d9b84d 100644 --- a/fightme_webapp/lib/profile_page.dart +++ b/fightme_webapp/lib/profile_page.dart @@ -4,9 +4,12 @@ import 'package:fightme_webapp/settings_page.dart'; import 'package:fightme_webapp/Providers/stats_provider.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'pending_requests.dart'; import 'Models/user.dart'; import 'Widgets/friend_request_button.dart'; import 'Models/httpservice.dart'; +import 'Models/fight_game_session.dart'; +import 'game_history_page.dart'; import 'Cosmetics/profile_pictures.dart'; import 'Models/auth_clear.dart'; @@ -23,6 +26,7 @@ class ProfilePage extends StatefulWidget { class ProfilePageState extends State { late Future> _friends; + late Future> _games; void _update() { setState(() { @@ -34,6 +38,7 @@ class ProfilePageState extends State { void initState() { super.initState(); _friends = HttpService().getFriends(widget.userViewed.id); + _games = HttpService().getDoneGames(widget.userViewed.id); WidgetsBinding.instance.addPostFrameCallback((_) { final statsProvider = Provider.of(context, listen: false); @@ -41,6 +46,35 @@ class ProfilePageState extends State { }); } + int getWonGames(List games) { + int count = 0; + for (var game in games) { + if (game.winnerID == widget.userViewed.id) { + count++; + } + } + return count; + } + + double getGameRatio(List games) { + int winCount = 0; // | || + int lossCount = 0;// || |_ + for (var game in games) { + if (game.winnerID == widget.userViewed.id) { + winCount++; + } + else { + lossCount++; + } + } + if (lossCount == 0) { + return winCount.toDouble(); + } + else { + return winCount / lossCount; + } + } + friendsListView(list) => ListView.builder( scrollDirection: Axis.vertical, shrinkWrap: true, @@ -247,7 +281,7 @@ class ProfilePageState extends State { alignment: Alignment.topLeft, margin: const EdgeInsets.symmetric(horizontal: 30.0), decoration: BoxDecoration(border: Border.all()), - child:FutureBuilder(future: _friends, builder: (BuildContext context, AsyncSnapshot> snapshot) { + child: FutureBuilder(future: _friends, builder: (BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.hasData) { if (snapshot.data!.isEmpty) { return const Text( @@ -264,19 +298,48 @@ class ProfilePageState extends State { ), ], ), - Column( - children: [ - const Text("Placeholder"), - Container( - height: MediaQuery.of(context).size.height / 2.5, - width: MediaQuery.of(context).size.width / 2 - 60.0, - alignment: Alignment.topLeft, - margin: const EdgeInsets.symmetric(horizontal: 30.0), - decoration: BoxDecoration(border: Border.all()), - child: const Text("What would you like to see here?", style: TextStyle( - fontSize: 40, )), - ), - ], + FutureBuilder(future: _games, builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + return Column( + children: [ + const Text("Games won"), + Text("${getWonGames(snapshot.data!)}"), + const Text("Win/loss ratio"), + Text(getGameRatio(snapshot.data!).toStringAsFixed(2)), + if (widget.userViewed.id == widget.curUser.id) ...[ + FilledButton.tonal( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const GameHistoryPage())); + }, + child: const Text("Game history"), + ), + FilledButton.tonal( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const PendingRequestsPage())); + }, + child: const Text("Pending Requests"), + ), + ], + ], + ); + } + else { + return const Column( + children: [ + Text("Games won"), + CircularProgressIndicator(), + Text("Win/loss ratio"), + CircularProgressIndicator(), + ], + ); + } + } ), ], ), diff --git a/fightme_webapp/lib/vs_page.dart b/fightme_webapp/lib/vs_page.dart index 90e05ae..d43801d 100644 --- a/fightme_webapp/lib/vs_page.dart +++ b/fightme_webapp/lib/vs_page.dart @@ -7,9 +7,8 @@ import 'Cosmetics/profile_pictures.dart'; import 'globals.dart' as globals; class VsPage extends StatefulWidget { - final User curUser; - const VsPage({super.key, required this.curUser}); + const VsPage({super.key}); @override State createState() => VsPageState(); @@ -23,10 +22,9 @@ class VsPageState extends State { List colors = [Colors.red, Colors.orangeAccent, Colors.amberAccent, Colors.yellowAccent[100]!, Colors.lightGreenAccent[400]!]; HttpService http = HttpService(); List list = List.empty(growable: true); - List myFights = List.empty(growable: true); // TODO: Write the fighting game session in the backend then write a function in HttpService. - myFights.removeWhere((element) => element.winnerID != 0); + List myFights = await http.getActiveGames(globals.uid); for (var fight in myFights) { - User user = fight.user2; + User user = fight.getOtherUser(globals.uid); list.add( TextButton( onPressed: () { @@ -38,16 +36,27 @@ class VsPageState extends State { child: Image.asset(profilePictures[user.pfp], fit: BoxFit.cover, width: 60, height: 60), ), title: user.id != 0 ? Text(user.name) : const Text("Group"), - trailing: Column( + subtitle: Column( + mainAxisSize: MainAxisSize.min, children: [ Row( children: [ + const Visibility( + maintainSize: true, + visible: false, + maintainAnimation: true, + maintainState: true, + child: Text("HP"), + ), + const SizedBox( + width: 5, + ), for (int i = 1; i <= 5; i++) - i > 5 - fight.user2hp ? Expanded( + i > 5 - fight.getOtherUserHp(globals.uid) ? Expanded( child: Container( height: 15.0, decoration: BoxDecoration( - color: colors[fight.user2hp - 1], + color: colors[fight.getOtherUserHp(globals.uid) - 1], border: Border.all( color: Colors.black, width: 0.0), @@ -72,11 +81,11 @@ class VsPageState extends State { width: 5, ), for (int i = 1; i <= 5; i++) - i <= fight.user1hp ? Expanded( + i <= fight.getUserHp(globals.uid) ? Expanded( child: Container( height: 15.0, decoration: BoxDecoration( - color: colors[fight.user1hp - 1], + color: colors[fight.getUserHp(globals.uid) - 1], border: Border.all( color: Colors.black, width: 0.0), @@ -88,6 +97,16 @@ class VsPageState extends State { height: 15.0, ), ), + const SizedBox( + width: 5, + ), + const Visibility( + maintainSize: true, + visible: false, + maintainAnimation: true, + maintainState: true, + child: Text("HP"), + ), ] ), ],