Merge pull request #1336 from Bilb/remove-jazzicon
						commit
						56a81ccc93
					
				@ -1,22 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
    <!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
 | 
			
		||||
    <title>Group/group-28</title>
 | 
			
		||||
    <desc>Created with Sketch.</desc>
 | 
			
		||||
    <defs>
 | 
			
		||||
        <path d="M18.7272727,13.2857143 C20.6890909,13.2857143 22.2609091,11.6585714 22.2609091,9.64285714 C22.2609091,7.62714286 20.6890909,6 18.7272727,6 C16.7654545,6 15.1818182,7.62714286 15.1818182,9.64285714 C15.1818182,11.6585714 16.7654545,13.2857143 18.7272727,13.2857143 Z M9.27272727,13.2857143 C11.2345455,13.2857143 12.8063636,11.6585714 12.8063636,9.64285714 C12.8063636,7.62714286 11.2345455,6 9.27272727,6 C7.31090909,6 5.72727273,7.62714286 5.72727273,9.64285714 C5.72727273,11.6585714 7.31090909,13.2857143 9.27272727,13.2857143 Z M9.27272727,15.7142857 C6.51909091,15.7142857 1,17.135 1,19.9642857 L1,23 L17.5454545,23 L17.5454545,19.9642857 C17.5454545,17.135 12.0263636,15.7142857 9.27272727,15.7142857 Z M18.7272727,15.7142857 C18.3845455,15.7142857 17.9945455,15.7385714 17.5809091,15.775 C18.9518182,16.795 19.9090909,18.1671429 19.9090909,19.9642857 L19.9090909,23 L27,23 L27,19.9642857 C27,17.135 21.4809091,15.7142857 18.7272727,15.7142857 Z" id="path-1"></path>
 | 
			
		||||
        <rect id="path-3" x="0" y="0" width="28" height="28"></rect>
 | 
			
		||||
    </defs>
 | 
			
		||||
    <g id="Group/group-28" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
 | 
			
		||||
        <mask id="mask-2" fill="white">
 | 
			
		||||
            <use xlink:href="#path-1"></use>
 | 
			
		||||
        </mask>
 | 
			
		||||
        <use id="Shape" fill="#000000" fill-rule="nonzero" xlink:href="#path-1"></use>
 | 
			
		||||
        <g id="Color/UI/Black" mask="url(#mask-2)">
 | 
			
		||||
            <mask id="mask-4" fill="white">
 | 
			
		||||
                <use xlink:href="#path-3"></use>
 | 
			
		||||
            </mask>
 | 
			
		||||
            <use id="fill" fill="#000000" fill-rule="evenodd" xlink:href="#path-3"></use>
 | 
			
		||||
        </g>
 | 
			
		||||
    </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
@ -1,22 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
    <!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
 | 
			
		||||
    <title>Profile/profile-28</title>
 | 
			
		||||
    <desc>Created with Sketch.</desc>
 | 
			
		||||
    <defs>
 | 
			
		||||
        <path d="M14,14 C16.7625,14 19,11.7625 19,9 C19,6.2375 16.7625,4 14,4 C11.2375,4 9,6.2375 9,9 C9,11.7625 11.2375,14 14,14 Z M14,16.5 C10.6625,16.5 4,18.175 4,21.5 L4,24 L24,24 L24,21.5 C24,18.175 17.3375,16.5 14,16.5 Z" id="path-1"></path>
 | 
			
		||||
        <rect id="path-3" x="0" y="0" width="28" height="28"></rect>
 | 
			
		||||
    </defs>
 | 
			
		||||
    <g id="Profile/profile-28" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
 | 
			
		||||
        <mask id="mask-2" fill="white">
 | 
			
		||||
            <use xlink:href="#path-1"></use>
 | 
			
		||||
        </mask>
 | 
			
		||||
        <use id="Shape" fill="#000000" fill-rule="nonzero" xlink:href="#path-1"></use>
 | 
			
		||||
        <g id="Color/UI/Black" mask="url(#mask-2)">
 | 
			
		||||
            <mask id="mask-4" fill="white">
 | 
			
		||||
                <use xlink:href="#path-3"></use>
 | 
			
		||||
            </mask>
 | 
			
		||||
            <use id="fill" fill="#000000" fill-rule="evenodd" xlink:href="#path-3"></use>
 | 
			
		||||
        </g>
 | 
			
		||||
    </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.2 KiB  | 
