673 lines
17 KiB
Markdown
673 lines
17 KiB
Markdown
Placeholder component:
|
|
|
|
```jsx
|
|
<util.ConversationContext theme={util.theme}>
|
|
<Message />
|
|
</util.ConversationContext>
|
|
```
|
|
|
|
## MessageView (Backbone)
|
|
|
|
### Plain messages
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: 'How are you doing this fine day?',
|
|
sent_at: Date.now() - 18000,
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
### In a group conversation
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: 'How are you doing this fine day?',
|
|
sent_at: Date.now() - 200000,
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme} type="group">
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
### With an error
|
|
|
|
#### General error
|
|
|
|
```jsx
|
|
const error = new Error('Something went wrong!');
|
|
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: "This message won't get through...",
|
|
sent_at: Date.now() - 200000,
|
|
errors: [error],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
body: null,
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Network error (outgoing only)
|
|
|
|
```jsx
|
|
const error = new Error('Something went wrong!');
|
|
error.name = 'MessageError';
|
|
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 200000,
|
|
errors: [error],
|
|
body: "This message won't get through...",
|
|
});
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme} type="group">
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Network error, partial send in group (outgoing only)
|
|
|
|
```jsx
|
|
const error = new Error('Something went wrong!');
|
|
error.name = 'MessageError';
|
|
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 200000,
|
|
errors: [error],
|
|
conversationId: util.groupNumber,
|
|
body: "This message won't get through...",
|
|
});
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme} type="group">
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### No message contents
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 200000,
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
### Disappearing
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 200000,
|
|
expireTimer: 120,
|
|
expirationStartTimestamp: Date.now() - 1000,
|
|
body: 'This message will self-destruct in two minutes',
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
### Notfications
|
|
|
|
#### Timer change
|
|
|
|
```jsx
|
|
const fromOther = new Whisper.Message({
|
|
type: 'incoming',
|
|
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
|
source: '+12025550003',
|
|
sent_at: Date.now() - 200000,
|
|
expireTimer: 120,
|
|
expirationStartTimestamp: Date.now() - 1000,
|
|
expirationTimerUpdate: {
|
|
source: '+12025550003',
|
|
},
|
|
});
|
|
const fromUpdate = new Whisper.Message({
|
|
type: 'incoming',
|
|
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
|
source: util.ourNumber,
|
|
sent_at: Date.now() - 200000,
|
|
expireTimer: 120,
|
|
expirationStartTimestamp: Date.now() - 1000,
|
|
expirationTimerUpdate: {
|
|
fromSync: true,
|
|
source: util.ourNumber,
|
|
},
|
|
});
|
|
const fromMe = new Whisper.Message({
|
|
type: 'incoming',
|
|
flags: textsecure.protobuf.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
|
source: util.ourNumber,
|
|
sent_at: Date.now() - 200000,
|
|
expireTimer: 120,
|
|
expirationStartTimestamp: Date.now() - 1000,
|
|
expirationTimerUpdate: {
|
|
source: util.ourNumber,
|
|
},
|
|
});
|
|
const View = Whisper.ExpirationTimerUpdateView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: fromOther }} />
|
|
<util.BackboneWrapper View={View} options={{ model: fromUpdate }} />
|
|
<util.BackboneWrapper View={View} options={{ model: fromMe }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Safety number change
|
|
|
|
```js
|
|
const incoming = new Whisper.Message({
|
|
type: 'keychange',
|
|
sent_at: Date.now() - 200000,
|
|
key_changed: '+12025550003',
|
|
});
|
|
const View = Whisper.KeyChangeView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Marking as verified
|
|
|
|
```js
|
|
const fromPrimary = new Whisper.Message({
|
|
type: 'verified-change',
|
|
sent_at: Date.now() - 200000,
|
|
verifiedChanged: '+12025550003',
|
|
verified: true,
|
|
});
|
|
const local = new Whisper.Message({
|
|
type: 'verified-change',
|
|
sent_at: Date.now() - 200000,
|
|
verifiedChanged: '+12025550003',
|
|
local: true,
|
|
verified: true,
|
|
});
|
|
|
|
const View = Whisper.VerifiedChangeView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: fromPrimary }} />
|
|
<util.BackboneWrapper View={View} options={{ model: local }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Marking as not verified
|
|
|
|
```js
|
|
const fromPrimary = new Whisper.Message({
|
|
type: 'verified-change',
|
|
sent_at: Date.now() - 200000,
|
|
verifiedChanged: '+12025550003',
|
|
});
|
|
const local = new Whisper.Message({
|
|
type: 'verified-change',
|
|
sent_at: Date.now() - 200000,
|
|
verifiedChanged: '+12025550003',
|
|
local: true,
|
|
});
|
|
|
|
const View = Whisper.VerifiedChangeView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: fromPrimary }} />
|
|
<util.BackboneWrapper View={View} options={{ model: local }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Group update
|
|
|
|
```js
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 200000,
|
|
group_update: {
|
|
joined: ['+12025550007', '+12025550008', '+12025550009'],
|
|
},
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### End session
|
|
|
|
```js
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 200000,
|
|
flags: textsecure.protobuf.DataMessage.Flags.END_SESSION,
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
### With an attachment
|
|
|
|
#### Image with caption
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: 'I am pretty confused about Pi.',
|
|
sent_at: Date.now() - 18000000,
|
|
attachments: [
|
|
{
|
|
data: util.gif,
|
|
fileName: 'pi.gif',
|
|
contentType: 'image/gif',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Image
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 18000000,
|
|
attachments: [
|
|
{
|
|
data: util.gif,
|
|
fileName: 'pi.gif',
|
|
contentType: 'image/gif',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Image with portrait aspect ratio
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 18000000,
|
|
attachments: [
|
|
{
|
|
data: util.portraitYellow,
|
|
fileName: 'portraitYellow.png',
|
|
contentType: 'image/png',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Image with portrait aspect ratio and caption
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: 'This is an odd yellow bar. Cool, huh?',
|
|
sent_at: Date.now() - 18000000,
|
|
attachments: [
|
|
{
|
|
data: util.portraitYellow,
|
|
fileName: 'portraitYellow.png',
|
|
contentType: 'image/png',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Image with landscape aspect ratio
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 18000000,
|
|
attachments: [
|
|
{
|
|
data: util.landscapePurple,
|
|
fileName: 'landscapePurple.jpg',
|
|
contentType: 'image/jpeg',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Image with landscape aspect ratio and caption
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: "An interesting horizontal bar. It's art.",
|
|
sent_at: Date.now() - 18000000,
|
|
attachments: [
|
|
{
|
|
data: util.landscapePurple,
|
|
fileName: 'landscapePurple.jpg',
|
|
contentType: 'image/jpeg',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Video with caption
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: "Beautiful, isn't it?",
|
|
sent_at: Date.now() - 10000,
|
|
attachments: [
|
|
{
|
|
data: util.mp4,
|
|
fileName: 'freezing_bubble.mp4',
|
|
contentType: 'video/mp4',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Video
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 10000,
|
|
attachments: [
|
|
{
|
|
data: util.mp4,
|
|
fileName: 'freezing_bubble.mp4',
|
|
contentType: 'video/mp4',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Audio with caption
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: 'This is a nice song',
|
|
sent_at: Date.now() - 15000,
|
|
attachments: [
|
|
{
|
|
data: util.mp3,
|
|
fileName: 'agnus_dei.mp3',
|
|
contentType: 'audio/mp3',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Audio
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 15000,
|
|
attachments: [
|
|
{
|
|
data: util.mp3,
|
|
fileName: 'agnus_dei.mp3',
|
|
contentType: 'audio/mp3',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Voice message
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 15000,
|
|
attachments: [
|
|
{
|
|
flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE,
|
|
data: util.mp3,
|
|
fileName: 'agnus_dei.mp3',
|
|
contentType: 'audio/mp3',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Other file type with caption
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
body: 'My manifesto is now complete!',
|
|
sent_at: Date.now() - 15000,
|
|
attachments: [
|
|
{
|
|
data: util.txt,
|
|
fileName: 'lorum_ipsum.txt',
|
|
contentType: 'text/plain',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|
|
|
|
#### Other file type
|
|
|
|
```jsx
|
|
const outgoing = new Whisper.Message({
|
|
type: 'outgoing',
|
|
sent_at: Date.now() - 15000,
|
|
attachments: [
|
|
{
|
|
data: util.txt,
|
|
fileName: 'lorum_ipsum.txt',
|
|
contentType: 'text/plain',
|
|
},
|
|
],
|
|
});
|
|
const incoming = new Whisper.Message(
|
|
Object.assign({}, outgoing.attributes, {
|
|
source: '+12025550003',
|
|
type: 'incoming',
|
|
})
|
|
);
|
|
const View = Whisper.MessageView;
|
|
<util.ConversationContext theme={util.theme}>
|
|
<util.BackboneWrapper View={View} options={{ model: incoming }} />
|
|
<util.BackboneWrapper View={View} options={{ model: outgoing }} />
|
|
</util.ConversationContext>;
|
|
```
|