support for pinning topics; truncate text with support for RTL languages

This commit is contained in:
or-else
2025-09-20 18:18:01 +03:00
parent 0fb5132d24
commit 4818ee7a25
56 changed files with 519 additions and 99 deletions
+3 -3
View File
@@ -8,7 +8,7 @@ import { MAX_TITLE_LENGTH, MAX_PEER_TITLE_LENGTH } from '../config.js';
import { CALL_STATE_INCOMING_RECEIVED } from '../constants.js';
import { makeImageUrl } from '../lib/blob-helpers.js';
import { clipStr } from '../lib/utils.js'
import { truncateString } from '../lib/strformat.js';
const RING_SOUND = new Audio('audio/call-in.m4a');
@@ -88,7 +88,7 @@ export default class CallIncoming extends React.Component {
}
this.setState({
fullName: clipStr(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
fullName: truncateString(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
avatar: makeImageUrl(topic.public ? topic.public.photo : null),
trustedBadges: badges,
});
@@ -127,7 +127,7 @@ export default class CallIncoming extends React.Component {
topic={this.props.topic}
title={this.state.fullName} />
</div>
<div className="caller-name">{clipStr(this.state.fullName, MAX_PEER_TITLE_LENGTH)}
<div className="caller-name">{truncateString(this.state.fullName, MAX_PEER_TITLE_LENGTH)}
<BadgeList short={true} trustedBadges={this.state.trustedBadges} /></div>
</div>
<div className="controls">
+2 -3
View File
@@ -6,8 +6,7 @@ import LetterTile from './letter-tile.jsx';
import { MAX_PEER_TITLE_LENGTH } from '../config.js';
import { CALL_STATE_OUTGOING_INITATED, CALL_STATE_IN_PROGRESS } from '../constants.js';
import { clipStr } from '../lib/utils.js'
import { truncateString } from '../lib/strformat.js';
const RING_SOUND = new Audio('audio/call-out.m4a');
RING_SOUND.loop = true;
@@ -584,7 +583,7 @@ class CallPanel extends React.PureComponent {
const disabled = !this.state.pc || !this.state.dataChannel || !(audioTracks && audioTracks[0]);
const audioIcon = audioTracks && audioTracks[0] && audioTracks[0].enabled ? 'mic' : 'mic_off';
const videoIcon = videoTracks && videoTracks[0] && videoTracks[0].enabled && videoTracks[0].readyState == 'live' ? 'videocam' : 'videocam_off';
const peerTitle = clipStr(this.props.title, MAX_PEER_TITLE_LENGTH);
const peerTitle = truncateString(this.props.title, MAX_PEER_TITLE_LENGTH);
const pulseAnimation = this.state.waitingForPeer ? ' pulse' : '';
let remoteActive = false;
+6 -3
View File
@@ -12,6 +12,7 @@ import { Drafty } from 'tinode-sdk';
import { previewFormatter } from '../lib/formatters.js';
import { deliveryMarker } from '../lib/utils.js';
import { truncateString } from '../lib/strformat.js';
const messages = defineMessages({
self_topic_name: {
@@ -65,8 +66,8 @@ class Contact extends React.Component {
description="Title shown when the topic has no name" /></i>;
}
} else if (title.length > 30) {
// FIXME: this is probably wrong for RTL languages.
title = title.substring(0, 28) + '…';
// Have to support RTL languages too.
title = truncateString(title, 30);
}
const online = this.props.now ? 'online' : 'offline';
const avatar = this.props.avatar ? this.props.avatar : true;
@@ -115,8 +116,10 @@ class Contact extends React.Component {
const comment = preview || this.props.comment ||
(self ? this.props.intl.formatMessage(messages.self_topic_comment) : '\u00A0');
const bgColor = this.props.showCheckmark ? null :
(this.props.selected ? 'selected' : (this.props.pinned ? 'pinned' : null));
return (
<li className={!this.props.showCheckmark && this.props.selected ? 'selected' : null} onClick={this.handleClick}>
<li className={bgColor} onClick={this.handleClick}>
<div className="avatar-box">
<LetterTile
tinode={this.props.tinode}
+42
View File
@@ -126,6 +126,16 @@ const messages = defineMessages({
defaultMessage: 'Unpin',
description: 'Menu item [Unpin] for un-pinning the message.'
},
pin_chat: {
id: 'pin_chat',
defaultMessage: 'Pin',
description: 'Menu item [Pin] for pinning chat to the top.'
},
unpin_chat: {
id: 'unpin_chat',
defaultMessage: 'Unpin',
description: 'Menu item [Unpin] for un-pinning the chat.'
},
});
class ContextMenu extends React.Component {
@@ -326,6 +336,38 @@ class ContextMenu extends React.Component {
});
}
},
'topic_pin': {
id: 'topic_pin',
title: formatMessage(messages.pin_chat),
handler: (params, errorHandler) => {
const me = this.props.tinode.getMeTopic();
if (!me) {
console.warn("'me' topic not found");
return;
}
return me.pinTopic(params.topicName, true).catch(err => {
if (errorHandler) {
errorHandler(err.message, 'err');
}
});
}
},
'topic_unpin': {
id: 'topic_unpin',
title: formatMessage(messages.unpin_chat),
handler: (params, errorHandler) => {
const me = this.props.tinode.getMeTopic();
if (!me) {
console.warn("'me' topic not found");
return;
}
return me.pinTopic(params.topicName, false).catch(err => {
if (errorHandler) {
errorHandler(err.message, 'err');
}
});
}
},
// menu_item_edit_permissions is defined elsewhere.
'permissions': {
id: 'permissions',
+4 -3
View File
@@ -9,6 +9,7 @@ import TagManager from './tag-manager.jsx';
import { AVATAR_SIZE, MAX_AVATAR_BYTES, MAX_EXTERN_ATTACHMENT_SIZE, MAX_TITLE_LENGTH,
MAX_TOPIC_DESCRIPTION_LENGTH } from '../config.js';
import { imageScaled, blobToBase64, makeImageUrl } from '../lib/blob-helpers.js';
import { truncateString } from '../lib/strformat.js';
export default class NewTopicGroup extends React.PureComponent {
constructor(props) {
@@ -100,9 +101,9 @@ export default class NewTopicGroup extends React.PureComponent {
handleSubmit(e) {
e.preventDefault();
const fn = this.state.fullName.trim().substring(0, MAX_TITLE_LENGTH);
const comment = this.state.private.trim().substring(0, MAX_TITLE_LENGTH);
const description = this.state.description.trim().substring(0, MAX_TOPIC_DESCRIPTION_LENGTH);
const fn = truncateString(this.state.fullName.trim(), MAX_TITLE_LENGTH);
const comment = truncateString(this.state.private.trim(), MAX_TITLE_LENGTH);
const description = truncateString(this.state.description.trim(), MAX_TOPIC_DESCRIPTION_LENGTH);
if (fn) {
this.props.onSubmit(fn, description, this.state.imageUrl, comment, this.state.tags, this.state.isChannel);
}
+2 -1
View File
@@ -13,6 +13,7 @@ import TagManager from './tag-manager.jsx';
import { AVATAR_SIZE, MAX_AVATAR_BYTES, MAX_EXTERN_ATTACHMENT_SIZE, MAX_TITLE_LENGTH,
MAX_TOPIC_DESCRIPTION_LENGTH } from '../config.js';
import { imageScaled, blobToBase64, makeImageUrl } from '../lib/blob-helpers.js';
import { truncateString } from '../lib/strformat.js';
import { arrayEqual, theCard } from '../lib/utils.js';
const messages = defineMessages({
@@ -98,7 +99,7 @@ class TopicDescEdit extends React.Component {
}
handleFullNameUpdate(fn) {
fn = fn.trim().substring(0, MAX_TITLE_LENGTH);
fn = truncateString(fn.trim(), MAX_TITLE_LENGTH);
if (fn && this.state.fullName !== fn) {
this.setState({fullName: fn});
this.props.onUpdateTopicDesc(this.props.topic, theCard(fn, null));