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

[FAB-135] Participant control #60

Merged
merged 19 commits into from
Oct 9, 2021
Merged
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
51 changes: 39 additions & 12 deletions fableous-be/handlers/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,37 @@ func (sess *activeSession) BroadcastMessage(message *pb.WSMessage) (err error) {
return
}

func (sess *activeSession) KickController(role pb.ControllerRole, announceHub bool) (err error) {
sess.mutex.Lock()
if targetConn, ok := sess.controllerConn[role]; ok {
err = utils.SendMessage(targetConn, &pb.WSMessage{
Type: pb.WSMessageType_JOIN,
Data: &pb.WSMessage_Join{
Join: &pb.WSJoinMessageData{
Role: pb.ControllerRole_HUB,
Joining: false,
},
},
})
_ = targetConn.Close()
}
delete(sess.controllerConn, role)
delete(sess.controllerName, role)
sess.mutex.Unlock()
if announceHub {
err = utils.SendMessage(sess.hubConn, &pb.WSMessage{
Type: pb.WSMessageType_JOIN,
Data: &pb.WSMessage_Join{
Join: &pb.WSJoinMessageData{
Role: role,
Joining: false,
},
},
})
}
return
}

func (m *module) ConnectHubWS(ctx *gin.Context, classroomID string) (err error) {
ctx.Request.Header.Del("Sec-Websocket-Extensions")
var session models.Session
Expand Down Expand Up @@ -153,6 +184,13 @@ func (m *module) HubCommandWorker(conn *websocket.Conn, sess *activeSession) (er
}
}
}
if clearedController := message.Data.(*pb.WSMessage_Control).Control.Clear; clearedController != pb.ControllerRole_NONE {
_ = utils.SendMessage(sess.hubConn, message)
_ = utils.SendMessage(sess.controllerConn[clearedController], message)
}
if kickedController := message.Data.(*pb.WSMessage_Control).Control.Kick; kickedController != pb.ControllerRole_NONE {
_ = sess.KickController(kickedController, false)
}
case pb.WSMessageType_IMAGE:
go m.SavePayload(sess, message, true)
case pb.WSMessageType_MANIFEST:
Expand Down Expand Up @@ -204,18 +242,7 @@ func (m *module) ControllerCommandWorker(conn *websocket.Conn, sess *activeSessi
if !websocket.IsCloseError(err, websocket.CloseGoingAway, websocket.CloseNormalClosure) {
log.Printf("[ControllerCommandWorker] failed reading message. %s\n", err)
}
sess.mutex.Lock()
delete(sess.controllerConn, role)
sess.mutex.Unlock()
_ = utils.SendMessage(sess.hubConn, &pb.WSMessage{
Type: pb.WSMessageType_JOIN,
Data: &pb.WSMessage_Join{
Join: &pb.WSJoinMessageData{
Role: role,
Joining: false,
},
},
})
_ = sess.KickController(role, true)
break
}
switch message.Type {
Expand Down
4 changes: 4 additions & 0 deletions fableous-fe/src/colors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable no-param-reassign */
/* eslint-disable no-bitwise */
import { colors as muiColors } from "@material-ui/core";

export const colors = {
orange: {
light: "#FF704F",
Expand All @@ -21,6 +23,8 @@ export const colors = {
},
black: "#000000",
green: "#43A047",
warning: muiColors.amber[800],
error: muiColors.red[700],
};

export const generateColor = (seed: string): string => {
Expand Down
12 changes: 8 additions & 4 deletions fableous-fe/src/components/ClassroomItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ const useStyles = makeStyles(() => ({
},
deleteButton: {
"&:hover": {
background: colors.red.main,
background: colors.error,
},
position: "absolute",
right: -8,
top: -8,
background: colors.red.main,
background: colors.error,
color: colors.white,
},
}));
Expand Down Expand Up @@ -277,7 +277,11 @@ export default function ClassroomItem(props: {
<Button onClick={() => setDeleting(false)} color="primary">
Cancel
</Button>
<Button onClick={handleDelete} color="secondary">
<Button
onClick={handleDelete}
style={{ color: colors.error }}
startIcon={<Icon fontSize="small">delete</Icon>}
>
Delete
</Button>
</DialogActions>
Expand All @@ -297,7 +301,7 @@ export default function ClassroomItem(props: {
</Button>
<Button
onClick={handleDeleteOngoingSession}
color="secondary"
style={{ color: colors.error }}
endIcon={<Icon fontSize="small">stop</Icon>}
>
Stop
Expand Down
10 changes: 7 additions & 3 deletions fableous-fe/src/components/StoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ export default function StoryItem(props: {
},
deleteButton: {
"&:hover": {
background: colors.red.main,
background: colors.error,
},
position: "absolute",
right: -8,
top: -8,
background: colors.red.main,
background: colors.error,
color: colors.white,
},
title: {
Expand Down Expand Up @@ -370,7 +370,11 @@ export default function StoryItem(props: {
<Button onClick={() => setDeleting(false)} color="primary">
Cancel
</Button>
<Button onClick={handleDelete} color="secondary">
<Button
onClick={handleDelete}
style={{ color: colors.error }}
startIcon={<Icon fontSize="small">delete</Icon>}
>
Delete
</Button>
</DialogActions>
Expand Down
33 changes: 21 additions & 12 deletions fableous-fe/src/components/canvas/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,19 @@ const Canvas = forwardRef<ImperativeCanvasRef, CanvasProps>(
[setCursor, role, wsConn]
);

const resetCanvas = () => {
const ctx = canvasRef.current.getContext(
"2d"
) as CanvasRenderingContext2D;
const { width, height } = canvasRef.current;
ctx.clearRect(0, 0, width, height);
setAudioPaths([]);
setTextShapes({});
setTextId(1);
setEditingTextId(0);
setCheckpointHistory([]);
};

const readMessage = useCallback(
async (ev: MessageEvent<ArrayBuffer>) => {
const msg = pb.WSMessage.decode(new Uint8Array(ev.data));
Expand Down Expand Up @@ -663,20 +676,25 @@ const Canvas = forwardRef<ImperativeCanvasRef, CanvasProps>(
msg.paint?.text as ToolMode.Paint
);
break;
case pb.WSMessageType.CONTROL:
if (msg.control?.clear === layer) {
resetCanvas();
}
break;
default:
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[
layer,
canvasRef,
placePaint,
placeFill,
placeText,
placeAudio,
placeCheckpoint,
placeUndo,
placeCursor,
placeAudio,
]
);

Expand Down Expand Up @@ -848,16 +866,7 @@ const Canvas = forwardRef<ImperativeCanvasRef, CanvasProps>(

// cleanup before moving to next page
useEffect(() => {
const ctx = canvasRef.current.getContext(
"2d"
) as CanvasRenderingContext2D;
const { width, height } = canvasRef.current;
ctx.clearRect(0, 0, width, height);
setAudioPaths([]);
setTextShapes({});
setTextId(1);
setEditingTextId(0);
setCheckpointHistory([]);
resetCanvas();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageNum]);

Expand Down
104 changes: 71 additions & 33 deletions fableous-fe/src/components/canvas/CanvasToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { ToolMode } from "../../constant";
import { ImperativeCanvasRef } from "./data";
import { proto as pb } from "../../proto/message_pb";
import BrushWidthIcon from "./BrushWidthIcon";
import CanvasToolbarTooltip from "./CanvasToolbarTooltip";
import ToolbarTooltip from "./ToolbarTooltip";
import { TutorialTargetId } from "../../tutorialTargetIds";
import { BRUSH_COLORS, BRUSH_WIDTHS } from "./constants";
import { colors } from "../../colors";
Expand Down Expand Up @@ -111,7 +111,7 @@ const CanvasToolbar = forwardRef<ImperativeCanvasRef, CanvasToolbarProps>(
pb.ControllerRole.BACKGROUND,
].includes(role) && (
<>
<CanvasToolbarTooltip
<ToolbarTooltip
isOpen={isWidthPickerOpen}
setIsOpen={setIsWidthPickerOpen}
tooltipTitle={
Expand Down Expand Up @@ -169,7 +169,7 @@ const CanvasToolbar = forwardRef<ImperativeCanvasRef, CanvasToolbarProps>(
strokeWidth={toolNormWidth * ICON_STROKE_WIDTH_RATIO}
/>
</IconButton>
</CanvasToolbarTooltip>
</ToolbarTooltip>
<IconButton
id={TutorialTargetId.EraseTool}
onClick={() => {
Expand All @@ -196,39 +196,77 @@ const CanvasToolbar = forwardRef<ImperativeCanvasRef, CanvasToolbarProps>(
>
<FormatColorFillIcon fontSize="large" />
</IconButton>
<CanvasToolbarTooltip
<ToolbarTooltip
isOpen={isColorPickerOpen}
setIsOpen={setIsColorPickerOpen}
// cannot use tailwind classes due to using mui portal so tooltip works corrrectly eventhough overflow set in parent
tooltipTitle={
<div
style={{
display: "flex",
}}
>
{BRUSH_COLORS.map((color) => (
<Button
component="div"
onClick={() => {
setToolColorRememberPrev(color);
setIsColorPickerOpen(false);
}}
style={{
backgroundColor: color,
width: "38px",
height: "38px",
padding: 0,
margin: 4,
minWidth: "auto",
borderRadius: 4,
border: `2px solid ${
toolColor === color ? colors.orange.main : "#0000"
}`,
}}
key={color}
/>
))}
</div>
<>
<div
style={{
display: "flex",
}}
>
{BRUSH_COLORS.slice(0, BRUSH_COLORS.length / 2).map(
(color) => (
<Button
component="div"
onClick={() => {
setToolColorRememberPrev(color);
setIsColorPickerOpen(false);
}}
style={{
backgroundColor: color,
width: "38px",
height: "38px",
padding: 0,
margin: 4,
minWidth: "auto",
borderRadius: 4,
border: `2px solid ${
toolColor === color
? colors.orange.main
: "#0000"
}`,
}}
key={color}
/>
)
)}
</div>
<div
style={{
display: "flex",
}}
>
{BRUSH_COLORS.slice(BRUSH_COLORS.length / 2).map(
(color) => (
<Button
component="div"
onClick={() => {
setToolColorRememberPrev(color);
setIsColorPickerOpen(false);
}}
style={{
backgroundColor: color,
width: "38px",
height: "38px",
padding: 0,
margin: 4,
minWidth: "auto",
borderRadius: 4,
border: `2px solid ${
toolColor === color
? colors.orange.main
: "#0000"
}`,
}}
key={color}
/>
)
)}
</div>
</>
}
>
<IconButton
Expand All @@ -247,7 +285,7 @@ const CanvasToolbar = forwardRef<ImperativeCanvasRef, CanvasToolbarProps>(
className="absolute bottom-1 right-1"
/>
</IconButton>
</CanvasToolbarTooltip>
</ToolbarTooltip>
</>
)}
{role === pb.ControllerRole.STORY && (
Expand Down
Loading