Merge pull request #498 from Mikunj/mod-badges

Mod badges
pull/502/head
Mikunj Varsani 6 years ago committed by GitHub
commit 51f161a613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1 @@
<svg height="512pt" viewBox="0 -92 512 512" width="512pt" xmlns="http://www.w3.org/2000/svg"><path d="m419.25 277.976562h-326.5c-4.988281 0-9.648438-2.464843-12.457031-6.585937-43.078125-63.171875-46.382813-184.691406-46.632813-202.730469-.015625-.707031-.023437-1.421875-.023437-2.132812 0-8.316406 6.734375-15.0625 15.050781-15.078125h.03125c8.300781 0 15.046875 6.714843 15.078125 15.019531 0 .101562.003906.992188.039063 2.570312 1.328124 42.902344 36.644531 77.390626 79.863281 77.390626 44.058593 0 79.902343-35.84375 79.902343-79.902344 0-8.328125 6.753907-15.078125 15.078126-15.078125h34.636718c8.328125 0 15.078125 6.75 15.078125 15.078125 0 44.058594 35.847657 79.902344 79.90625 79.902344 43.257813 0 78.597657-34.550782 79.867188-77.507813.027343-1.507813.035156-2.351563.035156-2.449219.03125-8.308594 6.773437-15.023437 15.078125-15.023437h.027344c8.316406.015625 15.050781 6.761719 15.050781 15.078125 0 .714844-.007813 1.425781-.019531 2.136718-.253906 18.035157-3.558594 139.558594-46.632813 202.730469-2.808593 4.117188-7.472656 6.582031-12.457031 6.582031zm0 0" fill="#fff780"/><path d="m463.308594 51.449219c-.007813 0-.015625 0-.027344 0-8.300781 0-15.046875 6.714843-15.078125 15.019531 0 .101562-.003906.945312-.035156 2.453125-1.269531 42.953125-36.609375 77.507813-79.867188 77.507813-44.058593 0-79.902343-35.84375-79.902343-79.902344 0-8.328125-6.753907-15.078125-15.078126-15.078125h-17.316406v226.523437h163.246094c4.988281 0 9.648438-2.464844 12.457031-6.582031 43.078125-63.171875 46.382813-184.695313 46.632813-202.730469.015625-.707031.023437-1.421875.023437-2.132812-.003906-8.316406-6.738281-15.0625-15.054687-15.078125zm0 0" fill="#ffc02e"/><path d="m256 0c-26.863281 0-48.71875 21.855469-48.71875 48.71875s21.855469 48.714844 48.71875 48.714844 48.71875-21.851563 48.71875-48.714844-21.855469-48.71875-48.71875-48.71875zm0 0" fill="#ffc02e"/><path d="m256.003906 0v97.4375c26.863282-.003906 48.714844-21.855469 48.714844-48.71875s-21.855469-48.71484375-48.714844-48.71875zm0 0" fill="#ffa73b"/><path d="m48.71875 37.597656c-26.863281 0-48.71875 21.855469-48.71875 48.71875 0 26.863282 21.855469 48.71875 48.71875 48.71875s48.714844-21.855468 48.714844-48.71875c0-26.863281-21.851563-48.71875-48.714844-48.71875zm0 0" fill="#ffc02e"/><path d="m463.28125 37.597656c-26.863281 0-48.714844 21.855469-48.714844 48.71875 0 26.859375 21.851563 48.714844 48.714844 48.714844s48.71875-21.855469 48.71875-48.714844c0-26.863281-21.855469-48.71875-48.71875-48.71875zm0 0" fill="#ffa73b"/><path d="m419.25 327.441406h-326.5c-8.328125 0-15.078125-6.75-15.078125-15.078125v-44.964843h356.65625v44.964843c0 8.328125-6.75 15.078125-15.078125 15.078125zm0 0" fill="#ffc02e"/><path d="m256.003906 327.441406h163.246094c8.328125 0 15.078125-6.75 15.078125-15.078125v-44.964843h-178.324219zm0 0" fill="#ffa73b"/></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -55,6 +55,7 @@
'check.svg',
'clock.svg',
'close-circle.svg',
'crown.svg',
'delete.svg',
'dots-horizontal.svg',
'double-check.svg',

