ui
This commit is contained in:
@@ -120,6 +120,9 @@ pub enum PeerEvent {
|
|||||||
DownloadGameFilesFailed {
|
DownloadGameFilesFailed {
|
||||||
id: String,
|
id: String,
|
||||||
},
|
},
|
||||||
|
NoPeersHaveGame {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
PeerConnected(SocketAddr),
|
PeerConnected(SocketAddr),
|
||||||
PeerDisconnected(SocketAddr),
|
PeerDisconnected(SocketAddr),
|
||||||
PeerDiscovered(SocketAddr),
|
PeerDiscovered(SocketAddr),
|
||||||
@@ -1315,6 +1318,9 @@ async fn handle_get_game_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerE
|
|||||||
let peers = { ctx.peer_game_db.read().await.peers_with_game(&id) };
|
let peers = { ctx.peer_game_db.read().await.peers_with_game(&id) };
|
||||||
if peers.is_empty() {
|
if peers.is_empty() {
|
||||||
log::warn!("No peers have game {id}");
|
log::warn!("No peers have game {id}");
|
||||||
|
if let Err(e) = tx_notify_ui.send(PeerEvent::NoPeersHaveGame { id: id.clone() }) {
|
||||||
|
log::error!("Failed to send NoPeersHaveGame event: {e}");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -663,6 +663,21 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
PeerEvent::NoPeersHaveGame { id } => {
|
||||||
|
log::warn!("PeerEvent::NoPeersHaveGame received for {id}");
|
||||||
|
|
||||||
|
if let Err(e) = app_handle.emit("game-no-peers", Some(id.clone())) {
|
||||||
|
log::error!("PeerEvent::NoPeersHaveGame: Failed to emit game-no-peers event: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
app_handle
|
||||||
|
.state::<LanSpreadState>()
|
||||||
|
.inner()
|
||||||
|
.games_in_download
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.remove(&id);
|
||||||
|
}
|
||||||
PeerEvent::DownloadGameFilesBegin { id } => {
|
PeerEvent::DownloadGameFilesBegin { id } => {
|
||||||
log::info!("PeerEvent::DownloadGameFilesBegin received");
|
log::info!("PeerEvent::DownloadGameFilesBegin received");
|
||||||
|
|
||||||
|
|||||||
@@ -216,3 +216,15 @@ h1.align-center {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-info {
|
||||||
|
min-height: 18px;
|
||||||
|
margin: 8px 10px 16px;
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: #8892b0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-info.error {
|
||||||
|
color: #ff6666;
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,16 +18,20 @@ enum InstallStatus {
|
|||||||
Installed = 'Installed',
|
Installed = 'Installed',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StatusLevel = 'info' | 'error';
|
||||||
|
|
||||||
interface Game {
|
interface Game {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
size: number;
|
size: number;
|
||||||
thumbnail: Uint8Array;
|
thumbnail: Uint8Array | number[];
|
||||||
installed: boolean;
|
installed: boolean;
|
||||||
install_status: InstallStatus;
|
install_status: InstallStatus;
|
||||||
eti_game_version?: string;
|
eti_game_version?: string;
|
||||||
local_version?: string;
|
local_version?: string;
|
||||||
|
status_message?: string;
|
||||||
|
status_level?: StatusLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
@@ -57,7 +61,12 @@ const App = () => {
|
|||||||
const game_id = event.payload as string;
|
const game_id = event.payload as string;
|
||||||
console.log(`❌ game-download-failed ${game_id} event received`);
|
console.log(`❌ game-download-failed ${game_id} event received`);
|
||||||
setGameItems(prev => prev.map(item => item.id === game_id
|
setGameItems(prev => prev.map(item => item.id === game_id
|
||||||
? {...item, install_status: InstallStatus.NotInstalled}
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: item.installed ? InstallStatus.Installed : InstallStatus.NotInstalled,
|
||||||
|
status_message: 'Download failed. Please try again.',
|
||||||
|
status_level: 'error',
|
||||||
|
}
|
||||||
: item));
|
: item));
|
||||||
|
|
||||||
// Convert to string explicitly and verify it's not empty
|
// Convert to string explicitly and verify it's not empty
|
||||||
@@ -72,7 +81,24 @@ const App = () => {
|
|||||||
return unlisten;
|
return unlisten;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setupNoPeersListener = async () => {
|
||||||
|
const unlisten = await listen('game-no-peers', (event) => {
|
||||||
|
const game_id = event.payload as string;
|
||||||
|
console.log(`⚠️ game-no-peers ${game_id} event received`);
|
||||||
|
setGameItems(prev => prev.map(item => item.id === game_id
|
||||||
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: item.installed ? InstallStatus.Installed : InstallStatus.NotInstalled,
|
||||||
|
status_message: 'No peers currently have this game.',
|
||||||
|
status_level: 'error',
|
||||||
|
}
|
||||||
|
: item));
|
||||||
|
});
|
||||||
|
return unlisten;
|
||||||
|
};
|
||||||
|
|
||||||
setupDownloadFailedListener();
|
setupDownloadFailedListener();
|
||||||
|
setupNoPeersListener();
|
||||||
}, [gameDir]);
|
}, [gameDir]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -82,7 +108,12 @@ const App = () => {
|
|||||||
const game_id = event.payload as string;
|
const game_id = event.payload as string;
|
||||||
console.log(`🗲 game-unpack-finished ${game_id} event received`);
|
console.log(`🗲 game-unpack-finished ${game_id} event received`);
|
||||||
setGameItems(prev => prev.map(item => item.id === game_id
|
setGameItems(prev => prev.map(item => item.id === game_id
|
||||||
? {...item, install_status: InstallStatus.Installed}
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: InstallStatus.Installed,
|
||||||
|
status_message: undefined,
|
||||||
|
status_level: undefined,
|
||||||
|
}
|
||||||
: item));
|
: item));
|
||||||
|
|
||||||
// Convert to string explicitly and verify it's not empty
|
// Convert to string explicitly and verify it's not empty
|
||||||
@@ -131,7 +162,20 @@ const App = () => {
|
|||||||
console.log('🗲 Received games-list-updated event');
|
console.log('🗲 Received games-list-updated event');
|
||||||
const games = event.payload as Game[];
|
const games = event.payload as Game[];
|
||||||
console.log(`🎮 ${games.length} Games received`);
|
console.log(`🎮 ${games.length} Games received`);
|
||||||
setGameItems(games);
|
setGameItems(prev => {
|
||||||
|
const previousById = new Map(prev.map(item => [item.id, item]));
|
||||||
|
return games.map(game => {
|
||||||
|
const previous = previousById.get(game.id);
|
||||||
|
const installStatus = previous?.install_status
|
||||||
|
?? (game.installed ? InstallStatus.Installed : InstallStatus.NotInstalled);
|
||||||
|
return {
|
||||||
|
...game,
|
||||||
|
install_status: installStatus,
|
||||||
|
status_message: previous?.status_message,
|
||||||
|
status_level: previous?.status_level,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
getInitialGameDir();
|
getInitialGameDir();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -140,7 +184,12 @@ const App = () => {
|
|||||||
const game_id = event.payload as string;
|
const game_id = event.payload as string;
|
||||||
console.log(`🗲 game-download-begin ${game_id} event received`);
|
console.log(`🗲 game-download-begin ${game_id} event received`);
|
||||||
setGameItems(prev => prev.map(item => item.id === game_id
|
setGameItems(prev => prev.map(item => item.id === game_id
|
||||||
? { ...item, install_status: InstallStatus.Downloading }
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: InstallStatus.Downloading,
|
||||||
|
status_message: undefined,
|
||||||
|
status_level: undefined,
|
||||||
|
}
|
||||||
: item));
|
: item));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,7 +198,12 @@ const App = () => {
|
|||||||
const game_id = event.payload as string;
|
const game_id = event.payload as string;
|
||||||
console.log(`🗲 game-download-finished ${game_id} event received`);
|
console.log(`🗲 game-download-finished ${game_id} event received`);
|
||||||
setGameItems(prev => prev.map(item => item.id === game_id
|
setGameItems(prev => prev.map(item => item.id === game_id
|
||||||
? { ...item, install_status: InstallStatus.Unpacking }
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: InstallStatus.Unpacking,
|
||||||
|
status_message: undefined,
|
||||||
|
status_level: undefined,
|
||||||
|
}
|
||||||
: item));
|
: item));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -195,7 +249,12 @@ const App = () => {
|
|||||||
console.log(`✅ Game install for id=${id} started...`);
|
console.log(`✅ Game install for id=${id} started...`);
|
||||||
// update install status in gameItems for this game
|
// update install status in gameItems for this game
|
||||||
setGameItems(prev => prev.map(item => item.id === id
|
setGameItems(prev => prev.map(item => item.id === id
|
||||||
? { ...item, install_status: InstallStatus.CheckingPeers }
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: InstallStatus.CheckingPeers,
|
||||||
|
status_message: undefined,
|
||||||
|
status_level: undefined,
|
||||||
|
}
|
||||||
: item));
|
: item));
|
||||||
} else {
|
} else {
|
||||||
// game is already being installed
|
// game is already being installed
|
||||||
@@ -214,7 +273,12 @@ const App = () => {
|
|||||||
console.log(`✅ Game update for id=${id} started...`);
|
console.log(`✅ Game update for id=${id} started...`);
|
||||||
// update install status in gameItems for this game
|
// update install status in gameItems for this game
|
||||||
setGameItems(prev => prev.map(item => item.id === id
|
setGameItems(prev => prev.map(item => item.id === id
|
||||||
? { ...item, install_status: InstallStatus.CheckingPeers }
|
? {
|
||||||
|
...item,
|
||||||
|
install_status: InstallStatus.CheckingPeers,
|
||||||
|
status_message: undefined,
|
||||||
|
status_level: undefined,
|
||||||
|
}
|
||||||
: item));
|
: item));
|
||||||
} else {
|
} else {
|
||||||
// game is already being installed/updated
|
// game is already being installed/updated
|
||||||
@@ -337,6 +401,9 @@ const App = () => {
|
|||||||
: 'Update'
|
: 'Update'
|
||||||
: 'Play'}
|
: 'Play'}
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`item-info${item.status_level ? ` ${item.status_level}` : ''}`}>
|
||||||
|
{item.status_message ?? ''}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user