Creative Code

Lunar-(18) Message, 팔로우,팔로워, 오픈채팅기능 본문

Projects

Lunar-(18) Message, 팔로우,팔로워, 오픈채팅기능

빛하루 2024. 2. 3. 23:25

pages/chat.py

잠시 Lunar의 개발이 중단됩니다..!

 

왼쪽 Friend list에서 서로 팔로우가 되어있는 유저들 목록 출력이 되고 각 유저의 아이디를 클릭하면 대화내역 불러오는 기능, 오른쪽 사이드바에는 오픈채팅을 생성하고 (인원 제한 설정가능), 오픈채팅 버튼을 누르면 역시 대화내용들을 불러올 수 있다. participating rooms 에는 현재 참여중인 채팅방의 목록이 표시된다.

 

 

※pages/chat.py 코드

# lunar.state.home 모듈에서 필요한 State 및 HomeState를 가져옵니다.
import reflex as rx
from lunar.state.base import State
from lunar.state.home import HomeState

# 컴포넌트를 가져옵니다.
from ..components import container

color = "rgb(107,99,246)"
# 탭 버튼을 생성하는 함수
def tab_button(imagepath, href):
    """A tab switcher button."""
    return rx.link(
        rx.image(
            src=imagepath,
            height='40px',
            width='40px',
        ),
        display="inline-flex",
        align_items="center",
        py=3,
        px=2,
        href=href,  # 버튼 클릭 시 이동할 경로
    )

# 왼쪽에 표시되는 탭 스위처
def tabs():
    """The tab switcher displayed on the left."""
    return rx.box(
        rx.container(
            rx.hstack(
                rx.image(
                    src='/moon.png',
                    height='60px',
                    width='60px',         
                ),
                rx.text(
                    "Lunar", 
                    style={
                        "fontSize": "40px",
                        "fontWeight": "bolder",
                        "fontFamily": "Calibri, Calibri",
                        "background": "-webkit-linear-gradient(-45deg, #e04a3f, #4e8be6)",
                        "-webkit-background-clip": "text",
                        "color": "transparent",
                    },
                    center_content=True,
                ),  # 앱 이름
            ),
        ),
        rx.container(height='30px'),
        rx.vstack(
            rx.vstack(
                rx.text(
                    'Friend list',
                    font_Size='25px',
                    font_Weight='bold',
                    color = '#e0a353',
                ),
                rx.vstack(
                    rx.container(height='10px'),
                    rx.vstack(
                        rx.foreach(
                            HomeState.following,
                            lambda follow: rx.vstack(
                                rx.button(
                                    rx.vstack(
                                        rx.text(follow.followed_username),  # 팔로잉 중인 사용자의 사용자 이름
                                        width = '100%',
                                        align_items='start',
                                    ),
                                    on_click = HomeState.get_messages(follow.followed_username),
                                    width = '100%',
                                ),
                                width = '100%',
                                padding="1em",
                            ),
                        ),
                        border = '2px solid #000000',
                        border_radius = '20px',
                        box_shadow = '10px 10px 10px #76adde',
                        width = '100%',
                    ),
                    rx.container(height='10px'),
                    width='90%',
                    align_items='start',
                ),
                width = '100%',
                align_items='start',
            ),
            rx.container(height='10px'),
            align_items='start',
            width = '100%',
        ),
        py=4,
        overflow = 'auto',
    )

def sidebar():
    return rx.box(
        rx.container(height = '20px'),
        rx.text(
            'Open chat list',
            font_Size = '25px',
            font_weight='bolder',
            color = '#d19330',
        ),
        rx.vstack(
            rx.container(height='400px'),
            overflow='auto',
            border = '2px solid #000000',
            border_radius = '20px',
        ),
        rx.container(height='50px'),
        rx.text(
            'Participating rooms',
            font_Size = '25px',
            font_weight='bolder',
            color = '#2ee67a',
        ),
        rx.vstack(
            rx.container(height='30px'),
            border = '2px solid #000000',
            border_radius = '20px',
        ),
        py=4,
        overflow='auto',
    )

def message(message):
    box_color = rx.cond(message.send_user == HomeState.user.username, "#f3f7b7","#9dc6eb")
    align_direction = rx.cond(message.send_user== HomeState.user.username,"end","start")
    return rx.vstack(
        rx.box(
            rx.hstack(
                rx.hstack(
                    rx.container(width='2px'),
                    rx.avatar(name=message.send_user, size="sm"), 
                ),
                rx.box(
                    rx.hstack(
                        rx.text("@" + message.send_user, font_weight="bold"),  
                        rx.text("["+ message.created_at +"]"),
                    ),
                    rx.text(message.message, width="auto"), 
                    width = 'auto',
                ),
                rx.container(width = '2px'),
                py=4,
                gap=1,
                width='auto',
            ),
            border = '2px solid #000000', 
            border_radius='20px',
            background=box_color,
        ),
        rx.container(height='5px'),
        align_items=align_direction,
        width='100%',
    )

# 피드 영역
def feed(HomeState):
    return rx.box(
        rx.container(height='10px'),
        rx.text(
            HomeState.receive_user,
            font_Size = '25px',
            font_weight='bolder',
        ),
        rx.vstack(
            rx.vstack(
                rx.cond(
                    HomeState.messages,
                    rx.foreach(
                        HomeState.messages,
                        message
                    ),
                ),
                height='90%',
                width = '100%',
                overflow='auto',
            ),
            rx.hstack(
                rx.input(
                    on_blur=HomeState.set_kakaotalk,
                    placeholder="Write Message!",
                    border = '2px solid #000000',
                    border_radius = '10px',
                    width ='95%',
                ),
                rx.button(
                    rx.image(
                        src = '/dm.png',
                        height='auto',
                        width='auto',
                    ),
                    on_click = HomeState.sending_message,
                    border_radius="1em",
                    box_shadow="rgba(151, 65, 252, 0.8) 0 15px 30px -10px",
                    background_image="linear-gradient(144deg,#AF40FF,#5B42F3 50%,#00DDEB)",
                    box_sizing="border-box",
                    color="white",
                    opacity="0.6",
                    _hover={"opacity": 1},
                    width ='5%',
                ),
                width = '100%',
            ),
            height='90%',
            align_items='start',
        ),
        h="100%",
        overflow='auto'
    )