@ -2144,18 +2144,20 @@
});
}
},
isModerator() {
isModerator(pubKey) {
if (!this.isPublic()) {
return false;
}
return this.get('modStatus');
const moderators = this.get('moderators');
return Array.isArray(moderators) && moderators.includes(pubKey);
},
async setModStatus(newStatus) {
async setModerators(moderators) {
if (!this.isPublic()) {
return;
}
if (this.get('modStatus') !== newStatus) {
this.set({ modStatus: newStatus });
// TODO: compare array properly
if (!_.isEqual(this.get('moderators'), moderators)) {
this.set({ moderators });
await window.Signal.Data.updateConversation(this.id, this.attributes, {
Conversation: Whisper.Conversation,
});

@ -681,9 +681,12 @@
isP2p: !!this.get('isP2p'),
isPublic: !!this.get('isPublic'),
isRss: !!this.get('isRss'),
isModerator:
!!this.get('isPublic') &&
this.getConversation().isModerator(this.getSource()),
isDeletable:
!this.get('isPublic') ||
this.getConversation().isModerator() ||
this.getConversation().isModerator(this.OUR_NUMBER) ||
this.getSource() === this.OUR_NUMBER,
onCopyText: () => this.copyText(),

@ -7,7 +7,8 @@ const { URL, URLSearchParams } = require('url');
// Can't be less than 1200 if we have unauth'd requests
const PUBLICCHAT_MSG_POLL_EVERY = 1.5 * 1000; // 1.5s
const PUBLICCHAT_CHAN_POLL_EVERY = 20 * 1000; // 20s
const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 1 second
const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 5s
const PUBLICCHAT_MOD_POLL_EVERY = 30 * 1000; // 30s
// singleton to relay events to libtextsecure/message_receiver
class LokiPublicChatAPI extends EventEmitter {
@ -219,7 +220,7 @@ class LokiPublicChannelAPI {
this.pollForMessages();
this.pollForDeletions();
this.pollForChannel();
this.refreshModStatus();
this.pollForModerators();
}
stop() {
@ -227,6 +228,9 @@ class LokiPublicChannelAPI {
if (this.timers.channel) {
clearTimeout(this.timers.channel);
}
if (this.timers.moderator) {
clearTimeout(this.timers.moderator);
}
if (this.timers.delete) {
clearTimeout(this.timers.delete);
}
@ -306,17 +310,37 @@ class LokiPublicChannelAPI {
};
}
// get moderation actions
async pollForModerators() {
try {
await this.pollOnceForModerators();
} catch (e) {
log.warn(`Error while polling for public chat moderators: ${e}`);
}
if (this.running) {
this.timers.moderator = setTimeout(() => {
this.pollForModerators();
}, PUBLICCHAT_MOD_POLL_EVERY);
}
}
// get moderator status
async refreshModStatus() {
async pollOnceForModerators() {
// get moderator status
const res = await this.serverRequest('loki/v1/user_info');
// if no problems and we have data
if (!res.err && res.response && res.response.data) {
this.modStatus = res.response.data.moderator_status;
const res = await this.serverRequest(
`loki/v1/channel/${this.channelId}/get_moderators`
);
const ourNumber = textsecure.storage.user.getNumber();
// Get the list of moderators if no errors occurred
const moderators = !res.err && res.response && res.response.moderators;
// if we encountered problems then we'll keep the old mod status
if (moderators) {
this.modStatus = moderators.includes(ourNumber);
}
// if problems, we won't drop moderator status
await this.conversation.setModStatus(this.modStatus);
await this.conversation.setModerators(moderators || []);
// get token info
const tokenRes = await this.serverRequest('token');
@ -328,7 +352,6 @@ class LokiPublicChannelAPI {
tokenRes.response.data.user
) {
// get our profile name and write it to the network
const ourNumber = textsecure.storage.user.getNumber();
const profileConvo = ConversationController.get(ourNumber);
const profileName = profileConvo.getProfileName();
@ -386,11 +409,11 @@ class LokiPublicChannelAPI {
try {
await this.pollForChannelOnce();
} catch (e) {
log.warn(`Error while polling for public chat deletions: ${e}`);
log.warn(`Error while polling for public chat room details: ${e}`);
}
if (this.running) {
this.timers.channel = setTimeout(() => {
this.pollForChannelOnce();
this.pollForChannel();
}, PUBLICCHAT_CHAN_POLL_EVERY);
}
}

@ -510,38 +510,27 @@
}
.module-message__metadata__date,
.module-message__metadata__p2p {
.module-message__metadata__badge {
font-size: 11px;
line-height: 16px;
letter-spacing: 0.3px;
color: $color-gray-60;
text-transform: uppercase;
}
.module-message__metadata__public {
font-size: 11px;
line-height: 16px;
letter-spacing: 0.3px;
color: $color-gray-60;
text-transform: uppercase;
.module-message__metadata__badge {
font-weight: bold;
}
.module-message__metadata__date--incoming,
.module-message__metadata__p2p--incoming {
color: $color-white-08;
}
.module-message__metadata__public--incoming {
.module-message__metadata__badge--incoming {
color: $color-white-08;
}
.module-message__metadata__date--with-image-no-caption {
color: $color-white;
}
.module-message__metadata__p2p {
font-weight: bold;
}
.module-message__metadata__public {
font-weight: bold;
}
.module-message__metadata__spacer {
flex-grow: 1;
}
@ -2064,6 +2053,25 @@
transform: translate(-50%, -50%);
}
.module-avatar__icon--crown-wrapper {
position: absolute;
bottom: 0;
right: 0;
height: 21px;
width: 21px;
transform: translate(25%, 25%);
padding: 9%;
background-color: $color-white;
border-radius: 50%;
filter: drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.3));
}
.module-avatar__icon--crown {
@include color-svg('../images/crown.svg', #ffb000);
height: 100%;
width: 100%;
}
.module-avatar__icon--group {
@include color-svg('../images/profile-group.svg', $color-white);
}

@ -1325,6 +1325,10 @@ body.dark-theme {
background-color: $color-gray-05;
}
.module-avatar__icon--crown-wrapper {
background-color: $color-gray-75;
}
.module-avatar--no-image {
background-color: $color-conversation-grey-shade;
}

@ -94,7 +94,11 @@ export class JazzIcon extends React.PureComponent<Props> {
private hueShift(colors: Array<string>, generator: RNG) {
const amount = generator.random() * 30 - wobble / 2;
return colors.map(hex => Color(hex).rotate(amount).hex());
return colors.map(hex =>
Color(hex)
.rotate(amount)
.hex()
);
}
private genShape(

@ -48,6 +48,7 @@ interface LinkPreviewType {
export interface Props {
disableMenu?: boolean;
isModerator?: boolean;
isDeletable: boolean;
text?: string;
textPending?: boolean;
@ -195,6 +196,34 @@ export class Message extends React.PureComponent<Props, State> {
});
}
public renderMetadataBadges() {
const { direction, isP2p, isPublic, isModerator } = this.props;
const badges = [isPublic && 'Public', isP2p && 'P2p', isModerator && 'Mod'];
return badges
.map(badgeText => {
if (typeof badgeText !== 'string') {
return null;
}
return (
<span
className={classNames(
'module-message__metadata__badge',
`module-message__metadata__badge--${direction}`,
`module-message__metadata__badge--${badgeText.toLowerCase()}`,
`module-message__metadata__badge--${badgeText.toLowerCase()}--${direction}`
)}
key={badgeText}
>
&nbsp;&nbsp;{badgeText}
</span>
);
})
.filter(i => !!i);
}
public renderMetadata() {
const {
collapseMetadata,
@ -206,8 +235,6 @@ export class Message extends React.PureComponent<Props, State> {
text,
textPending,
timestamp,
isP2p,
isPublic,
} = this.props;
if (collapseMetadata) {
@ -217,9 +244,6 @@ export class Message extends React.PureComponent<Props, State> {
const isShowingImage = this.isShowingImage();
const withImageNoCaption = Boolean(!text && isShowingImage);
const showError = status === 'error' && direction === 'outgoing';
const hasBadge = isP2p || isPublic;
const badgeText = isPublic ? 'Public' : isP2p ? 'P2p' : '';
const badgeType = badgeText.toLowerCase();
return (
<div
@ -252,16 +276,7 @@ export class Message extends React.PureComponent<Props, State> {
module="module-message__metadata__date"
/>
)}
{hasBadge ? (
<span
className={classNames(
`module-message__metadata__${badgeType}`,
`module-message__metadata__${badgeType}--${direction}`
)}
>
&nbsp;&nbsp;{badgeText}
</span>
) : null}
{this.renderMetadataBadges()}
{expirationLength && expirationTimestamp ? (
<ExpireTimer
direction={direction}
@ -648,6 +663,7 @@ export class Message extends React.PureComponent<Props, State> {
authorPhoneNumber,
authorProfileName,
collapseMetadata,
isModerator,
authorColor,
conversationType,
direction,
@ -674,6 +690,11 @@ export class Message extends React.PureComponent<Props, State> {
profileName={authorProfileName}
size={36}
/>
{isModerator && (
<div className="module-avatar__icon--crown-wrapper">
<div className="module-avatar__icon--crown" />
</div>
)}
</div>
);
}

Loading…
Cancel
Save