refactor: new ui step3
This commit is contained in:
parent
24430d0fae
commit
c15cdea57d
6 changed files with 172 additions and 153 deletions
|
|
@ -4,14 +4,13 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.patanix.de/git/kettlebell-app/internal/data"
|
||||
"git.patanix.de/git/kettlebell-app/internal/ui/utils"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"git.patanix.de/git/kettlebell-app/internal/data"
|
||||
"git.patanix.de/git/kettlebell-app/internal/ui/utils"
|
||||
)
|
||||
|
||||
func MakeHistoryScreen(db *data.DatabaseService, parent fyne.Window) fyne.CanvasObject {
|
||||
|
|
@ -19,19 +18,14 @@ func MakeHistoryScreen(db *data.DatabaseService, parent fyne.Window) fyne.Canvas
|
|||
|
||||
placeholder := widget.NewLabel("Noch keine Trainingsdaten vorhanden.")
|
||||
list := widget.NewList(
|
||||
func() int {
|
||||
return len(history)
|
||||
},
|
||||
func() int { return len(history) },
|
||||
func() fyne.CanvasObject {
|
||||
return widget.NewCard("", "", container.NewVBox(
|
||||
widget.NewLabel(""),
|
||||
widget.NewSeparator(),
|
||||
container.NewGridWithColumns(3,
|
||||
container.NewVBox(widget.NewLabel("Sätze"), widget.NewLabelWithStyle("", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Dauer"), widget.NewLabelWithStyle("", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Reps/Satz"), widget.NewLabelWithStyle("", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
),
|
||||
))
|
||||
stats := container.NewGridWithColumns(3,
|
||||
container.NewVBox(widget.NewLabel("Sätze"), widget.NewLabelWithStyle("", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Dauer"), widget.NewLabelWithStyle("", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Reps/Satz"), widget.NewLabelWithStyle("", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
)
|
||||
return widget.NewCard("", "", container.NewVBox(widget.NewLabel(""), widget.NewSeparator(), stats))
|
||||
},
|
||||
func(i widget.ListItemID, o fyne.CanvasObject) {
|
||||
session := history[i]
|
||||
|
|
@ -43,7 +37,6 @@ func MakeHistoryScreen(db *data.DatabaseService, parent fyne.Window) fyne.Canvas
|
|||
statsGrid := content.Objects[2].(*fyne.Container)
|
||||
|
||||
programLabel.SetText(fmt.Sprintf("%s - Tag %d", session.Program, session.BlockDay))
|
||||
|
||||
statsGrid.Objects[0].(*fyne.Container).Objects[1].(*widget.Label).SetText(fmt.Sprintf("%d", session.Sets))
|
||||
statsGrid.Objects[1].(*fyne.Container).Objects[1].(*widget.Label).SetText(utils.FormatDuration(session.Duration))
|
||||
statsGrid.Objects[2].(*fyne.Container).Objects[1].(*widget.Label).SetText(fmt.Sprintf("%d", session.RepsPerSet))
|
||||
|
|
@ -56,32 +49,25 @@ func MakeHistoryScreen(db *data.DatabaseService, parent fyne.Window) fyne.Canvas
|
|||
if err != nil {
|
||||
log.Printf("Fehler beim Laden der Historie: %v", err)
|
||||
dialog.ShowError(err, parent)
|
||||
return
|
||||
}
|
||||
if len(history) == 0 {
|
||||
list.Hide()
|
||||
placeholder.Show()
|
||||
list.Hide()
|
||||
} else {
|
||||
list.Show()
|
||||
placeholder.Hide()
|
||||
list.Show()
|
||||
}
|
||||
list.Refresh()
|
||||
}
|
||||
|
||||
list.OnSelected = func(id widget.ListItemID) {
|
||||
list.Unselect(id)
|
||||
}
|
||||
toolbar := widget.NewToolbar(widget.NewToolbarAction(theme.ViewRefreshIcon(), refreshData))
|
||||
content := container.NewStack(list, container.NewCenter(placeholder))
|
||||
layout := container.NewBorder(toolbar, nil, nil, nil, content)
|
||||
|
||||
toolbar := widget.NewToolbar(
|
||||
widget.NewToolbarAction(theme.ViewRefreshIcon(), refreshData),
|
||||
)
|
||||
|
||||
layout := container.NewBorder(toolbar, nil, nil, nil, container.NewStack(list, container.NewCenter(placeholder)))
|
||||
|
||||
wrapper := container.NewMax(layout)
|
||||
if wrapper.Visible() {
|
||||
// Daten laden, wenn der Container sichtbar wird
|
||||
if layout.Visible() {
|
||||
refreshData()
|
||||
}
|
||||
// wrapper.OnVisible = refreshData
|
||||
|
||||
return wrapper
|
||||
return layout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ package ui
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"git.patanix.de/git/kettlebell-app/internal/data"
|
||||
"git.patanix.de/git/kettlebell-app/internal/services"
|
||||
"git.patanix.de/git/kettlebell-app/internal/ui/theme"
|
||||
"git.patanix.de/git/kettlebell-app/internal/ui/utils"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
|
|
@ -12,7 +15,7 @@ import (
|
|||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func MakeHomeScreen(ts *services.TrainingService, onStart func()) fyne.CanvasObject {
|
||||
func MakeHomeScreen(ts *services.TrainingService, db *data.DatabaseService, onStart func()) fyne.CanvasObject {
|
||||
// Header
|
||||
headerTitle := canvas.NewText("Patanix", theme.ColorSlate200)
|
||||
headerTitle.TextSize = 28
|
||||
|
|
@ -25,8 +28,6 @@ func MakeHomeScreen(ts *services.TrainingService, onStart func()) fyne.CanvasObj
|
|||
|
||||
// Nächstes Training CTA
|
||||
state := ts.State
|
||||
|
||||
// Verwende ein Card-Widget für das Styling
|
||||
nextTrainingCard := widget.NewCard(
|
||||
"Nächstes Training",
|
||||
fmt.Sprintf("%s - Tag %d", state.CurrentProgram, state.CurrentBlockDay),
|
||||
|
|
@ -37,12 +38,30 @@ func MakeHomeScreen(ts *services.TrainingService, onStart func()) fyne.CanvasObj
|
|||
)
|
||||
|
||||
// Letzte Leistung
|
||||
setsValue := widget.NewLabelWithStyle("–", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})
|
||||
durationValue := widget.NewLabelWithStyle("–", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})
|
||||
weightValue := widget.NewLabelWithStyle("–", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})
|
||||
|
||||
statsCard := widget.NewCard("Letzte Leistung", "", container.NewGridWithColumns(3,
|
||||
container.NewVBox(widget.NewLabel("Sätze"), widget.NewLabelWithStyle("8", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Dauer"), widget.NewLabelWithStyle("18:45", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Gewicht"), widget.NewLabelWithStyle("16kg", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})),
|
||||
container.NewVBox(widget.NewLabel("Sätze"), setsValue),
|
||||
container.NewVBox(widget.NewLabel("Dauer"), durationValue),
|
||||
container.NewVBox(widget.NewLabel("Gewicht"), weightValue),
|
||||
))
|
||||
|
||||
// Funktion zum Laden der letzten Leistung
|
||||
loadLastPerformance := func() {
|
||||
lastSession, err := db.GetLastTraining()
|
||||
if err != nil {
|
||||
log.Printf("Fehler beim Laden der letzten Session: %v", err)
|
||||
return
|
||||
}
|
||||
if lastSession != nil {
|
||||
setsValue.SetText(fmt.Sprintf("%d", lastSession.Sets))
|
||||
durationValue.SetText(utils.FormatDuration(lastSession.Duration))
|
||||
weightValue.SetText(fmt.Sprintf("%.1fkg", lastSession.WeightLeft)) // Annahme: linkes Gewicht ist repräsentativ
|
||||
}
|
||||
}
|
||||
|
||||
layout := container.NewVBox(
|
||||
header,
|
||||
widget.NewSeparator(),
|
||||
|
|
@ -50,5 +69,12 @@ func MakeHomeScreen(ts *services.TrainingService, onStart func()) fyne.CanvasObj
|
|||
statsCard,
|
||||
)
|
||||
|
||||
return container.NewPadded(layout)
|
||||
paddedLayout := container.NewPadded(layout)
|
||||
// Daten laden, wenn der Bildschirm sichtbar wird
|
||||
if paddedLayout.Visible() {
|
||||
loadLastPerformance()
|
||||
}
|
||||
// paddedLayout.OnVisible = loadLastPerformance
|
||||
|
||||
return paddedLayout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,17 @@ import (
|
|||
)
|
||||
|
||||
func MakeSettingsScreen(settingsService *services.SettingsService, parent fyne.Window) fyne.CanvasObject {
|
||||
currentSettings := settingsService.LoadSettings()
|
||||
var timeEntry, setsEntry, weightLeftEntry, weightRightEntry *widget.Entry
|
||||
|
||||
timeEntry := widget.NewEntry()
|
||||
timeEntry.SetText(fmt.Sprintf("%d", currentSettings.TrainingTimeMinutes))
|
||||
loadData := func() {
|
||||
currentSettings := settingsService.LoadSettings()
|
||||
timeEntry.SetText(fmt.Sprintf("%d", currentSettings.TrainingTimeMinutes))
|
||||
setsEntry.SetText(fmt.Sprintf("%d", currentSettings.GoalSets))
|
||||
weightLeftEntry.SetText(fmt.Sprintf("%.1f", currentSettings.WeightLeft))
|
||||
weightRightEntry.SetText(fmt.Sprintf("%.1f", currentSettings.WeightRight))
|
||||
}
|
||||
|
||||
timeEntry = widget.NewEntry()
|
||||
timeEntry.Validator = func(s string) error {
|
||||
if _, err := strconv.Atoi(s); err != nil {
|
||||
return fmt.Errorf("muss eine Zahl sein")
|
||||
|
|
@ -23,22 +30,18 @@ func MakeSettingsScreen(settingsService *services.SettingsService, parent fyne.W
|
|||
return nil
|
||||
}
|
||||
|
||||
setsEntry := widget.NewEntry()
|
||||
setsEntry.SetText(fmt.Sprintf("%d", currentSettings.GoalSets))
|
||||
setsEntry.Validator = timeEntry.Validator // Gleicher Validator
|
||||
setsEntry = widget.NewEntry()
|
||||
setsEntry.Validator = timeEntry.Validator
|
||||
|
||||
weightLeftEntry := widget.NewEntry()
|
||||
weightLeftEntry.SetText(fmt.Sprintf("%.1f", currentSettings.WeightLeft))
|
||||
weightLeftEntry = widget.NewEntry()
|
||||
weightLeftEntry.Validator = func(s string) error {
|
||||
if _, err := strconv.ParseFloat(s, 64); err != nil {
|
||||
return fmt.Errorf("muss eine Zahl sein")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
weightRightEntry := widget.NewEntry()
|
||||
weightRightEntry.SetText(fmt.Sprintf("%.1f", currentSettings.WeightRight))
|
||||
weightRightEntry.Validator = weightLeftEntry.Validator // Gleicher Validator
|
||||
weightRightEntry = widget.NewEntry()
|
||||
weightRightEntry.Validator = weightLeftEntry.Validator
|
||||
|
||||
form := &widget.Form{
|
||||
Items: []*widget.FormItem{
|
||||
|
|
@ -58,10 +61,9 @@ func MakeSettingsScreen(settingsService *services.SettingsService, parent fyne.W
|
|||
GoalSets: goal,
|
||||
WeightLeft: weightL,
|
||||
WeightRight: weightR,
|
||||
InitialProgram: currentSettings.InitialProgram, // Beibehalten
|
||||
InitialProgram: settingsService.LoadSettings().InitialProgram,
|
||||
}
|
||||
settingsService.SaveSettings(newSettings)
|
||||
|
||||
fyne.CurrentApp().SendNotification(&fyne.Notification{
|
||||
Title: "Gespeichert",
|
||||
Content: "Die Einstellungen wurden erfolgreich aktualisiert.",
|
||||
|
|
@ -70,13 +72,11 @@ func MakeSettingsScreen(settingsService *services.SettingsService, parent fyne.W
|
|||
}
|
||||
|
||||
title := widget.NewLabelWithStyle("Einstellungen", fyne.TextAlignLeading, fyne.TextStyle{Bold: true})
|
||||
title.TextStyle.Monospace = true // Workaround to force refresh on size change
|
||||
layout := container.NewVBox(title, widget.NewSeparator(), form)
|
||||
paddedLayout := container.NewPadded(layout)
|
||||
if paddedLayout.Visible() {
|
||||
loadData()
|
||||
} // Daten laden, wenn sichtbar
|
||||
|
||||
layout := container.NewVBox(
|
||||
title,
|
||||
widget.NewSeparator(),
|
||||
form,
|
||||
)
|
||||
|
||||
return container.NewPadded(layout)
|
||||
return paddedLayout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,24 +15,23 @@ import (
|
|||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsService, parent fyne.Window) fyne.CanvasObject {
|
||||
// UI-Elemente mit canvas.Text für die Größensteuerung
|
||||
timerLabel := canvas.NewText("20:00", theme.ColorSlate200)
|
||||
// MakeTrainingScreen gibt jetzt das CanvasObject und die Start-Funktion zurück
|
||||
func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsService, parent fyne.Window) (fyne.CanvasObject, func()) {
|
||||
timerLabel := canvas.NewText("00:00", theme.ColorSlate200)
|
||||
timerLabel.TextSize = 60
|
||||
timerLabel.TextStyle.Bold = true
|
||||
timerLabel.Alignment = fyne.TextAlignCenter
|
||||
|
||||
setsLabel := canvas.NewText("0 / 8", theme.ColorSky400)
|
||||
setsLabel := canvas.NewText("0 / 0", theme.ColorSky400)
|
||||
setsLabel.TextSize = 48
|
||||
setsLabel.TextStyle.Bold = true
|
||||
setsLabel.Alignment = fyne.TextAlignCenter
|
||||
|
||||
repsLabel := canvas.NewText("5 Wiederholungen", theme.ColorSlate200)
|
||||
repsLabel := canvas.NewText("0 Wiederholungen", theme.ColorSlate200)
|
||||
repsLabel.TextSize = 20
|
||||
repsLabel.Alignment = fyne.TextAlignCenter
|
||||
|
||||
var mainTimer *time.Ticker
|
||||
var startButton *widget.Button // Start-Button deklarieren
|
||||
|
||||
updateUI := func() {
|
||||
state := ts.State
|
||||
|
|
@ -43,12 +42,6 @@ func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsServi
|
|||
timerLabel.Refresh()
|
||||
setsLabel.Refresh()
|
||||
repsLabel.Refresh()
|
||||
|
||||
if state.IsTrainingRunning {
|
||||
startButton.Disable()
|
||||
} else {
|
||||
startButton.Enable()
|
||||
}
|
||||
}
|
||||
|
||||
finishAction := func() {
|
||||
|
|
@ -56,6 +49,9 @@ func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsServi
|
|||
mainTimer.Stop()
|
||||
mainTimer = nil
|
||||
}
|
||||
if !ts.State.IsTrainingRunning {
|
||||
return // Nichts tun, wenn kein Training läuft
|
||||
}
|
||||
session := &data.TrainingSession{
|
||||
Date: time.Now(),
|
||||
Sets: int64(ts.State.SetsDone),
|
||||
|
|
@ -70,6 +66,9 @@ func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsServi
|
|||
}
|
||||
|
||||
startAction := func() {
|
||||
if ts.State.IsTrainingRunning {
|
||||
return // Verhindere Neustart
|
||||
}
|
||||
settings := ss.LoadSettings()
|
||||
ts.StartTraining(settings.TrainingTimeMinutes, settings.GoalSets)
|
||||
updateUI()
|
||||
|
|
@ -77,48 +76,43 @@ func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsServi
|
|||
mainTimer = time.NewTicker(time.Second)
|
||||
go func() {
|
||||
for mainTimer != nil {
|
||||
<-mainTimer.C
|
||||
if ts.State.RemainingSeconds <= 0 {
|
||||
finishAction()
|
||||
return
|
||||
select {
|
||||
case <-mainTimer.C:
|
||||
if ts.State.RemainingSeconds <= 0 {
|
||||
finishAction()
|
||||
return
|
||||
}
|
||||
ts.Tick()
|
||||
updateUI()
|
||||
}
|
||||
ts.Tick()
|
||||
updateUI()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
setAction := func() {
|
||||
if !ts.State.IsTrainingRunning {
|
||||
// Starte das Training, wenn es noch nicht läuft
|
||||
startAction()
|
||||
return // Kein Satz ohne laufendes Training
|
||||
}
|
||||
ts.CompleteSet()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
startButton = widget.NewButton("Training beginnen", startAction)
|
||||
|
||||
// Layout im "Cockpit"-Stil
|
||||
topPart := container.NewVBox(
|
||||
widget.NewLabelWithStyle("Verbleibende Zeit", fyne.TextAlignCenter, fyne.TextStyle{}),
|
||||
timerLabel,
|
||||
)
|
||||
|
||||
middlePart := container.NewVBox(
|
||||
widget.NewLabelWithStyle("Sätze", fyne.TextAlignCenter, fyne.TextStyle{}),
|
||||
setsLabel,
|
||||
repsLabel,
|
||||
)
|
||||
|
||||
topPart := container.NewVBox(widget.NewLabelWithStyle("Verbleibende Zeit", fyne.TextAlignCenter, fyne.TextStyle{}), timerLabel)
|
||||
middlePart := container.NewVBox(widget.NewLabelWithStyle("Sätze", fyne.TextAlignCenter, fyne.TextStyle{}), setsLabel, repsLabel)
|
||||
finishButton := widget.NewButton("Training beenden", finishAction)
|
||||
finishButton.Importance = widget.HighImportance
|
||||
|
||||
bottomPart := container.NewVBox(
|
||||
startButton, // Start-Button hinzugefügt
|
||||
widget.NewButton("Satz abschließen", setAction),
|
||||
finishButton,
|
||||
)
|
||||
|
||||
return container.NewBorder(topPart, bottomPart, nil, nil, container.NewCenter(middlePart))
|
||||
layout := container.NewBorder(topPart, bottomPart, nil, nil, container.NewCenter(middlePart))
|
||||
// UI aktualisieren, wenn der Bildschirm sichtbar wird
|
||||
if layout.Visible() {
|
||||
updateUI()
|
||||
}
|
||||
// layout.OnVisible = updateUI
|
||||
|
||||
return layout, startAction
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue