Route icon results through UI events (T-607)
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package gio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"softbox.local/core/application"
|
||||
)
|
||||
|
||||
var ErrIconRequestStale = errors.New("icon request no longer matches catalog")
|
||||
|
||||
// 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)
|
||||
return true
|
||||
}
|
||||
|
||||
// ApplyEvent validates and applies an application event on the UI goroutine.
|
||||
func (shell *AppShell) ApplyEvent(event application.Event) error {
|
||||
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] = 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, 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
|
||||
}
|
||||
Reference in New Issue
Block a user