Files
soft_quay/app-win7/ui/gio/icon_events.go
T

118 lines
3.3 KiB
Go

package gio
import (
"errors"
"fmt"
"softbox.local/core/application"
)
var ErrIconRequestStale = errors.New("icon request no longer matches catalog")
type iconFailureState struct {
Identity application.IconEventIdentity
Code application.IconFailureCode
}
// ExpectIcon records the newest request identity on the UI goroutine.
func (shell *AppShell) ExpectIcon(identity application.IconEventIdentity) error {
validated, err := application.NewIconEventIdentity(
identity.RequestID,
identity.AppID,
identity.Reference,
identity.DPI,
)
if err != nil {
return err
}
currentReference, exists := shell.iconReferences[validated.AppID]
if !exists || currentReference != validated.Reference {
return fmt.Errorf(
"%w: app=%q reference=%q",
ErrIconRequestStale,
validated.AppID,
validated.Reference,
)
}
if applied, exists := shell.iconApplied[validated.AppID]; !exists || !sameIconResource(applied, validated) {
delete(shell.icons, validated.AppID)
delete(shell.iconApplied, validated.AppID)
}
shell.iconRequests[validated.AppID] = validated
delete(shell.iconFailures, validated.AppID)
return nil
}
// CancelIconRequest invalidates the matching pending request on the UI goroutine.
func (shell *AppShell) CancelIconRequest(appID, requestID string) bool {
pending, exists := shell.iconRequests[appID]
if !exists || pending.RequestID != requestID {
return false
}
delete(shell.iconRequests, appID)
delete(shell.iconFailures, appID)
return true
}
// ApplyEvent validates and applies an application event on the UI goroutine.
func (shell *AppShell) ApplyEvent(event application.Event) error {
if handled, err := shell.applyCatalogEvent(event); err != nil || handled {
return err
}
if handled, err := shell.applyAuthorizationEvent(event); err != nil || handled {
return err
}
iconEvent, handled, err := application.ParseIconEvent(event)
if err != nil || !handled {
return err
}
identity := iconEvent.Identity
pending, exists := shell.iconRequests[identity.AppID]
if !exists || pending != identity {
return nil
}
if shell.iconReferences[identity.AppID] != identity.Reference {
return nil
}
delete(shell.iconRequests, identity.AppID)
switch iconEvent.Type {
case application.EventIconReady:
shell.ApplyIcon(identity.AppID, iconEvent.Image)
shell.iconApplied[identity.AppID] = identity
case application.EventIconFailed:
applied, hasApplied := shell.iconApplied[identity.AppID]
if !hasApplied || !sameIconResource(applied, identity) {
shell.ApplyIcon(identity.AppID, nil)
}
shell.iconFailures[identity.AppID] = iconFailureState{
Identity: identity,
Code: iconEvent.ErrorCode,
}
}
return nil
}
// IconFailure exposes the last failure for diagnostics without raw network data.
func (shell *AppShell) IconFailure(appID string) (application.IconFailureCode, bool) {
failure, exists := shell.iconFailures[appID]
return failure.Code, exists
}
func canonicalIconReference(reference string) string {
canonical, err := application.NormalizeIconReference(reference)
if err != nil {
return reference
}
return canonical
}
func sameIconResource(
left application.IconEventIdentity,
right application.IconEventIdentity,
) bool {
return left.AppID == right.AppID &&
left.Reference == right.Reference &&
left.DPI == right.DPI
}