Skip to content
Merged

Dev #95

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
10 changes: 4 additions & 6 deletions app/grout.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,19 @@ func main() {
quitOnBack := len(config.Hosts) == 1
showCollections := config.ShowCollections(config.Hosts[0])

fsm := buildFSM(config, currentCFW, platforms, quitOnBack, showCollections)

if err := fsm.Run(); err != nil {
logger.Error("FSM error", "error", err)
if err := runWithRouter(config, currentCFW, platforms, quitOnBack, showCollections); err != nil {
logger.Error("Router error", "error", err)
}
}

func cleanup() {
if autoSync != nil && autoSync.IsRunning() {
if currentAppState != nil && currentAppState.AutoSync != nil && currentAppState.AutoSync.IsRunning() {
gaba.GetLogger().Info("Waiting for auto-sync to complete before exiting...")
gaba.ProcessMessage(
i18n.Localize(&goi18n.Message{ID: "auto_sync_waiting", Other: "Waiting for save sync to complete..."}, nil),
gaba.ProcessMessageOptions{},
func() (interface{}, error) {
autoSync.Wait()
currentAppState.AutoSync.Wait()
return nil, nil
},
)
Expand Down
169 changes: 169 additions & 0 deletions app/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package main

import (
"grout/cache"
"grout/cfw"
"grout/internal"
"grout/romm"
"grout/ui"

gaba "github.com/BrandonKowalski/gabagool/v2/pkg/gabagool"
"github.com/BrandonKowalski/gabagool/v2/pkg/gabagool/i18n"
"github.com/BrandonKowalski/gabagool/v2/pkg/gabagool/router"
goi18n "github.com/nicksnyder/go-i18n/v2/i18n"
uatomic "go.uber.org/atomic"
)

func filterGamesByPlatform(games []romm.Rom, platformID int) []romm.Rom {
filtered := make([]romm.Rom, 0)
for _, game := range games {
if game.PlatformID == platformID {
filtered = append(filtered, game)
}
}
return filtered
}

func savePlatformOrder(state *AppState, platforms []romm.Platform) {
var platformOrder []string
for _, p := range platforms {
platformOrder = append(platformOrder, p.Slug)
}
state.Config.PlatformOrder = platformOrder
state.Platforms = platforms
internal.SaveConfig(state.Config)
}

func triggerAutoSyncRouter(state *AppState) {
if state.AutoSync != nil {
state.AutoSync.Trigger()
}
}

func executeDownloadUI(state *AppState, r ui.GameDetailsOutput, stack *router.Stack) {
entry := stack.Peek()
var allGames []romm.Rom
var searchFilter string
if entry != nil {
if input, ok := entry.Input.(ui.GameListInput); ok {
allGames = input.Games
searchFilter = input.SearchFilter
}
}

downloadScreen := ui.NewDownloadScreen()
downloadScreen.Execute(*state.Config, state.Host, r.Platform, []romm.Rom{r.Game}, allGames, searchFilter, r.SelectedFileID)
}

func executeMultiDownloadUI(state *AppState, r ui.GameListOutput) {
downloadScreen := ui.NewDownloadScreen()
downloadScreen.Execute(*state.Config, state.Host, r.Platform, r.SelectedGames, r.AllGames, r.SearchFilter, 0)
}

func handlePlatformMappingUpdateUI(state *AppState, r ui.PlatformMappingOutput) {
state.Config.DirectoryMappings = r.Mappings
state.Config.PlatformOrder = internal.PrunePlatformOrder(state.Config.PlatformOrder, r.Mappings)
internal.SaveConfig(state.Config)

platforms, err := internal.GetMappedPlatforms(state.Host, r.Mappings, state.Config.ApiTimeout)
if err != nil {
gaba.GetLogger().Error("Failed to refresh platforms after mapping update", "error", err)
return
}

oldIDs := make(map[int]bool)
for _, p := range state.Platforms {
oldIDs[p.ID] = true
}

var newPlatforms []romm.Platform
for _, p := range platforms {
if !oldIDs[p.ID] {
newPlatforms = append(newPlatforms, p)
}
}

state.Platforms = platforms

if len(newPlatforms) > 0 && state.CacheSync != nil {
state.CacheSync.SyncPlatforms(newPlatforms)
}
}

func handleLogout(state *AppState) {
logger := gaba.GetLogger()

if err := cache.DeleteCacheFolder(); err != nil {
logger.Error("Failed to delete cache folder", "error", err)
}

state.Config.Hosts = nil
state.Config.DirectoryMappings = nil
state.Config.PlatformOrder = nil

if err := internal.SaveConfig(state.Config); err != nil {
logger.Error("Failed to save config after logout", "error", err)
return
}

logger.Info("User logged out successfully")

loginConfig, err := ui.LoginFlow(romm.Host{})
if err != nil {
logger.Error("Login flow failed after logout", "error", err)
return
}

state.Config.Hosts = loginConfig.Hosts
if err := internal.SaveConfig(state.Config); err != nil {
logger.Error("Failed to save config after re-login", "error", err)
return
}

state.Host = state.Config.Hosts[0]

if len(state.Config.DirectoryMappings) == 0 {
screen := ui.NewPlatformMappingScreen()
result, err := screen.Draw(ui.PlatformMappingInput{
Host: state.Config.Hosts[0],
ApiTimeout: state.Config.ApiTimeout,
CFW: state.CFW,
RomDirectory: cfw.GetRomDirectory(),
AutoSelect: false,
HideBackButton: true,
PlatformsBinding: state.Config.PlatformsBinding,
})

if err == nil && result.Action == ui.PlatformMappingActionSaved {
state.Config.DirectoryMappings = result.Mappings
internal.SaveConfig(state.Config)
}
}

if err := cache.InitCacheManager(state.Config.Hosts[0], state.Config); err != nil {
logger.Error("Failed to initialize cache manager after re-login", "error", err)
}

platforms, err := internal.GetMappedPlatforms(state.Config.Hosts[0], state.Config.DirectoryMappings, state.Config.ApiTimeout)
if err != nil {
logger.Error("Failed to load platforms after re-login", "error", err)
return
}
state.Platforms = platforms

if cm := cache.GetCacheManager(); cm != nil && cm.IsFirstRun() {
progress := uatomic.NewFloat64(0)
gaba.ProcessMessage(
i18n.Localize(&goi18n.Message{ID: "cache_building", Other: "Building cache..."}, nil),
gaba.ProcessMessageOptions{
ShowThemeBackground: true,
ShowProgressBar: true,
Progress: progress,
},
func() (interface{}, error) {
_, err := cm.PopulateFullCacheWithProgress(platforms, progress)
return nil, err
},
)
}
}
199 changes: 199 additions & 0 deletions app/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package main

import (
"grout/cache"
"grout/cfw"
"grout/internal"
"grout/romm"
"grout/sync"
"grout/ui"
"grout/update"

gaba "github.com/BrandonKowalski/gabagool/v2/pkg/gabagool"
"github.com/BrandonKowalski/gabagool/v2/pkg/gabagool/i18n"
"github.com/BrandonKowalski/gabagool/v2/pkg/gabagool/router"
goi18n "github.com/nicksnyder/go-i18n/v2/i18n"
uatomic "go.uber.org/atomic"
)

func runWithRouter(config *internal.Config, currentCFW cfw.CFW, platforms []romm.Platform, quitOnBack bool, showCollections bool) error {
state := &AppState{
Config: config,
Host: config.Hosts[0],
CFW: currentCFW,
Platforms: platforms,
}
currentAppState = state

r := buildRouter(state, quitOnBack, showCollections)

initialInput := ui.PlatformSelectionInput{
Platforms: platforms,
QuitOnBack: quitOnBack,
ShowCollections: showCollections,
ShowSaveSync: computeShowSaveSync(state),
}

return r.Run(ScreenPlatformSelection, initialInput)
}

func buildRouter(state *AppState, quitOnBack bool, showCollections bool) *router.Router {
r := router.New()

state.CacheSync = cache.NewBackgroundSync(state.Platforms)
ui.AddStatusBarIcon(state.CacheSync.Icon())

if cm := cache.GetCacheManager(); cm != nil && cm.IsFirstRun() {
progress := uatomic.NewFloat64(0)
gaba.ProcessMessage(
i18n.Localize(&goi18n.Message{ID: "cache_building", Other: "Building cache..."}, nil),
gaba.ProcessMessageOptions{
ShowThemeBackground: true,
ShowProgressBar: true,
Progress: progress,
},
func() (interface{}, error) {
_, err := cm.PopulateFullCacheWithProgress(state.Platforms, progress)
return nil, err
},
)
state.CacheSync.SetSynced()
} else {
state.CacheSync.Start()
}

cache.RunArtworkValidation()

registerScreens(r, state)
r.OnTransition(buildTransitionFunc(state, quitOnBack, showCollections))

return r
}

func registerScreens(r *router.Router, state *AppState) {
r.Register(ScreenPlatformSelection, func(input any) (any, error) {
in := input.(ui.PlatformSelectionInput)

if state.Config.SaveSyncMode == internal.SaveSyncModeAutomatic {
state.autoSyncOnce.Do(func() {
state.AutoSync = sync.NewAutoSync(state.Host, state.Config)
ui.AddStatusBarIcon(state.AutoSync.Icon())
state.AutoSync.Start()
})
}

state.autoUpdateOnce.Do(func() {
state.AutoUpdate = update.NewAutoUpdate(state.CFW, state.Config.ReleaseChannel, &state.Host)
ui.AddStatusBarIcon(state.AutoUpdate.Icon())
state.AutoUpdate.Start()
})

if in.ShowSaveSync == nil {
in.ShowSaveSync = computeShowSaveSync(state)
}

screen := ui.NewPlatformSelectionScreen()
return screen.Draw(in)
})

r.Register(ScreenGameList, func(input any) (any, error) {
screen := ui.NewGameListScreen()
return screen.Draw(input.(ui.GameListInput))
})

r.Register(ScreenGameDetails, func(input any) (any, error) {
screen := ui.NewGameDetailsScreen()
return screen.Draw(input.(ui.GameDetailsInput))
})

r.Register(ScreenGameOptions, func(input any) (any, error) {
screen := ui.NewGameOptionsScreen()
return screen.Draw(input.(ui.GameOptionsInput))
})

r.Register(ScreenSearch, func(input any) (any, error) {
screen := ui.NewSearchScreen()
return screen.Draw(input.(ui.SearchInput))
})

r.Register(ScreenCollectionList, func(input any) (any, error) {
screen := ui.NewCollectionSelectionScreen()
return screen.Draw(input.(ui.CollectionSelectionInput))
})

r.Register(ScreenCollectionPlatformSelection, func(input any) (any, error) {
screen := ui.NewCollectionPlatformSelectionScreen()
return screen.Draw(input.(ui.CollectionPlatformSelectionInput))
})

r.Register(ScreenSettings, func(input any) (any, error) {
screen := ui.NewSettingsScreen()
return screen.Draw(input.(ui.SettingsInput))
})

r.Register(ScreenGeneralSettings, func(input any) (any, error) {
screen := ui.NewGeneralSettingsScreen()
return screen.Draw(input.(ui.GeneralSettingsInput))
})

r.Register(ScreenCollectionsSettings, func(input any) (any, error) {
screen := ui.NewCollectionsSettingsScreen()
return screen.Draw(input.(ui.CollectionsSettingsInput))
})

r.Register(ScreenAdvancedSettings, func(input any) (any, error) {
screen := ui.NewAdvancedSettingsScreen()
return screen.Draw(input.(ui.AdvancedSettingsInput))
})

r.Register(ScreenPlatformMapping, func(input any) (any, error) {
screen := ui.NewPlatformMappingScreen()
return screen.Draw(input.(ui.PlatformMappingInput))
})

r.Register(ScreenSaveSyncSettings, func(input any) (any, error) {
screen := ui.NewSaveSyncSettingsScreen()
return screen.Draw(input.(ui.SaveSyncSettingsInput))
})

r.Register(ScreenInfo, func(input any) (any, error) {
screen := ui.NewInfoScreen()
return screen.Draw(input.(ui.InfoInput))
})

r.Register(ScreenLogoutConfirmation, func(input any) (any, error) {
screen := ui.NewLogoutConfirmationScreen()
return screen.Draw()
})

r.Register(ScreenRebuildCache, func(input any) (any, error) {
in := input.(ui.RebuildCacheInput)
in.CacheSync = state.CacheSync
screen := ui.NewRebuildCacheScreen()
return screen.Draw(in)
})

r.Register(ScreenSaveSync, func(input any) (any, error) {
screen := ui.NewSaveSyncScreen()
return screen.Draw(input.(ui.SaveSyncInput))
})

r.Register(ScreenBIOSDownload, func(input any) (any, error) {
in := input.(ui.BIOSDownloadInput)
screen := ui.NewBIOSDownloadScreen()
screen.Execute(in.Config, in.Host, in.Platform)
return ui.BIOSDownloadOutput{Platform: in.Platform}, nil
})

r.Register(ScreenArtworkSync, func(input any) (any, error) {
in := input.(ui.ArtworkSyncInput)
screen := ui.NewArtworkSyncScreen()
screen.Execute(in.Config, in.Host)
return ui.ArtworkSyncOutput{}, nil
})

r.Register(ScreenUpdateCheck, func(input any) (any, error) {
screen := ui.NewUpdateScreen()
return screen.Draw(input.(ui.UpdateInput))
})
}
Loading