From 60b8dd7bab46d5a8f141b73564669980a79db5c4 Mon Sep 17 00:00:00 2001 From: tyler Date: Tue, 30 Jan 2024 12:24:07 -0500 Subject: [PATCH] Added chat commands --- NOTES.md | 16 +- app.go | 42 +++- frontend/src/components/ChatMessage.css | 44 ++++ frontend/src/components/ChatMessage.jsx | 28 +++ frontend/src/components/Highlight.jsx | 2 - frontend/src/components/StreamChat.css | 76 ------- frontend/src/components/StreamChat.jsx | 182 ++------------- frontend/src/components/StreamChatBot.css | 104 +++++++++ frontend/src/components/StreamChatBot.jsx | 212 ++++++++++++++++++ frontend/src/components/StreamChatMessage.css | 165 +++++++++++++- frontend/src/components/StreamChatMessage.jsx | 176 +++++++++++++-- frontend/src/screens/Dashboard.css | 10 +- frontend/src/screens/Dashboard.jsx | 43 ++-- frontend/src/screens/SignIn.jsx | 2 +- go.mod | 10 +- go.sum | 24 +- internal/api/api.go | 2 +- internal/chatbot/chatbot.go | 186 +++++++++++++-- internal/config/config.go | 30 ++- licenses/github.com/twbs/icons/LICENSE | 21 ++ 20 files changed, 1039 insertions(+), 336 deletions(-) create mode 100644 frontend/src/components/ChatMessage.css create mode 100644 frontend/src/components/ChatMessage.jsx create mode 100644 frontend/src/components/StreamChatBot.css create mode 100644 frontend/src/components/StreamChatBot.jsx create mode 100644 licenses/github.com/twbs/icons/LICENSE diff --git a/NOTES.md b/NOTES.md index fe1d68f..ea5a2c9 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,10 +1,16 @@ # Doing -New chat message modal: -- submit button in modal component (check for button on click and button text) - - primary button (save) - - secondary button (delete) -- on close: reset values (in stream chat message component) +Show error when choosing file "chooseFile" +Show filename in chat bot list +Add styling to choose file button + +Commands +- specify for follower/subscriber/locals only/rants + - check badges for subscriber and locals + +Update +- github.com/rhysd/go-github-selfupdate +- github.com/inconshreveable/go-update Create loading indicator before API is called diff --git a/app.go b/app.go index b7ae59e..ac052b4 100644 --- a/app.go +++ b/app.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "os" + "path/filepath" "sync" "time" @@ -13,6 +14,7 @@ import ( "github.com/tylertravisty/rum-goggles/internal/chatbot" "github.com/tylertravisty/rum-goggles/internal/config" rumblelivestreamlib "github.com/tylertravisty/rumble-livestream-lib-go" + "github.com/wailsapp/wails/v2/pkg/runtime" ) type chat struct { @@ -141,11 +143,11 @@ func (a *App) ChatBotMessages(cid string) (map[string]config.ChatMessage, error) return channel.ChatBot.Messages, nil } -func (a *App) AddChatMessage(cid string, asChannel bool, interval time.Duration, message string) (map[string]config.ChatMessage, error) { +func (a *App) AddChatMessage(cid string, asChannel bool, command string, interval time.Duration, onCommand bool, text string, textFile string) (map[string]config.ChatMessage, error) { var err error a.cfgMu.Lock() defer a.cfgMu.Unlock() - _, err = a.cfg.NewChatMessage(cid, asChannel, interval, message) + _, err = a.cfg.NewChatMessage(cid, asChannel, command, interval, onCommand, text, textFile) if err != nil { a.logError.Println("error creating new chat:", err) return nil, fmt.Errorf("Error creating new chat message. Try again.") @@ -192,11 +194,11 @@ func (a *App) DeleteChatMessage(mid string, cid string) (map[string]config.ChatM return a.cfg.Channels[cid].ChatBot.Messages, nil } -func (a *App) UpdateChatMessage(id string, cid string, asChannel bool, interval time.Duration, message string) (map[string]config.ChatMessage, error) { +func (a *App) UpdateChatMessage(id string, cid string, asChannel bool, command string, interval time.Duration, onCommand bool, text string, textFile string) (map[string]config.ChatMessage, error) { var err error a.cfgMu.Lock() defer a.cfgMu.Unlock() - _, err = a.cfg.UpdateChatMessage(id, cid, asChannel, interval, message) + _, err = a.cfg.UpdateChatMessage(id, cid, asChannel, command, interval, onCommand, text, textFile) if err != nil { a.logError.Println("error updating chat message:", err) return nil, fmt.Errorf("Error updating chat message. Try again.") @@ -240,7 +242,13 @@ func (a *App) NewChatBot(cid string, username string, password string, streamUrl err = a.cb.Login(username, password) if err != nil { a.logError.Println("error logging into chat bot:", err) - return fmt.Errorf("Error logging in. Try Again.") + return fmt.Errorf("Error logging in. Try again.") + } + + err = a.cb.StartChatStream() + if err != nil { + a.logError.Println("error starting chat stream:", err) + return fmt.Errorf("Error connecting to chat. Try again.") } // a.cb = cb @@ -271,6 +279,11 @@ func (a *App) resetChatBot() error { return fmt.Errorf("error stopping all chat bot messages: %v", err) } + err = a.cb.StopChatStream() + if err != nil { + return fmt.Errorf("error stopping chat stream: %v", err) + } + err = a.cb.Logout() if err != nil { return fmt.Errorf("error logging out of chat bot: %v", err) @@ -343,3 +356,22 @@ func (a *App) updateChatBotConfig(cfg config.ChatBot) { a.cb.Cfg = cfg } } + +func (a *App) OpenFileDialog() (string, error) { + home, err := os.UserHomeDir() + if err != nil { + a.logError.Println("error getting home directory:", err) + return "", fmt.Errorf("Error opening file explorer. Try again.") + } + filepath, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{DefaultDirectory: home}) + if err != nil { + a.logError.Println("error opening file dialog:", err) + return "", fmt.Errorf("Error opening file explorer. Try again.") + } + + return filepath, err +} + +func (a *App) FilepathBase(path string) string { + return filepath.Base(path) +} diff --git a/frontend/src/components/ChatMessage.css b/frontend/src/components/ChatMessage.css new file mode 100644 index 0000000..5e5a270 --- /dev/null +++ b/frontend/src/components/ChatMessage.css @@ -0,0 +1,44 @@ +.chat-message { + align-items: start; + background-color: rgba(6,23,38,1); + padding: 10px; + display: flex; + flex-direction: row; +} + +.chat-message-user-image { + border-radius: 50%; + height: 22px; + margin-right: 8px; + width: 22px; +} + +.chat-message-user-initial { + align-items: center; + background-color: #37c; + border: 1px solid #eee; + border-radius: 50%; + color: #eee; + display: flex; + font-family: sans-serif; + font-size: 12px; + font-weight: bold; + height: 22px; + justify-content: center; + margin-right: 8px; + width: 22px; +} + +.chat-message-username { + color: white; + font-family: sans-serif; + font-size: 14px; + font-weight: bold; + margin-right: 3px; +} + +.chat-message-text { + color: white; + font-family: sans-serif; + font-size: 14px; +} \ No newline at end of file diff --git a/frontend/src/components/ChatMessage.jsx b/frontend/src/components/ChatMessage.jsx new file mode 100644 index 0000000..ca18b71 --- /dev/null +++ b/frontend/src/components/ChatMessage.jsx @@ -0,0 +1,28 @@ +import './ChatMessage.css'; + +function ChatMessage(props) { + const upperInitial = () => { + return props.message.username[0].toUpperCase(); + }; + + return ( +
+ {props.message.image === '' || props.message.image === undefined ? ( + {upperInitial()} + ) : ( + + )} +
+ + {props.message.username} + + {props.message.text} +
+
+ ); +} + +export default ChatMessage; diff --git a/frontend/src/components/Highlight.jsx b/frontend/src/components/Highlight.jsx index 5d355ca..3d00a63 100644 --- a/frontend/src/components/Highlight.jsx +++ b/frontend/src/components/Highlight.jsx @@ -17,13 +17,11 @@ function Highlight(props) { }; const stopwatchString = () => { - console.log(props.value); if (isNaN(Date.parse(props.value))) { return '--:--'; } let now = new Date(); let date = new Date(props.value); - console.log(date); let diff = now - date; let msMinute = 1000 * 60; diff --git a/frontend/src/components/StreamChat.css b/frontend/src/components/StreamChat.css index 0560425..e75b20c 100644 --- a/frontend/src/components/StreamChat.css +++ b/frontend/src/components/StreamChat.css @@ -3,43 +3,6 @@ height: 100%; } -.stream-chat-button { - align-items: center; - border: none; - display: flex; - justify-content: center; - padding: 0px; -} - -.stream-chat-button:hover { - cursor: pointer; -} - -.stream-chat-button-title { - background-color: rgba(6,23,38,1); -} - -.stream-chat-button-chat { - align-items: center; - background-color: #000312; - display: flex; - justify-content: center; - width: 10%; -} - -.stream-chat-icon { - height: 24px; - width: 24px; -} - -.stream-chat-controls { - align-items: center; - display: flex; - flex-direction: row; - justify-content: space-between; - width: 55px; -} - .stream-chat-header { align-items: center; background-color: rgba(6,23,38,1); @@ -52,45 +15,6 @@ text-align: left; } -.stream-chat-item { - border-bottom: 1px solid #82b1ff; - box-sizing: border-box; - color: white; - display: flex; - flex-direction: row; - font-family: sans-serif; - justify-content: space-between; - padding: 10px 20px; - width: 100%; -} - -.stream-chat-item-sender { - align-items: center; - box-sizing: border-box; - display: flex; - justify-content: left; - padding-left: 10px; - width: 20%; -} - -.stream-chat-item-interval { - align-items: center; - box-sizing: border-box; - display: flex; - justify-content: left; - padding-left: 10px; - width: 20%; -} - -.stream-chat-item-message { - align-items: center; - display: flex; - justify-content: left; - overflow: hidden; - white-space: nowrap; - width: 50%; -} - .stream-chat-list { overflow-y: auto; height: calc(100vh - 84px - 40px - 179px); diff --git a/frontend/src/components/StreamChat.jsx b/frontend/src/components/StreamChat.jsx index 6394850..3414bb7 100644 --- a/frontend/src/components/StreamChat.jsx +++ b/frontend/src/components/StreamChat.jsx @@ -1,42 +1,34 @@ -import { useEffect, useState } from 'react'; -import { StartChatBotMessage, StopChatBotMessage } from '../../wailsjs/go/main/App'; +import { useState } from 'react'; import { EventsOn } from '../../wailsjs/runtime/runtime'; -import { GearFill, Pause, Play, PlusCircle } from '../assets/icons'; +import ChatMessage from './ChatMessage'; import './StreamChat.css'; -import { SmallModal } from './Modal'; function StreamChat(props) { - const sortChatsAlpha = () => { - let keys = Object.keys(props.chats); + const [messages, setMessages] = useState([ + { + color: '#ec131f', + image: 'https://ak2.rmbl.ws/z0/V/m/v/E/VmvEe.asF.4-18osof-s35kf7.jpeg', + username: 'tylertravisty', + text: 'Hello, world this is si s a a sdf asd f', + }, + { + username: 'tylertravisty', + text: 'Another chat message', + }, + ]); - let sorted = [...keys].sort((a, b) => - props.chats[a].text.toLowerCase() > props.chats[b].text.toLowerCase() ? 1 : -1 - ); - return sorted; - }; + EventsOn('ChatMessage', (msg) => { + setMessages(...messages, msg); + }); return (
{props.title} -
- - -
- {sortChatsAlpha().map((chat, index) => ( - + {messages.map((message, index) => ( + ))}
@@ -44,139 +36,3 @@ function StreamChat(props) { } export default StreamChat; - -function StreamChatItem(props) { - const [active, setActive] = useState(props.chat.active); - const [error, setError] = useState(''); - - const changeActive = (bool) => { - console.log('ChangeActive:', bool); - props.chat.active = bool; - setActive(bool); - }; - - useEffect(() => { - EventsOn('ChatBotMessageActive-' + props.chat.id, (mid) => { - console.log('ChatBotMessageActive', props.chat.id, mid); - if (mid === props.chat.id) { - changeActive(true); - } - }); - - EventsOn('ChatBotMessageError-' + props.chat.id, (mid) => { - console.log('ChatBotMessageError', props.chat.id, mid); - if (mid === props.chat.id) { - changeActive(false); - } - }); - }, []); - - const prependZero = (value) => { - if (value < 10) { - return '0' + value; - } - - return '' + value; - }; - - const printInterval = (interval) => { - let hours = Math.floor(interval / 3600); - let minutes = Math.floor(interval / 60 - hours * 60); - let seconds = Math.floor(interval - hours * 3600 - minutes * 60); - - // hours = prependZero(hours); - // minutes = prependZero(minutes); - // seconds = prependZero(seconds); - // return hours + ':' + minutes + ':' + seconds; - - return hours + 'h ' + minutes + 'm ' + seconds + 's'; - }; - - const intervalToTimer = (interval) => { - let hours = Math.floor(interval / 3600); - let minutes = Math.floor(interval / 60 - hours * 60); - let seconds = Math.floor(interval - hours * 3600 - minutes * 60); - - if (minutes !== 0) { - seconds = prependZero(seconds); - } - if (hours !== 0) { - minutes = prependZero(minutes); - } - if (hours === 0) { - hours = ''; - if (minutes === 0) { - minutes = ''; - if (seconds === 0) { - seconds = ''; - } - } - } - - return hours + minutes + seconds; - }; - - const openChat = () => { - props.onItemClick( - props.chat.id, - props.chat.as_channel, - intervalToTimer(props.chat.interval), - props.chat.text - ); - }; - - const startMessage = () => { - StartChatBotMessage(props.chat.id) - .then(() => { - changeActive(true); - }) - .catch((error) => { - setError(error); - }); - }; - - const stopMessage = () => { - StopChatBotMessage(props.chat.id).then(() => { - changeActive(false); - }); - }; - - return ( - <> - setError('')} - show={error !== ''} - style={{ minWidth: '300px', maxWidth: '200px', maxHeight: '200px' }} - title={'Error'} - message={error} - submitButton={'OK'} - onSubmit={() => setError('')} - /> -
openChat()}> - {props.chat.text} - - {printInterval(props.chat.interval)} - - - {props.chat.as_channel ? 'Channel' : 'User'} - - -
- - ); -} diff --git a/frontend/src/components/StreamChatBot.css b/frontend/src/components/StreamChatBot.css new file mode 100644 index 0000000..3526c82 --- /dev/null +++ b/frontend/src/components/StreamChatBot.css @@ -0,0 +1,104 @@ +.stream-chatbot { + width: 100%; + height: 100%; +} + +.stream-chatbot-button { + align-items: center; + border: none; + display: flex; + justify-content: center; + padding: 0px; +} + +.stream-chatbot-button:hover { + cursor: pointer; +} + +.stream-chatbot-button-title { + background-color: rgba(6,23,38,1); +} + +.stream-chatbot-button-chat { + align-items: center; + background-color: #000312; + display: flex; + justify-content: center; + width: 10%; +} + +.stream-chatbot-icon { + height: 24px; + width: 24px; +} + +.stream-chatbot-controls { + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; + width: 55px; +} + +.stream-chatbot-header { + align-items: center; + background-color: rgba(6,23,38,1); + border-bottom: 1px solid #495a6a; + display: flex; + flex-direction: row; + justify-content: space-between; + height: 19px; + padding: 10px 20px; + text-align: left; +} + +.stream-chatbot-item { + border-bottom: 1px solid #82b1ff; + box-sizing: border-box; + color: white; + display: flex; + flex-direction: row; + font-family: sans-serif; + justify-content: space-between; + padding: 10px 20px; + width: 100%; +} + +.stream-chatbot-item-sender { + align-items: center; + box-sizing: border-box; + display: flex; + justify-content: left; + padding-left: 10px; + width: 20%; +} + +.stream-chatbot-item-interval { + align-items: center; + box-sizing: border-box; + display: flex; + justify-content: left; + padding-left: 10px; + width: 20%; +} + +.stream-chatbot-item-message { + align-items: center; + display: flex; + justify-content: left; + overflow: hidden; + white-space: nowrap; + width: 50%; +} + +.stream-chatbot-list { + overflow-y: auto; + height: calc(100vh - 84px - 40px - 179px); +} + +.stream-chatbot-title { + color: white; + font-family: sans-serif; + font-size: 12px; + font-weight: bold; +} \ No newline at end of file diff --git a/frontend/src/components/StreamChatBot.jsx b/frontend/src/components/StreamChatBot.jsx new file mode 100644 index 0000000..012c4ba --- /dev/null +++ b/frontend/src/components/StreamChatBot.jsx @@ -0,0 +1,212 @@ +import { useEffect, useState } from 'react'; +import { FilepathBase, StartChatBotMessage, StopChatBotMessage } from '../../wailsjs/go/main/App'; +import { EventsOn } from '../../wailsjs/runtime/runtime'; +import { GearFill, Pause, Play, PlusCircle } from '../assets/icons'; +import './StreamChatBot.css'; +import { SmallModal } from './Modal'; + +function StreamChatBot(props) { + const sortChatsAlpha = () => { + let keys = Object.keys(props.chats); + + let sorted = [...keys].sort((a, b) => + props.chats[a].text.toLowerCase() > props.chats[b].text.toLowerCase() ? 1 : -1 + ); + return sorted; + }; + + return ( +
+
+ {props.title} +
+ + +
+
+
+ {sortChatsAlpha().map((chat, index) => ( + + ))} +
+
+ ); +} + +export default StreamChatBot; + +function StreamChatItem(props) { + const [active, setActive] = useState(props.chat.active); + const [error, setError] = useState(''); + const [filename, setFilename] = useState(''); + + useEffect(() => { + if (props.chat.text_file !== '') { + FilepathBase(props.chat.text_file).then((name) => { + setFilename(name); + }); + } + }, []); + + const changeActive = (bool) => { + console.log('ChangeActive:', bool); + props.chat.active = bool; + setActive(bool); + }; + + useEffect(() => { + EventsOn('ChatBotCommandActive-' + props.chat.id, (mid) => { + console.log('ChatBotCommandActive', props.chat.id, mid); + if (mid === props.chat.id) { + changeActive(true); + } + }); + + EventsOn('ChatBotCommandError-' + props.chat.id, (mid) => { + console.log('ChatBotCommandError', props.chat.id, mid); + if (mid === props.chat.id) { + changeActive(false); + } + }); + + EventsOn('ChatBotMessageActive-' + props.chat.id, (mid) => { + console.log('ChatBotMessageActive', props.chat.id, mid); + if (mid === props.chat.id) { + changeActive(true); + } + }); + + EventsOn('ChatBotMessageError-' + props.chat.id, (mid) => { + console.log('ChatBotMessageError', props.chat.id, mid); + if (mid === props.chat.id) { + changeActive(false); + } + }); + }, []); + + const prependZero = (value) => { + if (value < 10) { + return '0' + value; + } + + return '' + value; + }; + + const printInterval = (interval) => { + let hours = Math.floor(interval / 3600); + let minutes = Math.floor(interval / 60 - hours * 60); + let seconds = Math.floor(interval - hours * 3600 - minutes * 60); + + // hours = prependZero(hours); + // minutes = prependZero(minutes); + // seconds = prependZero(seconds); + // return hours + ':' + minutes + ':' + seconds; + + return hours + 'h ' + minutes + 'm ' + seconds + 's'; + }; + + const intervalToTimer = (interval) => { + let hours = Math.floor(interval / 3600); + let minutes = Math.floor(interval / 60 - hours * 60); + let seconds = Math.floor(interval - hours * 3600 - minutes * 60); + + if (minutes !== 0) { + seconds = prependZero(seconds); + } + if (hours !== 0) { + minutes = prependZero(minutes); + } + if (hours === 0) { + hours = ''; + if (minutes === 0) { + minutes = ''; + if (seconds === 0) { + seconds = ''; + } + } + } + + return hours + minutes + seconds; + }; + + const openChat = () => { + props.onItemClick( + props.chat.id, + props.chat.as_channel, + props.chat.command, + intervalToTimer(props.chat.interval), + props.chat.on_command, + props.chat.text, + props.chat.text_file + ); + }; + + const startMessage = () => { + StartChatBotMessage(props.chat.id) + .then(() => { + changeActive(true); + }) + .catch((error) => { + setError(error); + }); + }; + + const stopMessage = () => { + StopChatBotMessage(props.chat.id).then(() => { + changeActive(false); + }); + }; + + return ( + <> + setError('')} + show={error !== ''} + style={{ minWidth: '300px', maxWidth: '200px', maxHeight: '200px' }} + title={'Error'} + message={error} + submitButton={'OK'} + onSubmit={() => setError('')} + /> +
openChat()}> + + {props.chat.text_file !== '' ? filename : props.chat.text} + + + {props.chat.on_command + ? props.chat.command + : printInterval(props.chat.interval)} + + + {props.chat.as_channel ? 'Channel' : 'User'} + + +
+ + ); +} diff --git a/frontend/src/components/StreamChatMessage.css b/frontend/src/components/StreamChatMessage.css index 143efaf..02038e9 100644 --- a/frontend/src/components/StreamChatMessage.css +++ b/frontend/src/components/StreamChatMessage.css @@ -20,7 +20,7 @@ width: 100vw; } */ -.chat-as-channel { +.chat-toggle { align-items: center; display: flex; justify-content: space-between; @@ -28,12 +28,49 @@ width: 100%; } -.chat-as-channel-label { +.chat-toggle-label { color: white; font-family: sans-serif; padding-right: 10px; } +.chat-command { + align-items: center; + display: flex; + flex-direction: row; + justify-content: center; + padding-top: 10px; + width: 100%; +} + +.chat-command-input { + border: none; + border-radius: 34px; + box-sizing: border-box; + font-family: monospace; + font-size: 16px; + outline: none; + padding: 5px 10px 5px 10px; + text-align: right; + width: 100%; +} + +.chat-command-label { + color: white; + height: 29px; +} + +.chat-command-input { + border: none; + border-radius: 34px; + box-sizing: border-box; + font-family: monospace; + font-size: 16px; + outline: none; + padding: 5px 10px 5px 10px; + text-align: center; +} + .chat-interval { align-items: center; display: flex; @@ -127,24 +164,31 @@ align-items: center; display: flex; flex-direction: row; - justify-content: start; + justify-content: space-between; width: 100%; } -.chat-as-channel-switch { +.stream-chat-message-title-right { + align-items: center; + display: flex; + flex-direction: row; + justify-content: center; +} + +.chat-toggle-switch { position: relative; display: inline-block; width: 50px; height: 24px; } -.chat-as-channel-switch input { +.chat-toggle-switch input { opacity: 0; width: 0; height: 0; } -.chat-as-channel-slider { +.chat-toggle-slider { position: absolute; cursor: pointer; top: 0; @@ -156,7 +200,7 @@ transition: .4s; } -.chat-as-channel-slider:before { +.chat-toggle-slider:before { position: absolute; content: ""; height: 16px; @@ -168,20 +212,117 @@ transition: .4s; } -input:checked + .chat-as-channel-slider { +input:checked + .chat-toggle-slider { background-color: #85c742; } -input:checked + .chat-as-channel-slider:before { +input:checked + .chat-toggle-slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); } /* Rounded sliders */ -.chat-as-channel-slider.round { +.chat-toggle-slider.round { border-radius: 34px; } -.chat-as-channel-slider.round:before { +.chat-toggle-slider.round:before { border-radius: 50%; -} \ No newline at end of file +} + +.chat-toggle-check-container { + display: block; + position: relative; + padding-left: 16px; + margin-bottom: 15px; + cursor: pointer; + font-size: 15px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.chat-toggle-check-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +} + +.chat-toggle-check { + border-radius: 3px; + position: absolute; + top: 0; + left: 0; + height: 15px; + width: 15px; + background-color: #495a6a; +} + +.chat-toggle-check-container:hover input ~ .chat-toggle-check { + background-color: #495a6a; +} + +.chat-toggle-check-container input:checked ~ .chat-toggle-check { + background-color: #85c742; +} + +.chat-toggle-check:after { + content: ""; + position: absolute; + display: none; +} + +.chat-toggle-check-container input:checked ~ .chat-toggle-check:after { + display: block; +} + +.chat-toggle-check-container .chat-toggle-check:after { + left: 4px; + top: 1px; + width: 4px; + height: 8px; + border: solid white; + border-width: 0 3px 3px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.chat-toggle-check-label { + padding-right: 5px; +} + +.choose-file { + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; + width: 100%; +} + +.choose-file-button-box { + min-width: 100px; + width: 100px; +} + +.choose-file-button { + background-color: #85c742; + border: none; + border-radius: 5px; + color: #061726; + cursor: pointer; + font-size: 16px; + text-decoration: none; + /* width: 200px; */ + width: 100%; +} + +.choose-file-path { + overflow: scroll; + margin-left: 5px; + white-space: nowrap; +} + diff --git a/frontend/src/components/StreamChatMessage.jsx b/frontend/src/components/StreamChatMessage.jsx index 6a29869..770d9af 100644 --- a/frontend/src/components/StreamChatMessage.jsx +++ b/frontend/src/components/StreamChatMessage.jsx @@ -2,28 +2,41 @@ import { useEffect, useState } from 'react'; import { Modal, SmallModal } from './Modal'; +import { OpenFileDialog } from '../../wailsjs/go/main/App'; + import './StreamChatMessage.css'; export function StreamChatMessageModal(props) { const [asChannel, setAsChannel] = useState(props.asChannel); - const [openDelete, setOpenDelete] = useState(false); + const [chatCommand, setChatCommand] = useState(props.chatCommand); const [error, setError] = useState(''); - const [message, setMessage] = useState(props.message); - const updateMessage = (event) => setMessage(event.target.value); + const [onCommand, setOnCommand] = useState(props.onCommand); + const [openDelete, setOpenDelete] = useState(false); + const [readFromFile, setReadFromFile] = useState(false); + const [text, setText] = useState(props.text); + const [textFile, setTextFile] = useState(props.textFile); + const updateText = (event) => setText(event.target.value); const [timer, setTimer] = useState(props.interval); useEffect(() => { console.log('update chat'); setAsChannel(props.asChannel); + setOnCommand(props.onCommand); setError(''); - setMessage(props.message); + setReadFromFile(props.textFile !== ''); + setText(props.text); + setTextFile(props.textFile); setTimer(props.interval); }, []); const reset = () => { setAsChannel(false); + setChatCommand(false); setError(''); - setMessage(''); + setReadFromFile(false); + setText(''); + setTextFile(''); + setOnCommand(false); setTimer(''); }; @@ -33,21 +46,34 @@ export function StreamChatMessageModal(props) { }; const submit = () => { - if (message === '') { + if (!readFromFile && text === '') { setError('Add message'); return; } + if (readFromFile && textFile === '') { + setError('Select file containing messages'); + return; + } + if (timer === '') { setError('Set timer'); return; } + if (onCommand && chatCommand === '') { + setError('Add command'); + return; + } + let ac = asChannel; - let msg = message; + let oc = onCommand; + let cmd = chatCommand; let int = timerToInterval(); + let txt = text; + let txtfile = textFile; reset(); - props.onSubmit(props.chatID, ac, int, msg); + props.onSubmit(props.chatID, ac, cmd, int, oc, txt, txtfile); }; const deleteMessage = () => { @@ -65,6 +91,24 @@ export function StreamChatMessageModal(props) { props.onDelete(props.chatID); }; + const updateChatCommand = (e) => { + let command = e.target.value; + + if (command.length === 1) { + if (command !== '!') { + command = '!' + command; + } + } + command = command.toLowerCase(); + let postfix = command.replace('!', ''); + + if (postfix !== '' && !/^[a-z0-9]+$/gi.test(postfix)) { + return; + } + + setChatCommand(command); + }; + const updateTimerBackspace = (e) => { if (timer.length === 0) { return; @@ -116,10 +160,31 @@ export function StreamChatMessageModal(props) { return t.substring(0, 2) + ':' + t.substring(2, 4) + ':' + t.substring(4, 6); }; - const checkToggle = (e) => { + const checkChannelToggle = (e) => { setAsChannel(e.target.checked); }; + const checkCommandToggle = (e) => { + setOnCommand(e.target.checked); + }; + + const checkReadFromFile = (e) => { + setReadFromFile(e.target.checked); + if (!e.target.checked) { + setTextFile(''); + } + }; + + const chooseFile = () => { + OpenFileDialog() + .then((filepath) => { + if (filepath !== '') { + setTextFile(filepath); + } + }) + .catch((error) => setError(error)); + }; + return ( <>
- {error && {error}} + {/* {error && {error}} */}
Message +
+ Read from file + +
-