diff --git a/VERSION.properties b/VERSION.properties index 230d9d6f..2e486484 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.5.8 +client.version=1.5.9 server.version=1.4.7 diff --git a/shine-UI/js/pages/channel-thread-view.js b/shine-UI/js/pages/channel-thread-view.js index 65a62d97..d179abce 100644 --- a/shine-UI/js/pages/channel-thread-view.js +++ b/shine-UI/js/pages/channel-thread-view.js @@ -209,6 +209,24 @@ function resolveChannelDisplayName(channelSelector) { return `${found.channel?.ownerLogin || 'неизвестно'}/${found.channel?.channelName || 'канал'}`; } +function resolveChannelHeadingFromNode(node) { + const info = node?.channelInfo; + const ownerBch = String(info?.ownerBlockchainName || '').trim(); + const rootBlockNumber = Number(info?.channelRoot?.blockNumber); + if (!ownerBch || !Number.isFinite(rootBlockNumber) || rootBlockNumber < 0) return ''; + if (rootBlockNumber === 0) return 'История пользователя'; + + const label = resolveChannelDisplayName({ + ownerBlockchainName: ownerBch, + channelRootBlockNumber: rootBlockNumber, + channelRootBlockHash: '0', + }); + const slashIndex = label.indexOf('/'); + const channelName = slashIndex >= 0 ? label.slice(slashIndex + 1).trim() : label.trim(); + if (!channelName) return 'Сообщение в канале'; + return `Сообщение в канале ${channelName}`; +} + function extractChannelContextFromThreadPayload(payload) { const focusInfo = payload?.focus?.channelInfo; if (focusInfo?.ownerBlockchainName && focusInfo?.channelRoot?.blockNumber != null) { @@ -706,7 +724,7 @@ function renderNodeCard(node, heading, handlers, localNumber) { const isOwnMessage = String(node?.authorLogin || '').trim().toLowerCase() === String(state.session.login || '').trim().toLowerCase(); const isChannelPost = Number(node?.channelInfo?.channelRoot?.blockNumber) >= 0; const msgSubType = Number(node?.msgSubType || 0); - const repostTarget = msgSubType === 30 ? buildRepostTargetFromNode(node) : null; + const repostTarget = msgSubType === 50 ? buildRepostTargetFromNode(node) : null; const parsedText = parseMessageAttachments(text); const headingText = String(heading || '').trim(); @@ -1326,12 +1344,9 @@ export function render({ navigate, route }) { if (ancestors.length) { ancestorsWrap = document.createElement('div'); ancestorsWrap.className = 'stack thread-block thread-block--ancestors'; - const title = document.createElement('h3'); - title.className = 'section-title'; - title.textContent = 'История выше (на что это ответ)'; - ancestorsWrap.append(title); ancestors.forEach((node, index) => { - ancestorsWrap.append(renderNodeCard(node, `Предок ${index + 1}`, handlers, nextNumber())); + const heading = index === 0 ? resolveChannelHeadingFromNode(node) : ''; + ancestorsWrap.append(renderNodeCard(node, heading, handlers, nextNumber())); }); } diff --git a/shine-UI/js/pages/channel-view.js b/shine-UI/js/pages/channel-view.js index 1c64a2d0..11c7d6cb 100644 --- a/shine-UI/js/pages/channel-view.js +++ b/shine-UI/js/pages/channel-view.js @@ -37,6 +37,7 @@ import { buildArweaveDataUrl } from '../services/arweave-file-service.js'; export const pageMeta = { id: 'channel-view', title: 'Канал' }; const CHANNEL_TYPE_STORIES = 0; const CHANNEL_TYPE_PERSONAL = 100; +const MSG_SUBTYPE_TEXT_REPOST = 50; const pendingReactionActions = new Set(); const pendingScrollByRoute = new Map(); @@ -303,7 +304,19 @@ function createChannelAvatarElement(channel, size = 72) { return wrap; } -function openChannelMetaDetailsModal({ title = 'Данные канала', channel = {}, canEdit = false, onEdit = null } = {}) { +function openChannelMetaDetailsModal({ + title = 'Данные канала', + channel = {}, + canEdit = false, + onEdit = null, + changedAtMs = 0, +} = {}) { + const avatarState = String(channel.avaAr || '').trim() + ? 'Установлен' + : 'Не установлен'; + const changedAtLabel = changedAtMs + ? new Date(Number(changedAtMs)).toLocaleString('ru-RU') + : '—'; const root = document.getElementById('modal-root'); root.innerHTML = `
${escapeHtml(channel.displayTitle || channel.displayName || channel.name)}
- - + @@ -337,6 +355,7 @@ function openAboutChannelModal(channel, options = {}) { channel, canEdit: options.canEdit === true, onEdit: options.onEdit, + changedAtMs: Number(channel?.metaUpdatedAtMs || 0), }); } @@ -1181,15 +1200,14 @@ function renderChannelMetaEventCard(event) { const card = document.createElement('article'); card.className = 'card channel-system-event-card'; const label = event.kind === 'created' - ? `Создан канал ${event.title || event.name || ''}`.trim() - : 'Изменён профиль канала'; + ? 'Создан канал' + : 'Изменено описание канала'; card.innerHTML = ` - ${escapeHtml(label)} - ${escapeHtml(event.timestampMs ? new Date(event.timestampMs).toLocaleString('ru-RU') : '')} + ${escapeHtml(label)} `; card.addEventListener('click', () => { openChannelMetaDetailsModal({ - title: event.kind === 'created' ? 'Канал создан' : 'Профиль канала изменён', + title: label, channel: { name: event.name, displayTitle: event.title, @@ -1199,6 +1217,7 @@ function renderChannelMetaEventCard(event) { avaSize: event.avaSize, ownerName: event.ownerName, }, + changedAtMs: event.timestampMs, }); }); return card; @@ -1377,7 +1396,7 @@ function renderPostCard(post, { }); actions.append(shareButton); - if (post.msgSubType === 30 && post.targetRef?.blockchainName && Number.isFinite(post.targetRef?.blockNumber) && post.targetRef?.blockHash) { + if (post.msgSubType === MSG_SUBTYPE_TEXT_REPOST && post.targetRef?.blockchainName && Number.isFinite(post.targetRef?.blockNumber) && post.targetRef?.blockHash) { const originalBtn = document.createElement('button'); originalBtn.type = 'button'; originalBtn.className = 'channel-action-item'; @@ -1797,7 +1816,7 @@ export function render({ navigate, route }) { channelHeaderButton.onclick = (event) => { animatePress(event.currentTarget); openAboutChannelModal(apiData.channel, { - canEdit: apiData?.isOwnChannel === true, + canEdit: apiData?.isOwnChannel === true && !isStoriesChannel(apiData?.channel), onEdit: () => openEditChannelModal({ channel: apiData.channel, onSave: onEditChannelMeta, diff --git a/shine-UI/js/services/auth-service.js b/shine-UI/js/services/auth-service.js index 432147ce..0179c39d 100644 --- a/shine-UI/js/services/auth-service.js +++ b/shine-UI/js/services/auth-service.js @@ -53,8 +53,9 @@ const MSG_SUBTYPE_TEXT_POST = 10; const MSG_SUBTYPE_TEXT_EDIT_POST = 11; const MSG_SUBTYPE_TEXT_REPLY = 20; const MSG_SUBTYPE_TEXT_EDIT_REPLY = 21; -const MSG_SUBTYPE_TEXT_REPOST = 30; -const MSG_SUBTYPE_TEXT_CHANNEL_META = 70; +const MSG_SUBTYPE_TEXT_RATING = 30; +const MSG_SUBTYPE_TEXT_REPOST = 50; +const MSG_SUBTYPE_TEXT_CHANNEL_META = 90; const MSG_SUBTYPE_REACTION_LIKE = 1; const MSG_SUBTYPE_REACTION_UNLIKE = 2; const MSG_SUBTYPE_CONNECTION_FOLLOW = 30; diff --git a/shine-UI/styles/components.css b/shine-UI/styles/components.css index ff3f690b..9ef777e4 100644 --- a/shine-UI/styles/components.css +++ b/shine-UI/styles/components.css @@ -3939,6 +3939,12 @@ textarea.input { gap: 10px; } +.channels-screen--channel .channel-feed { + gap: 2px; + margin-left: -7px; + margin-right: -7px; +} + .channels-screen .channel-message-card { gap: 14px; padding: 20px; @@ -3950,6 +3956,10 @@ textarea.input { box-shadow: 0 0 60px rgba(80, 60, 180, 0.15); } +.channels-screen--channel .channel-message-card { + margin-bottom: 6px; +} + .channel-message-top { display: flex; align-items: center; @@ -4037,19 +4047,41 @@ textarea.input { .channel-system-event-card { display: flex; align-items: center; - justify-content: space-between; + justify-content: center; gap: 10px; - padding: 9px 11px; + width: fit-content; + max-width: min(88%, 460px); + margin: 0 auto 4px; + padding: 8px 16px; border-color: rgba(255, 210, 130, 0.22); - background: rgba(89, 67, 31, 0.22); + border-radius: 999px; + background: rgba(89, 67, 31, 0.26); color: rgba(255, 235, 188, 0.92); cursor: pointer; + text-align: center; } -.channel-system-event-card small { - flex: 0 0 auto; +.channel-system-event-card__label { + display: block; + font-size: 13px; + line-height: 1.2; +} + +.channel-meta-details-grid { + display: grid; + grid-template-columns: minmax(96px, 120px) 1fr; + gap: 10px 14px; + align-items: start; + color: rgba(255, 255, 255, 0.92); +} + +.channel-meta-details-grid > span:nth-child(odd) { color: rgba(255, 255, 255, 0.48); - font-size: 11px; +} + +.channel-meta-details-grid code { + color: rgba(255, 214, 117, 0.92); + word-break: break-word; } .channel-profile-card { @@ -5331,6 +5363,7 @@ textarea.input { } #about-channel-modal.modal, +#edit-channel-modal.modal, #reply-modal.modal, #channel-message-modal.modal, #channel-edit-description-modal.modal, @@ -5342,6 +5375,7 @@ textarea.input { } #about-channel-modal .modal-card, +#edit-channel-modal .modal-card, #reply-modal .modal-card, #channel-message-modal .modal-card, #channel-edit-description-modal .modal-card, @@ -5356,6 +5390,7 @@ textarea.input { } #about-channel-modal .modal-title, +#edit-channel-modal .modal-title, #reply-modal .modal-title, #channel-message-modal .modal-title, #channel-edit-description-modal .modal-title, @@ -5368,6 +5403,7 @@ textarea.input { } #about-channel-modal .input, +#edit-channel-modal .input, #reply-modal .input, #channel-message-modal .input, #channel-edit-description-modal .input, @@ -5390,6 +5426,7 @@ textarea.input { } #about-channel-modal .secondary-btn, +#edit-channel-modal .secondary-btn, #reply-modal .secondary-btn, #channel-message-modal .secondary-btn, #channel-edit-description-modal .secondary-btn, @@ -5403,6 +5440,7 @@ textarea.input { } #about-channel-modal .primary-btn, +#edit-channel-modal .primary-btn, #reply-modal .primary-btn, #channel-message-modal .primary-btn, #channel-edit-description-modal .primary-btn,