Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature/chat 대화 진행 화면 레이아웃 개발 완료 #10

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 51 additions & 19 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { SafeAreaView, StyleSheet } from "react-native";
import { Button, SafeAreaView, StyleSheet, Text, View } from "react-native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

import Home from "./screens/Home";
Expand All @@ -9,31 +9,63 @@ import Feedback from "./screens/Feedback";
import History from "./screens/History";
import { NavigationContainer } from "@react-navigation/native";
import { StatusBar } from "expo-status-bar";
import styled from "styled-components/native";
import styled, { ThemeProvider } from "styled-components/native";
import Vote from "./screens/Vote";
import { theme } from "./styled";

const SafeAreaViewContainer = styled(SafeAreaView)`
flex: 1;
`;

const Stack = createNativeStackNavigator();
export type RootStackParamList = {
Home: undefined;
Matching: undefined;
Chat: undefined;
Vote: undefined;
Feedback: undefined;
History: undefined;
};

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function App() {
return (
<SafeAreaViewContainer>
<NavigationContainer>
<StatusBar style="dark" />
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Matching" component={Matching} />
<Stack.Screen name="Chat" component={Chat} />
<Stack.Screen name="Feedback" component={Feedback} />
<Stack.Screen name="History" component={History} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaViewContainer>
<ThemeProvider theme={theme}>
<SafeAreaViewContainer>
<NavigationContainer>
<StatusBar style="dark" />
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Matching" component={Matching} />
<Stack.Screen
name="Chat"
component={Chat}
options={{
headerShown: true,
headerBackVisible: false,
headerBackTitleVisible: false,
title: "", // TODO: Chat Header Hide하는 방법찾기
}}
/>
<Stack.Screen
name="Vote"
component={Vote}
options={{
headerShown: true,
headerBackVisible: false,
headerBackTitleVisible: false,
title: "", // TODO: Chat Header Hide하는 방법찾기
}}
/>
<Stack.Screen name="Feedback" component={Feedback} />
<Stack.Screen name="History" component={History} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaViewContainer>
</ThemeProvider>
);
}
42 changes: 42 additions & 0 deletions src/components/ProfileImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from "react";
import { ImageSourcePropType } from "react-native";
import styled from "styled-components/native";

type ProfileImageSize = "sm" | "md" | "lg";

const SizeMap: { [k in ProfileImageSize]: number } = {
sm: 50,
md: 100,
lg: 150,
};

type ContainerProps = {
size: ProfileImageSize;
};

const Container = styled.View<ContainerProps>`
width: ${(props) => SizeMap[props.size] + "px"};
height: ${(props) => SizeMap[props.size] + "px"};
border-radius: ${(props) => SizeMap[props.size] / 2 + "px"};
overflow: hidden;
`;

const Image = styled.Image<ContainerProps>`
width: ${(props) => SizeMap[props.size] + "px"};
height: ${(props) => SizeMap[props.size] + "px"};
`;

interface Props {
size: ProfileImageSize;
image: ImageSourcePropType;
}

const ProfileImage: React.FC<Props> = ({ size = "sm", image }) => {
return (
<Container size={size}>
<Image size={size} source={image} />
</Container>
);
};

export default ProfileImage;
26 changes: 13 additions & 13 deletions src/constants/color.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
enum Color {
PVBlue = "#5988FF",
PVSkyblue = "#31BDFF",
PVRed = "#EF5D5D",
PVYellow = "#FCDE41",
PVGreen = "#00AD78",
PVBlack01 = "#303134",
PVBlack02 = "#6E7081",
PVBlack03 = "#AFB1C3",
PVBlack04 = "#CBCBD8",
PVBlack05 = "#E7E8F0",
PVBlack06 = "#F6F6F9",
White = "white"
PVBlue = "#5988FF",
PVSkyblue = "#31BDFF",
PVRed = "#EF5D5D",
PVYellow = "#FCDE41",
PVGreen = "#00AD78",
PVBlack01 = "#303134",
PVBlack02 = "#6E7081",
PVBlack03 = "#AFB1C3",
PVBlack04 = "#CBCBD8",
PVBlack05 = "#E7E8F0",
PVBlack06 = "#F6F6F9",
White = "white",
}

export { Color }
export { Color };
Binary file added src/img/mute.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/img/smile_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/img/unmute.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 0 additions & 13 deletions src/screens/Chat.tsx

This file was deleted.

56 changes: 56 additions & 0 deletions src/screens/Chat/Chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { BottomSection, Container, MiddleSection, TopSection } from "./style";
import React, { useEffect, useState } from "react";