@ -0,0 +1,102 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { getInitials } from '../../util/getInitials';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  diameter: number;
 | 
			
		||||
  phoneNumber: string;
 | 
			
		||||
  colors: Array<string>;
 | 
			
		||||
  borderColor: string;
 | 
			
		||||
  name?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface State {
 | 
			
		||||
  sha512Seed?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AvatarPlaceHolder extends React.PureComponent<Props, State> {
 | 
			
		||||
  public constructor(props: Props) {
 | 
			
		||||
    super(props);
 | 
			
		||||
 | 
			
		||||
    this.state = {
 | 
			
		||||
      sha512Seed: undefined,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public componentDidMount() {
 | 
			
		||||
    void this.sha512(this.props.phoneNumber).then((sha512Seed: string) => {
 | 
			
		||||
      this.setState({ sha512Seed });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public componentDidUpdate(prevProps: Props, prevState: State) {
 | 
			
		||||
    if (this.props.phoneNumber === prevProps.phoneNumber) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    void this.sha512(this.props.phoneNumber).then((sha512Seed: string) => {
 | 
			
		||||
      this.setState({ sha512Seed });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public render() {
 | 
			
		||||
    if (!this.state.sha512Seed) {
 | 
			
		||||
      return <></>;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const { borderColor, colors, diameter, phoneNumber, name } = this.props;
 | 
			
		||||
    const r = diameter / 2;
 | 
			
		||||
    const initial =
 | 
			
		||||
      getInitials(name)?.toLocaleUpperCase() ||
 | 
			
		||||
      getInitials(phoneNumber)?.toLocaleUpperCase() ||
 | 
			
		||||
      '0';
 | 
			
		||||
    const viewBox = `0 0 ${diameter} ${diameter}`;
 | 
			
		||||
    const fontSize = diameter * 0.5;
 | 
			
		||||
 | 
			
		||||
    // Generate the seed simulate the .hashCode as Java
 | 
			
		||||
    const hash = parseInt(this.state.sha512Seed.substring(0, 12), 16) || 0;
 | 
			
		||||
 | 
			
		||||
    const bgColorIndex = hash % colors.length;
 | 
			
		||||
 | 
			
		||||
    const bgColor = colors[bgColorIndex];
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <svg viewBox={viewBox}>
 | 
			
		||||
        <g id="UrTavla">
 | 
			
		||||
          <circle
 | 
			
		||||
            cx={r}
 | 
			
		||||
            cy={r}
 | 
			
		||||
            r={r}
 | 
			
		||||
            fill={bgColor}
 | 
			
		||||
            shape-rendering="geometricPrecision"
 | 
			
		||||
            stroke={borderColor}
 | 
			
		||||
            stroke-width="1"
 | 
			
		||||
          />
 | 
			
		||||
          <text
 | 
			
		||||
            font-size={fontSize}
 | 
			
		||||
            x="50%"
 | 
			
		||||
            y="50%"
 | 
			
		||||
            fill="white"
 | 
			
		||||
            text-anchor="middle"
 | 
			
		||||
            stroke="white"
 | 
			
		||||
            stroke-width={1}
 | 
			
		||||
            alignment-baseline="central"
 | 
			
		||||
          >
 | 
			
		||||
            {initial}
 | 
			
		||||
          </text>
 | 
			
		||||
        </g>
 | 
			
		||||
      </svg>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async sha512(str: string) {
 | 
			
		||||
    // tslint:disable-next-line: await-promise
 | 
			
		||||
    const buf = await crypto.subtle.digest(
 | 
			
		||||
      'SHA-512',
 | 
			
		||||
      new TextEncoder().encode(str)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // tslint:disable: prefer-template restrict-plus-operands
 | 
			
		||||
    return Array.prototype.map
 | 
			
		||||
      .call(new Uint8Array(buf), (x: any) => ('00' + x.toString(16)).slice(-2))
 | 
			
		||||
      .join('');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,94 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { Avatar } from '../Avatar';
 | 
			
		||||
import { LocalizerType } from '../../types/Util';
 | 
			
		||||
import { ConversationAttributes } from '../../../js/models/conversations';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  size: number;
 | 
			
		||||
  conversations: Array<ConversationAttributes>;
 | 
			
		||||
  i18n: LocalizerType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ClosedGroupAvatar extends React.PureComponent<Props> {
 | 
			
		||||
  public render() {
 | 
			
		||||
    const { conversations, size, i18n } = this.props;
 | 
			
		||||
 | 
			
		||||
    if (conversations.length === 1) {
 | 
			
		||||
      const conv = conversations[0];
 | 
			
		||||
      return (
 | 
			
		||||
        <Avatar
 | 
			
		||||
          avatarPath={conv.avatarPath}
 | 
			
		||||
          noteToSelf={conv.isMe}
 | 
			
		||||
          conversationType="direct"
 | 
			
		||||
          i18n={i18n}
 | 
			
		||||
          name={name}
 | 
			
		||||
          phoneNumber={conv.id}
 | 
			
		||||
          profileName={conv.name}
 | 
			
		||||
          size={size}
 | 
			
		||||
          isPublic={false}
 | 
			
		||||
        />
 | 
			
		||||
      );
 | 
			
		||||
    } else if (conversations.length > 1) {
 | 
			
		||||
      // in a closed group avatar, each visible avatar member size is 2/3 of the group avatar in size
 | 
			
		||||
      // Always use the size directly under the one requested
 | 
			
		||||
      let avatarsDiameter = 0;
 | 
			
		||||
      switch (size) {
 | 
			
		||||
        case 36: {
 | 
			
		||||
          avatarsDiameter = 28;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 48: {
 | 
			
		||||
          avatarsDiameter = 36;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 64: {
 | 
			
		||||
          avatarsDiameter = 48;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 80: {
 | 
			
		||||
          avatarsDiameter = 64;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 300: {
 | 
			
		||||
          avatarsDiameter = 80;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
          throw new Error(
 | 
			
		||||
            `Invalid size request for closed group avatar: ${size}`
 | 
			
		||||
          );
 | 
			
		||||
      }
 | 
			
		||||
      const conv1 = conversations[0];
 | 
			
		||||
      const conv2 = conversations[1];
 | 
			
		||||
      // use the 2 first members as group avatars
 | 
			
		||||
      return (
 | 
			
		||||
        <div className="module-avatar__icon-closed">
 | 
			
		||||
          <Avatar
 | 
			
		||||
            avatarPath={conv1.avatarPath}
 | 
			
		||||
            noteToSelf={conv1.isMe}
 | 
			
		||||
            conversationType="direct"
 | 
			
		||||
            i18n={i18n}
 | 
			
		||||
            name={name}
 | 
			
		||||
            phoneNumber={conv1.id}
 | 
			
		||||
            profileName={conv1.name}
 | 
			
		||||
            size={avatarsDiameter}
 | 
			
		||||
            isPublic={false}
 | 
			
		||||
          />
 | 
			
		||||
          <Avatar
 | 
			
		||||
            avatarPath={conv2.avatarPath}
 | 
			
		||||
            noteToSelf={conv2.isMe}
 | 
			
		||||
            conversationType="direct"
 | 
			
		||||
            i18n={i18n}
 | 
			
		||||
            name={name}
 | 
			
		||||
            phoneNumber={conv2.id}
 | 
			
		||||
            profileName={conv2.name}
 | 
			
		||||
            size={avatarsDiameter}
 | 
			
		||||
            isPublic={false}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      return <></>;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,2 @@
 | 
			
		||||
export { AvatarPlaceHolder } from './AvatarPlaceHolder';
 | 
			
		||||
export { ClosedGroupAvatar } from './ClosedGroupAvatar';
 | 
			
		||||
@ -1,166 +0,0 @@
 | 
			
		||||
// Modified from https://github.com/redlanta/react-jazzicon
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import Color from 'color';
 | 
			
		||||
import { Paper } from './Paper';
 | 
			
		||||
import { RNG } from './RNG';
 | 
			
		||||
 | 
			
		||||
const defaultColors = [
 | 
			
		||||
  '#01888c', // teal
 | 
			
		||||
  '#fc7500', // bright orange
 | 
			
		||||
  '#034f5d', // dark teal
 | 
			
		||||
  '#E784BA', // light pink
 | 
			
		||||
  '#81C8B6', // bright green
 | 
			
		||||
  '#c7144c', // raspberry
 | 
			
		||||
  '#f3c100', // goldenrod
 | 
			
		||||
  '#1598f2', // lightning blue
 | 
			
		||||
  '#2465e1', // sail blue
 | 
			
		||||
  '#f19e02', // gold
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const isColor = (str: string) => /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(str);
 | 
			
		||||
const isColors = (arr: Array<string>) => {
 | 
			
		||||
  if (!Array.isArray(arr)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (arr.every(value => typeof value === 'string' && isColor(value))) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  diameter: number;
 | 
			
		||||
  seed: number;
 | 
			
		||||
  paperStyles?: Object;
 | 
			
		||||
  svgStyles?: Object;
 | 
			
		||||
  shapeCount?: number;
 | 
			
		||||
  wobble?: number;
 | 
			
		||||
  colors?: Array<string>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tslint:disable-next-line no-http-string
 | 
			
		||||
const svgns = 'http://www.w3.org/2000/svg';
 | 
			
		||||
const shapeCount = 4;
 | 
			
		||||
const wobble = 30;
 | 
			
		||||
 | 
			
		||||
export class JazzIcon extends React.PureComponent<Props> {
 | 
			
		||||
  public render() {
 | 
			
		||||
    const {
 | 
			
		||||
      colors: customColors,
 | 
			
		||||
      diameter,
 | 
			
		||||
      paperStyles,
 | 
			
		||||
      seed,
 | 
			
		||||
      svgStyles,
 | 
			
		||||
    } = this.props;
 | 
			
		||||
 | 
			
		||||
    const generator = new RNG(seed);
 | 
			
		||||
 | 
			
		||||
    const colors = customColors || defaultColors;
 | 
			
		||||
 | 
			
		||||
    const newColours = this.hueShift(
 | 
			
		||||
      this.colorsForIcon(colors).slice(),
 | 
			
		||||
      generator
 | 
			
		||||
    );
 | 
			
		||||
    const shapesArr = Array(shapeCount).fill(null);
 | 
			
		||||
    const shuffledColours = this.shuffleArray(newColours, generator);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <Paper color={shuffledColours[0]} diameter={diameter} style={paperStyles}>
 | 
			
		||||
        <svg
 | 
			
		||||
          xmlns={svgns}
 | 
			
		||||
          x="0"
 | 
			
		||||
          y="0"
 | 
			
		||||
          height={diameter}
 | 
			
		||||
          width={diameter}
 | 
			
		||||
          style={svgStyles}
 | 
			
		||||
        >
 | 
			
		||||
          {shapesArr.map((_, i) =>
 | 
			
		||||
            this.genShape(
 | 
			
		||||
              shuffledColours[i + 1],
 | 
			
		||||
              diameter,
 | 
			
		||||
              i,
 | 
			
		||||
              shapeCount - 1,
 | 
			
		||||
              generator
 | 
			
		||||
            )
 | 
			
		||||
          )}
 | 
			
		||||
        </svg>
 | 
			
		||||
      </Paper>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private hueShift(colors: Array<string>, generator: RNG) {
 | 
			
		||||
    const amount = generator.random() * 30 - wobble / 2;
 | 
			
		||||
 | 
			
		||||
    return colors.map(hex =>
 | 
			
		||||
      Color(hex)
 | 
			
		||||
        .rotate(amount)
 | 
			
		||||
        .hex()
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private genShape(
 | 
			
		||||
    colour: string,
 | 
			
		||||
    diameter: number,
 | 
			
		||||
    i: number,
 | 
			
		||||
    total: number,
 | 
			
		||||
    generator: RNG
 | 
			
		||||
  ) {
 | 
			
		||||
    const center = diameter / 2;
 | 
			
		||||
    const firstRot = generator.random();
 | 
			
		||||
    const angle = Math.PI * 2 * firstRot;
 | 
			
		||||
    const velocity =
 | 
			
		||||
      (diameter / total) * generator.random() + (i * diameter) / total;
 | 
			
		||||
    const tx = Math.cos(angle) * velocity;
 | 
			
		||||
    const ty = Math.sin(angle) * velocity;
 | 
			
		||||
    const translate = `translate(${tx} ${ty})`;
 | 
			
		||||
 | 
			
		||||
    // Third random is a shape rotation on top of all of that.
 | 
			
		||||
    const secondRot = generator.random();
 | 
			
		||||
    const rot = firstRot * 360 + secondRot * 180;
 | 
			
		||||
    const rotate = `rotate(${rot.toFixed(1)} ${center} ${center})`;
 | 
			
		||||
    const transform = `${translate} ${rotate}`;
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <rect
 | 
			
		||||
        key={i}
 | 
			
		||||
        x="0"
 | 
			
		||||
        y="0"
 | 
			
		||||
        rx="0"
 | 
			
		||||
        ry="0"
 | 
			
		||||
        height={diameter}
 | 
			
		||||
        width={diameter}
 | 
			
		||||
        transform={transform}
 | 
			
		||||
        fill={colour}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private colorsForIcon(arr: Array<string>) {
 | 
			
		||||
    if (isColors(arr)) {
 | 
			
		||||
      return arr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return defaultColors;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private shuffleArray<T>(array: Array<T>, generator: RNG) {
 | 
			
		||||
    let currentIndex = array.length;
 | 
			
		||||
    const newArray = [...array];
 | 
			
		||||
 | 
			
		||||
    // While there remain elements to shuffle...
 | 
			
		||||
    while (currentIndex > 0) {
 | 
			
		||||
      // Pick a remaining element...
 | 
			
		||||
      const randomIndex = generator.next() % currentIndex;
 | 
			
		||||
      currentIndex -= 1;
 | 
			
		||||
      // And swap it with the current element.
 | 
			
		||||
      const temporaryValue = newArray[currentIndex];
 | 
			
		||||
      newArray[currentIndex] = newArray[randomIndex];
 | 
			
		||||
      newArray[randomIndex] = temporaryValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return newArray;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const styles = {
 | 
			
		||||
  borderRadius: '50%',
 | 
			
		||||
  display: 'inline-block',
 | 
			
		||||
  margin: 0,
 | 
			
		||||
  overflow: 'hidden',
 | 
			
		||||
  padding: 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
export const Paper = ({ children, color, diameter, style: styleOverrides }) => (
 | 
			
		||||
  <div
 | 
			
		||||
    className="paper"
 | 
			
		||||
    style={{
 | 
			
		||||
      ...styles,
 | 
			
		||||
      backgroundColor: color,
 | 
			
		||||
      height: diameter,
 | 
			
		||||
      width: diameter,
 | 
			
		||||
      ...(styleOverrides || {}),
 | 
			
		||||
    }}
 | 
			
		||||
  >
 | 
			
		||||
    {children}
 | 
			
		||||
  </div>
 | 
			
		||||
);
 | 
			
		||||
@ -1,21 +0,0 @@
 | 
			
		||||
export class RNG {
 | 
			
		||||
  private _seed: number;
 | 
			
		||||
  constructor(seed: number) {
 | 
			
		||||
    this._seed = seed % 2147483647;
 | 
			
		||||
    if (this._seed <= 0) {
 | 
			
		||||
      this._seed += 2147483646;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public next() {
 | 
			
		||||
    return (this._seed = (this._seed * 16807) % 2147483647);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public nextFloat() {
 | 
			
		||||
    return (this.next() - 1) / 2147483646;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public random() {
 | 
			
		||||
    return this.nextFloat();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
import { JazzIcon } from './JazzIcon';
 | 
			
		||||
export { JazzIcon };
 | 
			
		||||
@ -0,0 +1,63 @@
 | 
			
		||||
import { GroupUtils } from '../../session/utils';
 | 
			
		||||
import { UserUtil } from '../../util';
 | 
			
		||||
import { PubKey } from '../../session/types';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { ConversationAttributes } from '../../../js/models/conversations';
 | 
			
		||||
type State = {
 | 
			
		||||
  closedMemberConversations?: Array<ConversationAttributes>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function usingClosedConversationDetails(WrappedComponent: any) {
 | 
			
		||||
  return class extends React.Component<any, State> {
 | 
			
		||||
    constructor(props: any) {
 | 
			
		||||
      super(props);
 | 
			
		||||
      this.state = {
 | 
			
		||||
        closedMemberConversations: undefined,
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public componentDidMount() {
 | 
			
		||||
      void this.fetchClosedConversationDetails();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public componentDidUpdate() {
 | 
			
		||||
      void this.fetchClosedConversationDetails();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public render() {
 | 
			
		||||
      return (
 | 
			
		||||
        <WrappedComponent
 | 
			
		||||
          closedMemberConversations={this.state.closedMemberConversations}
 | 
			
		||||
          {...this.props}
 | 
			
		||||
        />
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async fetchClosedConversationDetails() {
 | 
			
		||||
      const {
 | 
			
		||||
        isPublic,
 | 
			
		||||
        type,
 | 
			
		||||
        conversationType,
 | 
			
		||||
        isGroup,
 | 
			
		||||
        phoneNumber,
 | 
			
		||||
        id,
 | 
			
		||||
      } = this.props;
 | 
			
		||||
      if (
 | 
			
		||||
        !isPublic &&
 | 
			
		||||
        (conversationType === 'group' || type === 'group' || isGroup)
 | 
			
		||||
      ) {
 | 
			
		||||
        const groupId = id || phoneNumber;
 | 
			
		||||
        let members = await GroupUtils.getGroupMembers(PubKey.cast(groupId));
 | 
			
		||||
        const ourPrimary = await UserUtil.getPrimary();
 | 
			
		||||
        members = members.filter(m => m.key !== ourPrimary.key);
 | 
			
		||||
        members.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
 | 
			
		||||
        const membersConvos = members.map(
 | 
			
		||||
          m => window.ConversationController.get(m.key).cachedProps
 | 
			
		||||
        );
 | 
			
		||||
        // no need to forward more than 2 conversation for rendering the group avatar
 | 
			
		||||
        membersConvos.slice(0, 2);
 | 
			
		||||
        this.setState({ closedMemberConversations: membersConvos });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue