Skip to content

Commit

Permalink
release: v2.3.6 (#2167)
Browse files Browse the repository at this point in the history
* feat: add flat ai speaking teacher features (#2166)

* chore(version): upgrade version to v2.3.6
  • Loading branch information
hqer927 authored Jan 20, 2025
1 parent 2a6c824 commit 0f92441
Show file tree
Hide file tree
Showing 104 changed files with 15,518 additions and 10,377 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## [2.3.6](https://github.com/netless-io/flat/compare/v2.3.5...v2.3.6) (2025-01-20)

## [2.3.5](https://github.com/netless-io/flat/compare/v2.3.4...v2.3.5) (2024-09-13)


Expand Down
15 changes: 15 additions & 0 deletions cspell.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,21 @@ module.exports = {

// esbuild config
"metafile",

// ai teacher
"SVGAI",
"peppa",
"Peppa",
"Tian",
"RTCAI",
"Secens",
"haimianbaby",
"ironman",
"luotianxiaoyi",
"spongebob",
"sillybear",
"Tasker",
"Secen",
],
flagWords: ["fuck", "bitch", "asshole", "bullshit", "crap", "suck", "wtf"],
dictionaries: [
Expand Down
2 changes: 1 addition & 1 deletion desktop/main-app/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "flat",
"productName": "Flat",
"version": "2.3.5",
"version": "2.3.6",
"private": true,
"description": "",
"homepage": "https://github.com/netless-io/flat",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const MainPageLayoutWrapper = observer(function MainPageLayoutWrap({ chil
routeConfig.SmallClassPage,
routeConfig.OneToOnePage,
routeConfig.ReplayPage,
routeConfig.AIPage,
].some(({ path }) => {
return !!matchPath(location.pathname, {
path,
Expand Down
10 changes: 9 additions & 1 deletion desktop/renderer-app/src/route-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { LoginPage } from "@netless/flat-pages/src/LoginPage";
import { BigClassPage } from "@netless/flat-pages/src/BigClassPage";
import { SmallClassPage } from "@netless/flat-pages/src/SmallClassPage";
import { OneToOnePage } from "@netless/flat-pages/src/OneToOnePage";
import { AIPage } from "@netless/flat-pages/src/AIPage";
import { ModifyPeriodicRoomPage } from "@netless/flat-pages/src/ModifyPeriodicRoomPage";
import { PeriodicRoomDetailPage } from "@netless/flat-pages/src/PeriodicRoomDetailPage";
import { GeneralSettingPage } from "@netless/flat-pages/src/UserSettingPage/GeneralSettingPage";
Expand All @@ -32,6 +33,7 @@ export enum RouteNameType {
SmallClassPage = "SmallClassPage",
BigClassPage = "BigClassPage",
OneToOnePage = "OneToOnePage",
AIPage = "AIPage",
RoomDetailPage = "RoomDetailPage",
UserScheduledPage = "UserScheduledPage",
PeriodicRoomDetailPage = "PeriodicRoomDetailPage",
Expand All @@ -55,7 +57,8 @@ export enum RouteNameType {
export type ClassRouteName =
| RouteNameType.SmallClassPage
| RouteNameType.OneToOnePage
| RouteNameType.BigClassPage;
| RouteNameType.BigClassPage
| RouteNameType.AIPage;

export const routeConfig = {
[RouteNameType.SplashPage]: {
Expand Down Expand Up @@ -83,6 +86,11 @@ export const routeConfig = {
path: "/classroom/OneToOne/:roomUUID/:ownerUUID/",
component: OneToOnePage,
},
[RouteNameType.AIPage]: {
title: "AIPage",
path: "/classroom/AIPage/:roomUUID/:ownerUUID/",
component: AIPage,
},
[RouteNameType.BigClassPage]: {
title: "BigClassPage",
path: "/classroom/BigClass/:roomUUID/:ownerUUID/",
Expand Down
5 changes: 4 additions & 1 deletion desktop/renderer-app/src/stores/ipc-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export class IPCStore {
}
case routeConfig[RouteNameType.BigClassPage].path:
case routeConfig[RouteNameType.SmallClassPage].path:
case routeConfig[RouteNameType.OneToOnePage].path: {
case routeConfig[RouteNameType.OneToOnePage].path:
case routeConfig[RouteNameType.AIPage].path: {
this.ipcAsyncByMainWindow("set-win-size", {
...constants.PageSize.Class,
autoCenter: true,
Expand Down Expand Up @@ -116,6 +117,7 @@ export class IPCStore {
case routeConfig[RouteNameType.BigClassPage].path:
case routeConfig[RouteNameType.SmallClassPage].path:
case routeConfig[RouteNameType.OneToOnePage].path:
case routeConfig[RouteNameType.AIPage].path:
case routeConfig[RouteNameType.ReplayPage].path: {
this.ipcAsyncByMainWindow("intercept-native-window-close", {
intercept: false,
Expand Down Expand Up @@ -154,6 +156,7 @@ export class IPCStore {
routeConfig.LoginPage,
routeConfig.BigClassPage,
routeConfig.OneToOnePage,
routeConfig.AIPage,
routeConfig.SmallClassPage,
].some(({ path }) => {
return !!matchPath(pathname, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function useURLAppLauncher(): void {
RouteNameType.SmallClassPage,
RouteNameType.OneToOnePage,
RouteNameType.BigClassPage,
RouteNameType.AIPage,
];

for (const name of classPages) {
Expand Down
4 changes: 4 additions & 0 deletions docs/releases/v2.3.6/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

## Features

1. Added flat ai speaking teacher features
4 changes: 4 additions & 0 deletions docs/releases/v2.3.6/zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## 新增
1. flat口语老师功能


Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,4 @@
.chat-user-status.is-teacher {
color: var(--grey-6);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useUpdate } from "react-use";
import { Observer, observer } from "mobx-react-lite";
import {
Expand Down Expand Up @@ -183,3 +183,34 @@ export const ChatMessageList = /* @__PURE__ */ observer<ChatMessageListProps>(
);
},
);

export const ReadOnlyChatMessageList = /* @__PURE__ */ observer<ChatMessageListProps>(
function ReadOnlyChatMessageList({ userUUID, messages, getUserByUUID, generateAvatar }) {
const showMessages = useMemo(() => {
return messages
.reduce((preValue, curValue, curIndex: number) => {
if (curIndex === 0) {
preValue.unshift(curValue);
} else if (preValue[0].timestamp < curValue.timestamp) {
preValue.unshift(curValue);
}
return preValue;
}, [] as ChatMsg[])
.slice(0, 2);
}, [messages]);
return (
<div className="chat-message-list">
{showMessages.map(message => (
<ChatMessage
key={message.uuid}
generateAvatar={generateAvatar}
message={message}
messageUser={getUserByUUID(message.senderID)}
userUUID={userUUID}
onMount={() => void 0}
/>
))}
</div>
);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,40 @@ import chatMessagesDefaultDarkSVG from "./icons/chat-messages-default-dark.svg";
import React, { useContext } from "react";
import { observer } from "mobx-react-lite";
import { ChatTypeBox, ChatTypeBoxProps } from "../ChatTypeBox";
import { ChatMessageList, ChatMessageListProps } from "../ChatMessageList";
import { ChatMessageList, ChatMessageListProps, ReadOnlyChatMessageList } from "../ChatMessageList";
import { DarkModeContext } from "../../FlatThemeProvider";

export type ChatMessagesProps = ChatTypeBoxProps & ChatMessageListProps;
export type ChatMessagesProps = ChatTypeBoxProps & ChatMessageListProps & { readOnly?: boolean };

export const ChatMessages = /* @__PURE__ */ observer<ChatMessagesProps>(function ChatMessages({
messages,
readOnly,
...restProps
}) {
const isDark = useContext(DarkModeContext);

return (
<div className="chat-messages-wrap">
<div className="chat-messages">
{messages.length > 0 ? (
<div className="chat-messages-box">
<ChatMessageList messages={messages} {...restProps} />
{readOnly ? (
<ReadOnlyChatMessageList messages={messages} {...restProps} />
) : (
<ChatMessageList messages={messages} {...restProps} />
)}
</div>
) : (
<div className="chat-messages-default">
<img src={isDark ? chatMessagesDefaultDarkSVG : chatMessagesDefaultSVG} />
</div>
(!readOnly && (
<div className="chat-messages-default">
<img
src={isDark ? chatMessagesDefaultDarkSVG : chatMessagesDefaultSVG}
/>
</div>
)) ||
null
)}
</div>
<ChatTypeBox {...restProps} />
{!!restProps.onMessageSend && <ChatTypeBox {...restProps} />}
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface ChatTypeBoxProps {
isCreator: boolean;
isBan: boolean;
onBanChange: () => void;
onMessageSend: (text: string) => Promise<void>;
onMessageSend?: (text: string) => Promise<void>;
}

export const ChatTypeBox = /* @__PURE__ */ observer<ChatTypeBoxProps>(function ChatTypeBox({
Expand All @@ -32,6 +32,9 @@ export const ChatTypeBox = /* @__PURE__ */ observer<ChatTypeBoxProps>(function C
if (isSending || trimmedText.length <= 0) {
return;
}
if (!onMessageSend) {
return;
}

updateSending(true);

Expand Down
27 changes: 16 additions & 11 deletions packages/flat-components/src/components/ChatPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { ChatTabTitle, ChatTabTitleProps } from "./ChatTabTitle";
export type ChatPanelProps = {
totalUserCount?: number;
onClickTotalUsersCount?: () => void;
readOnly?: boolean;
cc?: React.ReactNode;
} & ChatTabTitleProps &
Omit<ChatMessagesProps, "visible">;

Expand All @@ -17,17 +19,20 @@ export const ChatPanel = /* @__PURE__ */ observer<ChatPanelProps>(function ChatP

return (
<div className="chat-panel">
<div className="chat-panel-header">
<ChatTabTitle>
<span>{t("messages")}</span>
</ChatTabTitle>
{props.totalUserCount && (
<span className="chat-tab-subtitle" onClick={props.onClickTotalUsersCount}>
{t("total-users-count", { count: props.totalUserCount })}
</span>
)}
</div>
<ChatMessages {...props} visible />
{!props.readOnly && (
<div className="chat-panel-header">
<ChatTabTitle>
<span>{t("messages")}</span>
</ChatTabTitle>
{props.totalUserCount && (
<span className="chat-tab-subtitle" onClick={props.onClickTotalUsersCount}>
{t("total-users-count", { count: props.totalUserCount })}
</span>
)}
</div>
)}
<ChatMessages {...props} visible readOnly={props.readOnly} />
{props.cc && <div className="chat-panel-cc">{props.cc}</div>}
</div>
);
});
Expand Down
21 changes: 20 additions & 1 deletion packages/flat-components/src/components/ChatPanel/style.less
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@
.ReactVirtualized__List {
outline: none;
}

.chat-panel-cc {
position: absolute;
bottom: 50px;
right: 4px;

.video-avatar-chat-msg-btn {
width: 40px;
height: 40px;
border-radius: 20px;
border: none;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
pointer-events: all;
}
}
}

.chat-panel-header {
Expand Down Expand Up @@ -84,4 +103,4 @@
.chat-panel-header {
border-bottom-color: var(--grey-8);
}
}
}
11 changes: 10 additions & 1 deletion packages/flat-components/src/components/ChatPanel/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,13 @@ export type ChatMsgUserGuide = {
senderID: string;
};

export type ChatMsg = ChatMsgRoomMessage | ChatMsgNotice | ChatMsgBan | ChatMsgUserGuide;
export type AIChatMsgUser = ChatMsgRoomMessage & {
isFinal: boolean;
};

export type ChatMsg =
| ChatMsgRoomMessage
| ChatMsgNotice
| ChatMsgBan
| ChatMsgUserGuide
| AIChatMsgUser;
Loading

0 comments on commit 0f92441

Please sign in to comment.