mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 11:05:47 +05:00
various small UI improvements
This commit is contained in:
parent
5438bba025
commit
b227cde173
@ -8,7 +8,7 @@ function loadLobbyDetails(id, apply) {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsChats/getChatLobbyInfo',
|
||||
{
|
||||
id,
|
||||
id: { xstr64: id },
|
||||
},
|
||||
(detail, success) => {
|
||||
if (success && detail.retval) {
|
||||
@ -18,10 +18,7 @@ function loadLobbyDetails(id, apply) {
|
||||
apply(null);
|
||||
}
|
||||
},
|
||||
true,
|
||||
{},
|
||||
undefined,
|
||||
() => '{"id":"' + id + '"}'
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
@ -36,11 +33,11 @@ function loadDistantChatDetails(pid, apply) {
|
||||
if (success && detail.retval) {
|
||||
// Map to lobby-like structure for UI compatibility
|
||||
const info = detail.info;
|
||||
info.chatType = 2; // DISTANT (was 4, matched BROADCAST in C++)
|
||||
info.chatType = 2; // DISTANT (matches TYPE_PRIVATE_DISTANT in rschats.h)
|
||||
info.lobby_name = rs.userList.username(info.to_id) || 'Distant Chat ' + pid;
|
||||
info.lobby_topic = 'Private Encrypted Chat';
|
||||
info.gxs_id = info.own_id;
|
||||
info.lobby_id = { xstr64: pid }; // Use PID as lobby_id for UI internal routing
|
||||
info.lobby_id = pid; // Distant IDs are 128-bit hex strings, NO xstr64 wrapper
|
||||
apply(info);
|
||||
} else {
|
||||
apply(null);
|
||||
@ -94,7 +91,7 @@ const ChatRoomsModel = {
|
||||
// Deduplicate by ID to avoid double display if backend returns redundant info
|
||||
const seen = new Set();
|
||||
const uniqueLobbies = data.public_lobbies.filter((lobby) => {
|
||||
const id = lobby.lobby_id.xstr64;
|
||||
const id = rs.idToHex(lobby.lobby_id);
|
||||
if (seen.has(id)) return false;
|
||||
seen.add(id);
|
||||
return true;
|
||||
@ -114,7 +111,7 @@ const ChatRoomsModel = {
|
||||
(data) => {
|
||||
if (data && data.cl_list) {
|
||||
// Robust deduplication of IDs
|
||||
const ids = [...new Set(data.cl_list.map((lid) => lid.xstr64))];
|
||||
const ids = [...new Set(data.cl_list.map((lid) => rs.idToHex(lid)))];
|
||||
ChatRoomsModel.knownSubscrIds = ids;
|
||||
|
||||
// Remove stale entries that are no longer in the subscribed list
|
||||
@ -155,7 +152,7 @@ const ChatRoomsModel = {
|
||||
);
|
||||
},
|
||||
subscribed(info) {
|
||||
return this.knownSubscrIds.includes(info.lobby_id.xstr64);
|
||||
return this.knownSubscrIds.includes(rs.idToHex(info.lobby_id));
|
||||
},
|
||||
};
|
||||
|
||||
@ -171,17 +168,15 @@ const Message = () => {
|
||||
const datetime = new Date(msg.sendTime * 1000).toLocaleTimeString();
|
||||
// Handle both HistoryMsg (peerId) and ChatMessage (lobby_peer_gxs_id)
|
||||
const rawGxsId = msg.lobby_peer_gxs_id || msg.peerId;
|
||||
let gxsId = rawGxsId;
|
||||
if (rawGxsId && typeof rawGxsId === 'object') {
|
||||
gxsId = (rawGxsId.xstr64 && rawGxsId.xstr64 !== '0') ? rawGxsId.xstr64 : rawGxsId;
|
||||
}
|
||||
let gxsId = rs.idToHex(rawGxsId);
|
||||
|
||||
// Fallback for 1-to-1 chats where sender ID might be missing (zeros)
|
||||
const isZero = (id) => !id || id === '00000000000000000000000000000000' || id.xstr64 === '0';
|
||||
const isZero = (id) => !id || id === '00000000000000000000000000000000';
|
||||
if (isZero(gxsId)) {
|
||||
const lobby = ChatLobbyModel.currentLobby;
|
||||
// Types 1 (Private), 2 (Distant) are "private" conversations here
|
||||
if (lobby && (lobby.chatType === 1 || lobby.chatType === 2)) {
|
||||
gxsId = msg.incoming ? (lobby.to_id || lobby.peer_id) : (lobby.own_id || lobby.gxs_id);
|
||||
gxsId = msg.incoming ? rs.idToHex(lobby.to_id || lobby.peer_id || lobby.distant_chat_id) : rs.idToHex(lobby.own_id || lobby.gxs_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,43 +275,47 @@ const ChatLobbyModel = {
|
||||
setIdentity(lobbyId, nick) {
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsChats/setIdentityForChatLobby',
|
||||
{},
|
||||
() => m.route.set('/chat/:lobby_id', { lobbyId }),
|
||||
true,
|
||||
{},
|
||||
JSON.parse,
|
||||
() => '{"lobby_id":' + lobbyId + ',"nick":"' + nick + '"}'
|
||||
{
|
||||
lobby_id: { xstr64: lobbyId },
|
||||
nick: nick,
|
||||
},
|
||||
() => m.route.set('/chat/:lobby', { lobby: lobbyId }),
|
||||
true
|
||||
);
|
||||
},
|
||||
enterPublicLobby(lobbyId, nick) {
|
||||
// Set lobby nickname
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsChats/joinVisibleChatLobby',
|
||||
{},
|
||||
{
|
||||
lobby_id: { xstr64: lobbyId },
|
||||
own_id: nick,
|
||||
},
|
||||
() => {
|
||||
loadLobbyDetails(lobbyId, (info) => {
|
||||
ChatRoomsModel.subscribedRooms[lobbyId] = info;
|
||||
ChatRoomsModel.loadSubscribedRooms(() => {
|
||||
m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 });
|
||||
m.route.set('/chat/:lobby', { lobby: rs.idToHex(info.lobby_id) });
|
||||
});
|
||||
});
|
||||
},
|
||||
true,
|
||||
{},
|
||||
JSON.parse,
|
||||
() => '{"lobby_id":' + lobbyId + ',"own_id":"' + nick + '"}'
|
||||
true
|
||||
);
|
||||
},
|
||||
unsubscribeChatLobby(lobbyId, follow) {
|
||||
// Unsubscribe
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsChats/unsubscribeChatLobby',
|
||||
{},
|
||||
() => ChatRoomsModel.loadSubscribedRooms(follow),
|
||||
true,
|
||||
{},
|
||||
JSON.parse,
|
||||
() => '{"lobby_id":' + lobbyId + '}'
|
||||
{
|
||||
id: { xstr64: lobbyId },
|
||||
},
|
||||
(data, success) => {
|
||||
if (success) {
|
||||
if (follow) {
|
||||
follow();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
chatId() {
|
||||
@ -356,22 +355,30 @@ const ChatLobbyModel = {
|
||||
this.addMessages(l);
|
||||
});
|
||||
|
||||
// Register for chatEvents for future messages
|
||||
// Register for chatEvents for future messages
|
||||
rs.events[15].notify = (chatMessage) => {
|
||||
// DEBUG: Log incoming message structure
|
||||
console.log('[RS-DEBUG] Incoming Chat Message:', JSON.stringify(chatMessage, null, 2));
|
||||
|
||||
const msgCid = chatMessage.chat_id;
|
||||
let match = false;
|
||||
if (msgCid.type === detail.chatType) {
|
||||
if (detail.chatType === 3) {
|
||||
const clid = msgCid.lobby_id ? (typeof msgCid.lobby_id === 'object' ? msgCid.lobby_id.xstr64 : msgCid.lobby_id) : undefined;
|
||||
if (clid === currentlobbyid) match = true;
|
||||
} else if (detail.chatType === 2) {
|
||||
const dChatIdRaw = msgCid.distant_chat_id;
|
||||
const dChatId = typeof dChatIdRaw === 'object' ? (dChatIdRaw.xstr64 !== '0' ? dChatIdRaw.xstr64 : dChatIdRaw) : dChatIdRaw;
|
||||
if (dChatId == currentlobbyid) match = true;
|
||||
}
|
||||
let msgId;
|
||||
|
||||
if (msgCid.type === 3) {
|
||||
msgId = rs.idToHex(msgCid.lobby_id);
|
||||
} else if (msgCid.type === 2) {
|
||||
// For Distant Chat, the ID is the distant_chat_id
|
||||
msgId = rs.idToHex(msgCid.distant_chat_id);
|
||||
} else if (msgCid.type === 1) {
|
||||
// For Private Chat, the ID is the peer_id
|
||||
msgId = rs.idToHex(msgCid.peer_id);
|
||||
} else {
|
||||
// Fallback
|
||||
msgId = rs.idToHex(msgCid);
|
||||
}
|
||||
if (match) {
|
||||
|
||||
console.log('[RS-DEBUG] Resolved Msg ID:', msgId, 'Current Lobby ID:', currentlobbyid, 'Match:', msgId === currentlobbyid);
|
||||
|
||||
if (msgId === currentlobbyid) {
|
||||
this.addMessages([chatMessage]);
|
||||
}
|
||||
};
|
||||
@ -411,7 +418,7 @@ const ChatLobbyModel = {
|
||||
this.setupAction = this.enterPublicLobby;
|
||||
this.isSubscribed = false;
|
||||
ChatRoomsModel.allRooms.forEach((it) => {
|
||||
if (it.lobby_id.xstr64 === currentlobbyid) {
|
||||
if (rs.idToHex(it.lobby_id) === currentlobbyid) {
|
||||
this.currentLobby = it;
|
||||
this.lobby_user = '???';
|
||||
this.lobbyid = currentlobbyid;
|
||||
@ -443,21 +450,20 @@ const ChatLobbyModel = {
|
||||
);
|
||||
},
|
||||
selected(info, selName, defaultName) {
|
||||
const currid = (ChatLobbyModel.currentLobby.lobby_id || { xstr64: m.route.param('lobby') })
|
||||
.xstr64;
|
||||
return (info.lobby_id.xstr64 === currid ? selName : '') + defaultName;
|
||||
const currid = rs.idToHex(ChatLobbyModel.currentLobby.lobby_id || { xstr64: m.route.param('lobby') });
|
||||
return (rs.idToHex(info.lobby_id) === currid ? selName : '') + defaultName;
|
||||
},
|
||||
switchToEvent(info) {
|
||||
return () => {
|
||||
ChatLobbyModel.currentLobby = info;
|
||||
m.route.set('/chat/:lobby', { lobby: info.lobby_id.xstr64 });
|
||||
ChatLobbyModel.loadLobby(info.lobby_id.xstr64); // update
|
||||
m.route.set('/chat/:lobby', { lobby: rs.idToHex(info.lobby_id) });
|
||||
ChatLobbyModel.loadLobby(rs.idToHex(info.lobby_id)); // update
|
||||
};
|
||||
},
|
||||
setupEvent(info) {
|
||||
return () => {
|
||||
m.route.set('/chat/:lobby/setup', { lobby: info.lobby_id.xstr64 });
|
||||
ChatLobbyModel.loadPublicLobby(info.lobby_id.xstr64); // update
|
||||
m.route.set('/chat/:lobby/setup', { lobby: rs.idToHex(info.lobby_id) });
|
||||
ChatLobbyModel.loadPublicLobby(rs.idToHex(info.lobby_id)); // update
|
||||
};
|
||||
},
|
||||
};
|
||||
@ -471,7 +477,7 @@ const Lobby = () => {
|
||||
return m(
|
||||
ChatLobbyModel.selected(info, '.selected-lobby', tagname),
|
||||
{
|
||||
key: info.lobby_id.xstr64,
|
||||
key: rs.idToHex(info.lobby_id),
|
||||
onclick,
|
||||
},
|
||||
[
|
||||
@ -570,11 +576,36 @@ const LobbyName = () => {
|
||||
ChatLobbyModel.isSubscribed
|
||||
? [m('span.chatusername', ChatLobbyModel.lobby_user), m('span.chatatchar', '@')]
|
||||
: [],
|
||||
ChatLobbyModel.currentLobby.chatType === 2
|
||||
? m('i.fas.fa-circle', {
|
||||
style: {
|
||||
color:
|
||||
ChatLobbyModel.currentLobby.status === 2
|
||||
? '#2ecc71' // Green (Can Talk)
|
||||
: ChatLobbyModel.currentLobby.status === 1
|
||||
? '#f39c12' // Orange (Tunnel Down)
|
||||
: ChatLobbyModel.currentLobby.status === 3
|
||||
? '#e74c3c' // Red (Remotely Closed)
|
||||
: '#95a5a6', // Grey (Unknown)
|
||||
fontSize: '0.6em',
|
||||
marginRight: '10px',
|
||||
verticalAlign: 'middle',
|
||||
},
|
||||
title:
|
||||
ChatLobbyModel.currentLobby.status === 2
|
||||
? 'Tunnel Active (Can Talk)'
|
||||
: ChatLobbyModel.currentLobby.status === 1
|
||||
? 'Tunnel Down (Negotiating...)'
|
||||
: ChatLobbyModel.currentLobby.status === 3
|
||||
? 'Remotely Closed'
|
||||
: 'Status Unknown',
|
||||
})
|
||||
: [],
|
||||
m('span.chatlobbyname', ChatLobbyModel.currentLobby.lobby_name),
|
||||
m('.mobile-menu-icons', [
|
||||
m('i.fas.fa-users', { onclick: () => MobileState.toggleUsers() }),
|
||||
]),
|
||||
m.route.param('subaction') !== 'setup'
|
||||
m.route.param('subaction') !== 'setup' && ChatLobbyModel.currentLobby.chatType === 3
|
||||
? [
|
||||
m('i.fas.fa-cog.setupicon', {
|
||||
title: 'configure lobby',
|
||||
@ -739,8 +770,8 @@ const LayoutCreateDistant = () => {
|
||||
from_pid: id,
|
||||
notify: true,
|
||||
},
|
||||
(result) => {
|
||||
m.route.set('/chat/:lobbyid', { lobbyid: result.pid });
|
||||
(res) => {
|
||||
m.route.set('/chat/:lobby', { lobby: rs.idToHex(res.pid) });
|
||||
}
|
||||
),
|
||||
},
|
||||
|
||||
@ -149,24 +149,24 @@ const Component = () => {
|
||||
Downloads.resetSearch();
|
||||
},
|
||||
view: () => [
|
||||
m('.widget__body-heading', [
|
||||
m('h3', `Downloads (${Downloads.hashes ? Downloads.hashes.length : 0} files)`),
|
||||
m('.action', [
|
||||
m('.widget__body-heading', { style: { display: 'flex', flexDirection: 'column', alignItems: 'flex-start' } }, [
|
||||
m('.action', { style: { marginBottom: '10px' } }, [
|
||||
m('button', { onclick: () => widget.popupMessage(m(NewFileDialog)) }, 'Add new file'),
|
||||
m('button', { onclick: clearFileCompleted }, 'Clear completed'),
|
||||
]),
|
||||
m('h3', `Downloads (${Downloads.hashes ? Downloads.hashes.length : 0} files)`),
|
||||
]),
|
||||
m('.widget__body-content', [
|
||||
Downloads.statusMap &&
|
||||
Object.keys(Downloads.statusMap).map((hash) =>
|
||||
m(util.File, {
|
||||
info: Downloads.statusMap[hash],
|
||||
strategy: Downloads.strategies[hash],
|
||||
direction: 'down',
|
||||
transferred: Downloads.statusMap[hash].transfered.xint64,
|
||||
chunksInfo: Downloads.chunksMap[hash],
|
||||
})
|
||||
),
|
||||
Object.keys(Downloads.statusMap).map((hash) =>
|
||||
m(util.File, {
|
||||
info: Downloads.statusMap[hash],
|
||||
strategy: Downloads.strategies[hash],
|
||||
direction: 'down',
|
||||
transferred: Downloads.statusMap[hash].transfered.xint64,
|
||||
chunksInfo: Downloads.chunksMap[hash],
|
||||
})
|
||||
),
|
||||
]),
|
||||
],
|
||||
};
|
||||
|
||||
@ -205,7 +205,7 @@ const File = () => {
|
||||
});
|
||||
}
|
||||
return m('.file-view', { style: { display: info.isSearched ? 'block' : 'none' } }, [
|
||||
m('.file-view__heading', [
|
||||
m('.file-view__heading', { style: { display: 'flex', flexDirection: 'column', alignItems: 'flex-start' } }, [
|
||||
m('h6', info.fname),
|
||||
chunkStrat !== undefined &&
|
||||
direction === 'down' && [
|
||||
|
||||
@ -37,19 +37,40 @@ const navbar = () => {
|
||||
},
|
||||
[
|
||||
m('.nav-menu__logo', [
|
||||
m('img', {
|
||||
src: 'images/retroshare.svg',
|
||||
alt: 'retroshare_icon',
|
||||
}),
|
||||
m('.nav-menu__logo-text', [
|
||||
m('h5', 'RetroShare'),
|
||||
m('.webui-version-box', [
|
||||
m('span.webui-version', 'v87'),
|
||||
m(
|
||||
'.logo-container',
|
||||
{
|
||||
style: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginRight: '10px',
|
||||
},
|
||||
},
|
||||
[
|
||||
m('img', {
|
||||
src: 'images/retroshare.svg',
|
||||
alt: 'retroshare_icon',
|
||||
}),
|
||||
m('i.fas.fa-circle', {
|
||||
style: {
|
||||
color: rs.connectionState.status ? '#2ecc71' : '#e74c3c',
|
||||
fontSize: '0.6em',
|
||||
marginTop: '5px',
|
||||
transition: 'color 0.3s ease',
|
||||
},
|
||||
title: rs.connectionState.status ? 'Connected to RetroShare Core' : 'Connection Lost',
|
||||
}),
|
||||
m('span.webui-version', { style: { fontSize: '0.7em', marginTop: '3px', color: '#888' } }, 'v108'),
|
||||
m('i.fas.fa-sync-alt.refresh-icon', {
|
||||
style: { fontSize: '0.8em', marginTop: '2px', cursor: 'pointer', color: '#888' },
|
||||
onclick: () => window.location.reload(true),
|
||||
title: 'Force reload application',
|
||||
}),
|
||||
]),
|
||||
]
|
||||
),
|
||||
m('.nav-menu__logo-text', [
|
||||
m('h5', 'RetroShare'),
|
||||
]),
|
||||
]),
|
||||
m('.nav-menu__box', [
|
||||
|
||||
@ -96,6 +96,10 @@ function logout() {
|
||||
m.route.set('/');
|
||||
}
|
||||
|
||||
const connectionState = {
|
||||
status: true,
|
||||
};
|
||||
|
||||
function rsJsonApiRequest(
|
||||
path,
|
||||
data = {},
|
||||
@ -137,12 +141,14 @@ function rsJsonApiRequest(
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.status === 200) {
|
||||
connectionState.status = true;
|
||||
try {
|
||||
callback(result.body, true);
|
||||
} catch (e) {
|
||||
console.error('[RS] Error in success callback for path:', path, e);
|
||||
}
|
||||
} else {
|
||||
connectionState.status = false;
|
||||
if (result.status === 401) {
|
||||
setKeys(loginKey.username, loginKey.passwd, loginKey.url, false);
|
||||
m.route.set('/');
|
||||
@ -156,6 +162,7 @@ function rsJsonApiRequest(
|
||||
return result;
|
||||
})
|
||||
.catch(function (e) {
|
||||
connectionState.status = false;
|
||||
try {
|
||||
callback(e, false);
|
||||
} catch (cbErr) {
|
||||
@ -204,17 +211,10 @@ const eventQueue = {
|
||||
// #define RS_CHAT_TYPE_PUBLIC 1
|
||||
// #define RS_CHAT_TYPE_PRIVATE 2
|
||||
|
||||
1: (chatId) => {
|
||||
const id = chatId.peer_id;
|
||||
if (typeof id === 'object') return id.xstr64 !== '0' ? id.xstr64 : JSON.stringify(id);
|
||||
return id;
|
||||
}, // RS_CHAT_TYPE_PRIVATE
|
||||
2: (chatId) => {
|
||||
const id = chatId.distant_chat_id;
|
||||
if (typeof id === 'object') return id.xstr64 !== '0' ? id.xstr64 : JSON.stringify(id);
|
||||
return id;
|
||||
}, // RS_CHAT_TYPE_DISTANT
|
||||
3: (chatId) => (typeof chatId.lobby_id === 'object' ? chatId.lobby_id.xstr64 : chatId.lobby_id), // RS_CHAT_TYPE_LOBBY
|
||||
1: (cid) => hexId(cid),
|
||||
2: (cid) => hexId(cid),
|
||||
3: (cid) => hexId(cid),
|
||||
4: (cid) => hexId(cid),
|
||||
},
|
||||
messages: {},
|
||||
chatMessages: (chatId, owner, action) => {
|
||||
@ -514,8 +514,32 @@ function formatBytes(bytes, decimals = 2) {
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function hexId(id) {
|
||||
if (!id) return '';
|
||||
if (typeof id === 'string') return id;
|
||||
if (typeof id === 'number') return String(id);
|
||||
if (typeof id === 'object') {
|
||||
// 1. Check for xstr64 (64-bit wrapped ID)
|
||||
if (id.xstr64 && id.xstr64 !== '0') return id.xstr64;
|
||||
|
||||
// 2. Search for any hex string of appropriate length (128-bit or 64-bit)
|
||||
const keys = Object.keys(id);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const val = id[keys[i]];
|
||||
if (typeof val === 'string' && val.length >= 16 && val !== '00000000000000000000000000000000') return val;
|
||||
// Search deeper for nested xstr64
|
||||
if (val && typeof val === 'object' && val.xstr64 && val.xstr64 !== '0') return val.xstr64;
|
||||
}
|
||||
// 3. Last resort fallbacks
|
||||
if (id.xstr64 !== undefined) return String(id.xstr64);
|
||||
}
|
||||
return String(id);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
rsJsonApiRequest,
|
||||
idToHex: hexId,
|
||||
connectionState,
|
||||
setKeys,
|
||||
setBackgroundTask,
|
||||
logon,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user