From 789ee25e1f24019c0f2c93e917bb5c8a450c4f8b Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Fri, 27 Jun 2025 20:42:17 +0200 Subject: [PATCH] refactor: another ui test --- cmd/main.go | 62 ++++++++++++++++++-------- internal/ui/history.go | 33 ++++++++++++-- internal/ui/home.go | 76 ++++++++++++++++++++++++-------- internal/ui/training.go | 97 +++++++++++++++++++++-------------------- 4 files changed, 182 insertions(+), 86 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 7ca7e60..594f4e3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -16,8 +16,7 @@ import ( func main() { myApp := app.NewWithID("com.example.kettlebell-tracker") - // myApp.Settings().SetTheme(theme.DarkTheme()) - mainWIndow := myApp.NewWindow("Kettlebell Programm Tracker") + mainWindow := myApp.NewWindow("Kettlebell Programm Tracker") dbDir := myApp.Storage().RootURI().Path() dbPath := filepath.Join(dbDir, "kb_training.db") @@ -32,23 +31,50 @@ func main() { apiService := services.NewApiService(myApp.UniqueID()) trainingService := services.NewTrainingService(dbService, settingsService, apiService) + // Dark Mode nach Systemeinstellung + if fyne.CurrentDevice().IsMobile() { + myApp.Settings().SetTheme(theme.DarkTheme()) + } - homeScreen := ui.MakeHomeScreen() - settingsScreen := ui.MakeSettingsScreen(settingsService, mainWIndow) - historyScreen := ui.MakeHistoryScreen(dbService, mainWIndow) - trainingScreen := ui.MakeTrainingScreen(trainingService, settingsService, mainWIndow) + // mainWindow := myApp.NewWindow("Kettlebell Tracker") + mainWindow.SetMaster() - tabs := container.NewAppTabs( - container.NewTabItemWithIcon("Home", theme.HomeIcon(), homeScreen), - container.NewTabItemWithIcon("Training", theme.MediaPlayIcon(), trainingScreen), - container.NewTabItemWithIcon("Historie", theme.HistoryIcon(), historyScreen), - container.NewTabItemWithIcon("Einstellungen", theme.SettingsIcon(), settingsScreen), - ) + // Responsive Layout + content := container.NewMax() + nav := buildNavigation(content, mainWindow, dbService, settingsService, apiService, trainingService) // Eigene Nav-Komponente - tabs.SetTabLocation(container.TabLocationBottom) - - mainWIndow.Resize(fyne.NewSize(400, 600)) - mainWIndow.SetContent(tabs) - mainWIndow.SetMaster() - mainWIndow.ShowAndRun() + mainWindow.SetContent(container.NewBorder(nav, nil, nil, nil, content)) + mainWindow.Resize(fyne.NewSize(400, 600)) + mainWindow.ShowAndRun() +} + +func buildNavigation(content *fyne.Container, mainWindow fyne.Window, dbService *data.DatabaseService, settingsService *services.SettingsService, apiService *services.ApiService, trainingService *services.TrainingService) fyne.CanvasObject { + navItems := []struct { + icon fyne.Resource + title string + view func() fyne.CanvasObject + }{ + {theme.HomeIcon(), "Home", ui.MakeHomeScreen}, + {theme.MediaPlayIcon(), "Training", func() fyne.CanvasObject { + return ui.MakeTrainingScreen(trainingService, settingsService, mainWindow) + }}, + {theme.HistoryIcon(), "Historie", func() fyne.CanvasObject { + return ui.MakeHistoryScreen(dbService, mainWindow) + }}, + {theme.SettingsIcon(), "Einstellungen", func() fyne.CanvasObject { + return ui.MakeSettingsScreen(settingsService, mainWindow) + }}, + } + + nav := container.NewAppTabs() + for _, item := range navItems { + nav.Append(container.NewTabItemWithIcon(item.title, item.icon, item.view())) + } + nav.SetTabLocation(container.TabLocationBottom) + nav.OnSelected = func(t *container.TabItem) { + content.Objects = []fyne.CanvasObject{t.Content} + content.Refresh() + } + + return nav } diff --git a/internal/ui/history.go b/internal/ui/history.go index 6554d22..29825ef 100644 --- a/internal/ui/history.go +++ b/internal/ui/history.go @@ -84,9 +84,36 @@ func MakeHistoryScreen(db *data.DatabaseService, parent fyne.Window) fyne.Canvas refreshData() // Toolbar mit Refresh-Button - toolbar := widget.NewToolbar( - widget.NewToolbarAction(theme.ViewRefreshIcon(), refreshData), + // toolbar := widget.NewToolbar( + // widget.NewToolbarAction(theme.ViewRefreshIcon(), refreshData), + // ) + table := widget.NewTable( + func() (int, int) { return len(history), 4 }, + func() fyne.CanvasObject { return widget.NewLabel("Template") }, + func(id widget.TableCellID, cell fyne.CanvasObject) { + session := history[id.Row] + label := cell.(*widget.Label) + switch id.Col { + case 0: + label.SetText(session.Date.Format("02.01")) + case 1: + label.SetText(fmt.Sprintf("%d Sätze", session.Sets)) + case 2: + label.SetText(fmt.Sprintf("%.1fkg", session.WeightLeft)) + case 3: + label.SetText(formatDuration(session.Duration)) + } + }, ) + table.SetColumnWidth(0, 80) + table.SetColumnWidth(1, 100) + table.SetColumnWidth(2, 80) + table.SetColumnWidth(3, 80) - return container.NewBorder(toolbar, nil, nil, nil, container.NewStack(list, placeholder)) + // return container.NewBorder(toolbar, nil, nil, nil, container.NewStack(list, placeholder)) + return container.NewBorder( + widget.NewToolbar(widget.NewToolbarAction(theme.ViewRefreshIcon(), refreshData)), + nil, nil, nil, + table, + ) } diff --git a/internal/ui/home.go b/internal/ui/home.go index 7b7592d..f8d8566 100644 --- a/internal/ui/home.go +++ b/internal/ui/home.go @@ -8,29 +8,69 @@ import ( "fyne.io/fyne/v2/widget" ) -// MakeHomeScreen erstellt den statischen Willkommensbildschirm. +// // MakeHomeScreen erstellt den statischen Willkommensbildschirm. +// func MakeHomeScreen() fyne.CanvasObject { +// primaryColor := theme.PrimaryColor() +// +// title := canvas.NewText("Willkommen beim Giant Programm Tracker!", primaryColor) +// title.TextStyle.Bold = true +// title.Alignment = fyne.TextAlignCenter +// title.TextSize = 24 +// +// subtitle := widget.NewLabel("Verwalte deine Kettlebell-Trainings effizient.") +// subtitle.Alignment = fyne.TextAlignCenter +// +// icon := widget.NewIcon(theme.MediaPlayIcon()) +// icon.Resize(fyne.NewSize(150, 150)) +// +// // Layout erstellen, das dem Flutter-Layout entspricht +// content := container.NewVBox( +// title, +// widget.NewSeparator(), +// subtitle, +// container.NewPadded(icon), // Icon mit etwas Abstand +// ) +// +// // Zentriert den Inhalt +// return container.NewCenter(content) +// } + func MakeHomeScreen() fyne.CanvasObject { - primaryColor := theme.PrimaryColor() + primary := theme.PrimaryColor() + secondary := theme.WarningColor() - title := canvas.NewText("Willkommen beim Giant Programm Tracker!", primaryColor) - title.TextStyle.Bold = true - title.Alignment = fyne.TextAlignCenter - title.TextSize = 24 + // Header mit personalisierter Begrüßung + greeting := canvas.NewText("Dein Kettlebell Fortschritt", primary) + greeting.TextSize = 20 + greeting.Alignment = fyne.TextAlignCenter - subtitle := widget.NewLabel("Verwalte deine Kettlebell-Trainings effizient.") - subtitle.Alignment = fyne.TextAlignCenter + // Fortschrittsvisualisierung (Beispiel) + progressRing := canvas.NewCircle(secondary) + progressRing.StrokeWidth = 8 + progressRing.StrokeColor = primary + ringContainer := container.NewCenter(progressRing) - icon := widget.NewIcon(theme.MediaPlayIcon()) - icon.Resize(fyne.NewSize(150, 150)) + // Programmstatus + programInfo := widget.NewLabel("Aktuell: Giant - Woche 2/4") + programInfo.Alignment = fyne.TextAlignCenter - // Layout erstellen, das dem Flutter-Layout entspricht - content := container.NewVBox( - title, + // Primäre Aktion + startBtn := widget.NewButtonWithIcon("Training starten", theme.MediaPlayIcon(), func() {}) + startBtn.Importance = widget.HighImportance + + return container.NewVBox( + container.NewPadded(greeting), + ringContainer, + programInfo, + container.NewCenter(startBtn), widget.NewSeparator(), - subtitle, - container.NewPadded(icon), // Icon mit etwas Abstand + buildQuickStats(), // Eigene Komponente für Statistiken + ) +} + +func buildQuickStats() fyne.CanvasObject { + return container.NewGridWithColumns(2, + widget.NewCard("Letztes Training", "12 Sätze", nil), + widget.NewCard("Aktuelle Serie", "5 Tage", nil), ) - - // Zentriert den Inhalt - return container.NewCenter(content) } diff --git a/internal/ui/training.go b/internal/ui/training.go index be6ed34..e89d9e8 100644 --- a/internal/ui/training.go +++ b/internal/ui/training.go @@ -9,6 +9,7 @@ import ( "git.patanix.de/git/kettlebell-app/internal/services" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/theme" @@ -75,35 +76,35 @@ func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsServi } } - startAction := func() { - settings := ss.LoadSettings() - ts.StartTraining(settings.TrainingTimeMinutes, settings.GoalSets) - updateUI() - - mainTimer = time.NewTicker(time.Second) - go func() { - for range mainTimer.C { - if ts.State.RemainingSeconds <= 0 { - stopTimers() - fyne.CurrentApp().SendNotification(&fyne.Notification{ - Title: "Zeit abgelaufen!", - Content: "Training wird automatisch gespeichert.", - }) - finishButton.OnTapped() - return - } - ts.Tick() - updateUI() - } - }() - - lastSetTimer = time.NewTicker(time.Second) - go func() { - for range lastSetTimer.C { - ts.TickLastSetTimer() - } - }() - } + // startAction := func() { + // settings := ss.LoadSettings() + // ts.StartTraining(settings.TrainingTimeMinutes, settings.GoalSets) + // updateUI() + // + // mainTimer = time.NewTicker(time.Second) + // go func() { + // for range mainTimer.C { + // if ts.State.RemainingSeconds <= 0 { + // stopTimers() + // fyne.CurrentApp().SendNotification(&fyne.Notification{ + // Title: "Zeit abgelaufen!", + // Content: "Training wird automatisch gespeichert.", + // }) + // finishButton.OnTapped() + // return + // } + // ts.Tick() + // updateUI() + // } + // }() + // + // lastSetTimer = time.NewTicker(time.Second) + // go func() { + // for range lastSetTimer.C { + // ts.TickLastSetTimer() + // } + // }() + // } setAction := func() { ts.CompleteSet() @@ -135,27 +136,29 @@ func MakeTrainingScreen(ts *services.TrainingService, ss *services.SettingsServi updateUI() } - startButton = widget.NewButtonWithIcon("Start", theme.MediaPlayIcon(), startAction) - setButton = widget.NewButtonWithIcon("Satz", theme.ConfirmIcon(), setAction) - finishButton = widget.NewButtonWithIcon("Beenden", theme.MediaStopIcon(), finishAction) + timerDisplay := canvas.NewText("00:00", theme.PrimaryColor()) + timerDisplay.TextSize = 48 + timerDisplay.Alignment = fyne.TextAlignCenter - updateUI() + exerciseInfo := widget.NewLabel("Aktuelle Übung: Double Clean & Press") + exerciseInfo.Alignment = fyne.TextAlignCenter - headerCard := widget.NewCard("", "", container.NewVBox(programLabel, blockDayLabel, repsLabel)) - timerCard := widget.NewCard("", "", container.NewVBox( - widget.NewLabelWithStyle("Verbleibende Zeit", fyne.TextAlignCenter, fyne.TextStyle{}), - timerLabel, - progressBar, - progressLabel, - )) + progressRing := canvas.NewCircle(theme.BackgroundColor()) + progressRing.StrokeWidth = 5 + progressRing.StrokeColor = theme.PrimaryColor() - actionButtons := container.NewGridWithColumns(3, startButton, setButton, finishButton) - historyCard := widget.NewCard("Satz-Historie", "", setHistoryList) + // Vereinfachte Steuerung + setBtn := widget.NewButtonWithIcon("Satz", theme.ConfirmIcon(), setAction) + finishBtn := widget.NewButtonWithIcon("Beenden", theme.CancelIcon(), finishAction) + actionBar := container.NewGridWithColumns(2, setBtn, finishBtn) - return container.NewVBox( - headerCard, - timerCard, - actionButtons, - historyCard, + // Tastatur-Shortcut + canvasObj := container.NewVBox( + container.NewCenter(timerDisplay), + container.NewCenter(exerciseInfo), + container.NewCenter(progressRing), + actionBar, ) + + return container.NewPadded(canvasObj) }