# 홈 페이지
def chat():
    State.check_login
    return rx.vstack(
        rx.grid(
            tabs(),
            feed(HomeState),
            sidebar(),
            grid_template_columns="2fr 5fr 2fr",

            width='97%',
            h="90vh",
            gap=4,
        ),
        rx.grid(
            rx.vstack(
                rx.container(height='5px'),
                rx.button(
                    rx.icon(tag="moon"),
                    on_click=rx.toggle_color_mode,
                    width = '80%',
                    _hover={"bg": "orange.400"},
                ),
                width = '100%',
            ),
            rx.vstack(
                rx.hstack(
                    tab_button('/Home.png','/'),
                    tab_button('/profile.png','/profile'),
                    tab_button('/map.png','/map'),
                    tab_button('/chat.png','/chat'),
                    tab_button('/Aichat.png','/aichat'),
                    tab_button('/diary.png','/diary'),
                    tab_button('/video.png','/video'),
                    tab_button('/game.png','/game'),
                    tab_button('/music.png','/music'),
                    tab_button('/weather.png','/weather'),
                    tab_button('/setting.png','/setting'),
                    margin_right='5px',
                    border="1px solid #000000",
                    border_radius="full",
                    box_Shadow = '10px 10px 5px #3083f0',
                ),
                width = '100%',
            ),
            rx.vstack(
                rx.container(height='5px'),
                rx.button(
                    "Sign out",
                    on_click=State.logout,
                    bg="#212963",
                    color="white",
                    _hover={"bg": "blue.600"},
                    width = '80%',
                ),
                width = '100%',
            ),
            width='97%',
            grid_template_columns="2fr 5fr 2fr",
        ),
    )

 

※각 기능을 담당하는 state/home.py부분

 

#follow 함수
    def follow_user(self, username):
        """Follow a user."""
        with rx.session() as session:
            friend = Follows(
                follower_username=self.user.username, followed_username=username     # Follow모델에 follower_username에 현재 로그인 된 유저이름저장
            )                                                                        # Follow모델에 followed_username에 팔로잉 한 유저의 이름 저장
            session.add(friend)                                                      # session에 friend이름으로 생성된 Follow모델 추가
            session.commit()                                                         # session 저장
    
    #unfollow 함수
    def unfollow_user(self, username):
        """Unfollow a user."""
        with rx.session() as session: 
            follow = (                                                                       # follow한 유저 목록 불러오기
                session.query(Follows)
                .filter_by(follower_username=self.user.username, followed_username=username)
                .first()
            )
            if follow:                                                                       
                session.delete(follow)                                                       # follow가 되어있으면 session에서 삭제
                session.commit()                                                             # session 저장

                # Refresh the followers list after unfollowing
                self.followers = (                                                           # 삭제 후 session에 저장되어있는 follow 목록 불러오기
                    session.query(Follows)                                                   
                    .filter(Follows.followed_username == self.user.username)
                    .all()
                )        
    
    # 팔로잉 목록을 불러오는 함수
    @rx.var                                                                                  # 실시간으로 값의 변화 감지
    def following(self) -> list[Follows]:
        """Get a list of users the current user is following."""
        if self.logged_in:                                                                   # 로그인 되어있을 때
            with rx.session() as session:
                return (
                    session.query(Follows)                                                   # session에 저장되어 있는 follow 목록 불러오기
                    .filter(Follows.follower_username == self.user.username)
                    .all()
                )
        return []

    # 팔로워 목록을 불러오는 함수
    @rx.var
    def followers(self) -> list[Follows]:                                                    
        """Get a list of users following the current user."""
        if self.logged_in:                                                                   # 로그인 되어 있을 시
            with rx.session() as session:
                return (
                    session.query(Follows)                                                   # session에 저장된 follower 목록 불러오기
                    .where(Follows.followed_username == self.user.username)
                    .all()
                )
        return []
        
      # 메시지를 보내는 함수
    def sending_message(self):
        if not self.logged_in:
            return rx.window_alert("Please log in to send a message")
        if self.receive_user=='':
            return rx.window_alert('Please write User!')
        if len(self.kakaotalk)==0:
            return rx.window_alert('Please write at least one character!')
        
        
        with rx.session() as session:
            send_message = message(
                send_user = self.user.username,
                receive_user = self.receive_user,
                message = self.kakaotalk,
                created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            )
            session.add(send_message)
            session.commit()
            self.kakaotalk = ''
        return self.get_messages(self.receive_user)
    
    # 메시지 내역을 불러오는 함수
    def get_messages(self,talk_user):
        self.receive_user = talk_user
        """Get tweets from the database."""
        with rx.session() as session:
            self.messages = (session.query(message)
                .filter(
                    or_(
                        and_(
                            message.send_user == self.user.username,
                            message.receive_user == self.receive_user,
                        ),
                        and_(
                            message.send_user == self.receive_user,
                            message.receive_user == self.user.username,
                        )
                    )
                )
                .all()                       # session에 저장된 모든 story를 가져옴 
            )