import { Button } from "react-native";
import ChatUserCardList from "./ChatUserCardList";
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import { RootStackParamList } from "../../App";
import TimerHeader from "./TimerHeader";
import TooltipFooter from "./TooltipFooter";

const CHAT_DURATION_SECONDS = 60 * 5;
const CHAT_DURATION_MILLISECONDS = CHAT_DURATION_SECONDS * 1000;

const Chat: React.FC<NativeStackScreenProps<RootStackParamList, "Chat">> = ({
navigation,
}) => {
const [remainSec, setRemainSec] = useState<number>(CHAT_DURATION_SECONDS);

React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<Button onPress={() => navigation.goBack()} title="방 나가기" />
),
});
}, [navigation]);

useEffect(() => {
const endTime = new Date().getTime() + CHAT_DURATION_MILLISECONDS;
let id: NodeJS.Timer;
id = setInterval(() => {
const ms = endTime - new Date().getTime();
const remain = Math.round(ms / 1000);
setRemainSec(remain);
if (remain <= 0) clearInterval(id);
}, 1000);
return () => {
clearInterval(id);
};
}, []);

return (
<Container>
<TopSection>
<TimerHeader remainSeconds={remainSec} />
</TopSection>
<MiddleSection>
<ChatUserCardList />
</MiddleSection>
<BottomSection>
<TooltipFooter />
</BottomSection>
</Container>
);
};

export default Chat;
33 changes: 33 additions & 0 deletions src/screens/Chat/ChatUserCard/ChatUserCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Container, UserNameText, VoiceOnMark } from "./style";
import React, { useState } from "react";
import { muteIcon, smileProfileImage, unmuteIcon } from "../../../utils/images";

import EmotionBox from "./EmotionBox";
import { Image } from "react-native";
import ProfileImage from "../../../components/ProfileImage";

interface Props {
voiceOn?: boolean;
}

const ChatUserCard: React.FC<Props> = ({ voiceOn = false }) => {
const [isShownEmotionBox, setIsShownEmotionBox] = useState<boolean>(false);
const handleClick = () => {
setIsShownEmotionBox((prev) => !prev);
};
const closeEmotionBox = () => {
setIsShownEmotionBox(false);
};
return (
<Container selected={voiceOn} onPress={() => handleClick()}>
<ProfileImage size="md" image={smileProfileImage} />
<UserNameText>안녕하세요.</UserNameText>
<VoiceOnMark>
<Image source={voiceOn ? unmuteIcon : muteIcon} />
</VoiceOnMark>
{isShownEmotionBox && <EmotionBox onClose={() => closeEmotionBox()} />}
</Container>
);
};

export default ChatUserCard;
105 changes: 105 additions & 0 deletions src/screens/Chat/ChatUserCard/EmotionBox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React, { VoidFunctionComponent } from "react";
import styled from "styled-components/native";

const Container = styled.View`
position: absolute;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
border-radius: 75px;
overflow: hidden;
transform: translate(-75px, -75px);
flex-direction: row;
flex-wrap: wrap;
background-color: white;
`;

const EmotionButton = styled.TouchableOpacity`
width: 75px;
height: 75px;
justify-content: center;
align-items: center;
`;
const LeftTopButton = styled(EmotionButton)`
background-color: #f2f3fa;
`;

const RightTopButton = styled(EmotionButton)`
background-color: white;
`;

const LeftBottomButton = styled(EmotionButton)`
background-color: white;
`;

const RightBottomButton = styled(EmotionButton)`
background-color: #f2f3fa;
`;

const EmotionText = styled.Text`
font-size: 30px;
`;

const CircleHole = styled.View`
position: absolute;
left: 50%;
top: 50%;
width: 50px;
height: 50px;
border-radius: 25px;
transform: translate(-25px, -25px);
background-color: #f6f6f6;
`;

interface Props {
onClose(): void;
}

const EmotionBox: React.FC<Props> = ({ onClose }) => {
return (
<Container
style={{
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.23,
shadowRadius: 2.62,
elevation: 4,
}}
>
<LeftTopButton
onPress={() => {
onClose();
}}
>
<EmotionText>👀</EmotionText>
</LeftTopButton>
<RightTopButton
onPress={() => {
onClose();
}}
>
<EmotionText>👍</EmotionText>
</RightTopButton>
<LeftBottomButton
onPress={() => {
onClose();
}}
>
<EmotionText>🔥</EmotionText>
</LeftBottomButton>
<RightBottomButton
onPress={() => {
onClose();
}}
>
<EmotionText>💩</EmotionText>
</RightBottomButton>
<CircleHole />
</Container>
);
};
export default EmotionBox;
1 change: 1 addition & 0 deletions src/screens/Chat/ChatUserCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./ChatUserCard";
Loading