fix: layout, hotkeys, skip/switch speaker logic
This commit is contained in:
@@ -106,14 +106,14 @@ func (t *Timer) Start() {
|
||||
t.meetingWarned = false
|
||||
|
||||
if len(t.queue) > 0 {
|
||||
t.startNextSpeaker(now)
|
||||
t.startNextSpeaker(now, 0)
|
||||
}
|
||||
t.mu.Unlock()
|
||||
|
||||
go t.tick()
|
||||
}
|
||||
|
||||
func (t *Timer) startNextSpeaker(now time.Time) {
|
||||
func (t *Timer) startNextSpeaker(now time.Time, offset time.Duration) {
|
||||
if len(t.queue) == 0 {
|
||||
return
|
||||
}
|
||||
@@ -137,8 +137,8 @@ func (t *Timer) startNextSpeaker(now time.Time) {
|
||||
t.currentSpeakerID = speaker.ID
|
||||
t.currentSpeaker = speaker.Name
|
||||
t.speakerLimit = time.Duration(speaker.TimeLimit) * time.Second
|
||||
t.speakerStartTime = now
|
||||
t.speakerElapsed = 0
|
||||
t.speakerStartTime = now.Add(-offset)
|
||||
t.speakerElapsed = offset
|
||||
t.speakingOrder++
|
||||
t.speakerWarned = false
|
||||
t.speakerTimeUpEmitted = false
|
||||
@@ -193,7 +193,7 @@ func (t *Timer) NextSpeaker() {
|
||||
|
||||
var eventType EventType
|
||||
if len(t.queue) > 0 {
|
||||
t.startNextSpeaker(now)
|
||||
t.startNextSpeaker(now, 0)
|
||||
eventType = EventSpeakerChanged
|
||||
} else {
|
||||
t.running = false
|
||||
@@ -227,11 +227,14 @@ func (t *Timer) SkipSpeaker() {
|
||||
|
||||
now := time.Now()
|
||||
if len(t.queue) > 1 {
|
||||
t.startNextSpeaker(now)
|
||||
t.startNextSpeaker(now, 0)
|
||||
t.mu.Unlock()
|
||||
t.emit(EventSpeakerChanged)
|
||||
} else {
|
||||
// Only skipped speaker left - they need to speak now
|
||||
t.startNextSpeaker(now, 0)
|
||||
t.mu.Unlock()
|
||||
t.emit(EventSpeakerChanged)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +251,16 @@ func (t *Timer) RemoveFromQueue(speakerID uint) {
|
||||
return
|
||||
}
|
||||
|
||||
// Remove from queue
|
||||
// Find speaker info before removing
|
||||
var speakerInfo models.QueuedSpeaker
|
||||
for _, s := range t.queue {
|
||||
if s.ID == speakerID {
|
||||
speakerInfo = s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from current position in queue
|
||||
for i, s := range t.queue {
|
||||
if s.ID == speakerID {
|
||||
t.queue = append(t.queue[:i], t.queue[i+1:]...)
|
||||
@@ -256,11 +268,124 @@ func (t *Timer) RemoveFromQueue(speakerID uint) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add to end of queue so they can speak later
|
||||
if speakerInfo.ID != 0 {
|
||||
t.queue = append(t.queue, speakerInfo)
|
||||
}
|
||||
|
||||
// Mark as skipped in allSpeakers and move to end
|
||||
t.updateSpeakerStatus(speakerID, models.SpeakerStatusSkipped)
|
||||
t.moveSpeakerToEnd(speakerID)
|
||||
}
|
||||
|
||||
// SwitchToSpeaker moves the specified speaker to front of queue and starts them
|
||||
// If speaker is already done, resumes their timer from accumulated time
|
||||
func (t *Timer) SwitchToSpeaker(speakerID uint) {
|
||||
t.mu.Lock()
|
||||
|
||||
if !t.running {
|
||||
t.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// First, find speaker in allSpeakers to get their info and status
|
||||
var speakerInfo *models.SpeakerInfo
|
||||
var speakerInfoIdx int
|
||||
for i := range t.allSpeakers {
|
||||
if t.allSpeakers[i].ID == speakerID {
|
||||
speakerInfo = &t.allSpeakers[i]
|
||||
speakerInfoIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if speakerInfo == nil {
|
||||
t.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Don't switch to currently speaking speaker
|
||||
if speakerInfo.Status == models.SpeakerStatusSpeaking {
|
||||
t.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate offset for resuming (0 for pending/skipped, timeSpent for done)
|
||||
var offset time.Duration
|
||||
if speakerInfo.Status == models.SpeakerStatusDone {
|
||||
offset = time.Duration(speakerInfo.TimeSpent) * time.Second
|
||||
}
|
||||
|
||||
// Save current speaker time
|
||||
now := time.Now()
|
||||
if t.currentSpeakerID != 0 {
|
||||
timeSpent := int(now.Sub(t.speakerStartTime).Seconds())
|
||||
for i := range t.allSpeakers {
|
||||
if t.allSpeakers[i].ID == t.currentSpeakerID {
|
||||
if t.allSpeakers[i].Status == models.SpeakerStatusSpeaking {
|
||||
t.allSpeakers[i].Status = models.SpeakerStatusDone
|
||||
t.allSpeakers[i].TimeSpent = timeSpent
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find speaker in queue (pending/skipped) or create new entry (done)
|
||||
foundIdx := -1
|
||||
for i, s := range t.queue {
|
||||
if s.ID == speakerID {
|
||||
foundIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Create QueuedSpeaker from SpeakerInfo
|
||||
queuedSpeaker := models.QueuedSpeaker{
|
||||
ID: speakerInfo.ID,
|
||||
Name: speakerInfo.Name,
|
||||
TimeLimit: speakerInfo.TimeLimit,
|
||||
Order: speakerInfo.Order,
|
||||
}
|
||||
|
||||
if foundIdx >= 0 {
|
||||
// Remove from current position in queue
|
||||
t.queue = append(t.queue[:foundIdx], t.queue[foundIdx+1:]...)
|
||||
}
|
||||
// Insert at front of queue
|
||||
t.queue = append([]models.QueuedSpeaker{queuedSpeaker}, t.queue...)
|
||||
|
||||
// Move the selected speaker in allSpeakers to position after last done/speaking
|
||||
insertPos := 0
|
||||
for i, s := range t.allSpeakers {
|
||||
if s.Status == models.SpeakerStatusDone || s.Status == models.SpeakerStatusSpeaking {
|
||||
insertPos = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
if speakerInfoIdx >= 0 && speakerInfoIdx != insertPos {
|
||||
// Save speaker info before removing
|
||||
savedInfo := *speakerInfo
|
||||
// Remove from current position
|
||||
t.allSpeakers = append(t.allSpeakers[:speakerInfoIdx], t.allSpeakers[speakerInfoIdx+1:]...)
|
||||
// Adjust insert position if needed
|
||||
if speakerInfoIdx < insertPos {
|
||||
insertPos--
|
||||
}
|
||||
// Insert at new position
|
||||
t.allSpeakers = append(t.allSpeakers[:insertPos], append([]models.SpeakerInfo{savedInfo}, t.allSpeakers[insertPos:]...)...)
|
||||
// Update order numbers
|
||||
for i := range t.allSpeakers {
|
||||
t.allSpeakers[i].Order = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Start this speaker with offset (0 for new speakers, accumulated time for done)
|
||||
t.startNextSpeaker(now, offset)
|
||||
t.mu.Unlock()
|
||||
t.emit(EventSpeakerChanged)
|
||||
}
|
||||
|
||||
func (t *Timer) Pause() {
|
||||
t.mu.Lock()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user