Support for iOS theme
This commit is contained in:
parent
644bc9e6fb
commit
087dd0f758
7 changed files with 226 additions and 19 deletions
|
@ -428,6 +428,24 @@
|
|||
"selectAContact": {
|
||||
"message": "Select a contact or group to start chatting."
|
||||
},
|
||||
"replyingToYourself": {
|
||||
"message": "Replying to Yourself",
|
||||
"description": "Shown in iOS theme when you quote yourself"
|
||||
},
|
||||
"replyingToYou": {
|
||||
"message": "Replying to You",
|
||||
"description": "Shown in iOS theme when someone else quotes a message from you"
|
||||
},
|
||||
"replyingTo": {
|
||||
"message": "Replying to $name`$",
|
||||
"description": "Shown in iOS theme when you or someone quotes to a message which is not from you",
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"content": "$1",
|
||||
"example": "John"
|
||||
}
|
||||
}
|
||||
},
|
||||
"audio": {
|
||||
"message": "Audio",
|
||||
"description": "Shown in a quotation of a message containing an audio attachment if no text was originally provided with that attachment"
|
||||
|
|
|
@ -400,29 +400,30 @@
|
|||
});
|
||||
}
|
||||
|
||||
const OUR_NUMBER = textsecure.storage.user.getNumber();
|
||||
const { author } = quote;
|
||||
const contact = ConversationController.get(author);
|
||||
|
||||
const authorTitle = contact ? contact.getTitle() : author;
|
||||
const authorProfileName = contact ? contact.getProfileName() : null;
|
||||
const authorColor = contact ? contact.getColor() : 'grey';
|
||||
const isFromMe = contact ? contact.id === OUR_NUMBER : false;
|
||||
const isIncoming = this.model.isIncoming();
|
||||
const quoterContact = this.model.getContact();
|
||||
const quoterAuthorColor = quoterContact ? quoterContact.getColor() : null;
|
||||
|
||||
const props = {
|
||||
authorTitle,
|
||||
authorProfileName,
|
||||
attachments: quote.attachments && quote.attachments.map(processAttachment),
|
||||
authorColor,
|
||||
authorProfileName,
|
||||
authorTitle,
|
||||
isFromMe,
|
||||
isIncoming,
|
||||
quoterAuthorColor,
|
||||
openQuotedMessage: () => {
|
||||
onClick: () => {
|
||||
const { quotedMessage } = this.model;
|
||||
if (quotedMessage) {
|
||||
this.trigger('scroll-to-message', { id: quotedMessage.id });
|
||||
}
|
||||
},
|
||||
text: quote.text,
|
||||
attachments: quote.attachments && quote.attachments.map(processAttachment),
|
||||
};
|
||||
|
||||
if (!this.replyView) {
|
||||
|
|
|
@ -379,11 +379,7 @@ li.entry .error-icon-container {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.message-list .outgoing .bubble .quote {
|
||||
margin-top: $android-bubble-quote-padding - $android-bubble-padding-vertical;
|
||||
}
|
||||
|
||||
.private .message-list .incoming .bubble .quote {
|
||||
.message-list .outgoing .bubble .quote, .private .message-list .incoming .bubble .quote {
|
||||
margin-top: $android-bubble-quote-padding - $android-bubble-padding-vertical;
|
||||
}
|
||||
|
||||
|
@ -479,7 +475,7 @@ span.status {
|
|||
margin-bottom: 0.5em;
|
||||
|
||||
// Accent color border:
|
||||
border-left-width: 3;
|
||||
border-left-width: 3px;
|
||||
border-left-style: solid;
|
||||
|
||||
.primary {
|
||||
|
@ -489,6 +485,12 @@ span.status {
|
|||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
|
||||
// Will turn on in the iOS theme. This extra element is necessary because the iOS
|
||||
// theme requires text that isn't used at all in the Android Theme
|
||||
.ios-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.author {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.3em;
|
||||
|
|
|
@ -106,6 +106,130 @@ $ios-border-color: rgba(0,0,0,0.1);
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
.message-list {
|
||||
.quote {
|
||||
border-top-left-radius: 15px;
|
||||
border-top-right-radius: 15px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
|
||||
// Not ideal, but necessary to override the specificity of the android theme color
|
||||
// classes used in conversations.scss
|
||||
background-color: white !important;
|
||||
border: 1px solid lightgray !important;
|
||||
border-bottom: none !important;
|
||||
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
|
||||
.primary {
|
||||
padding: 10px;
|
||||
|
||||
.text,
|
||||
.filename-label,
|
||||
.type-label {
|
||||
border-left: 2px solid lightgray;
|
||||
padding: 5px;
|
||||
padding-left: 7px;
|
||||
// Without this smaller bottom padding, text beyond four lines still shows up!
|
||||
padding-bottom: 2px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.author {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ios-label {
|
||||
display: block;
|
||||
color: lightgray;
|
||||
font-size: smaller;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
height: 61px;
|
||||
width: 61px;
|
||||
|
||||
.circle-background {
|
||||
left: 12px;
|
||||
right: 12px;
|
||||
top: 12px;
|
||||
bottom: 12px;
|
||||
|
||||
background-color: $blue !important;
|
||||
}
|
||||
|
||||
.icon {
|
||||
left: 18px;
|
||||
right: 18px;
|
||||
top: 18px;
|
||||
bottom: 18px;
|
||||
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.inner {
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.from-me {
|
||||
.primary {
|
||||
.text,
|
||||
.filename-label,
|
||||
.type-label {
|
||||
border-left: 2px solid $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.incoming {
|
||||
.bubble {
|
||||
.quote {
|
||||
background-color: lightgray !important;
|
||||
border-left: none;
|
||||
|
||||
.ios-label {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.primary {
|
||||
.text,
|
||||
.filename-label,
|
||||
.type-label {
|
||||
border-left: 2px solid white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble {
|
||||
.quote.from-me {
|
||||
.primary {
|
||||
.text,
|
||||
.filename-label,
|
||||
.type-label {
|
||||
border-left: 2px solid $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.outgoing .bubble .quote,
|
||||
.private .message-list .incoming .bubble .quote {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.outgoing .bubble .quote .icon-container .circle-background {
|
||||
background-color: lightgray !important;
|
||||
}
|
||||
}
|
||||
|
||||
.attachments .bubbled {
|
||||
border-radius: 15px;
|
||||
|
|
|
@ -34,6 +34,39 @@ const View = Whisper.MessageView;
|
|||
</util.ConversationContext>
|
||||
```
|
||||
|
||||
#### Replies to you or yourself
|
||||
|
||||
```jsx
|
||||
const outgoing = new Whisper.Message({
|
||||
type: 'outgoing',
|
||||
body: 'About six',
|
||||
sent_at: Date.now() - 18000000,
|
||||
quote: {
|
||||
text: 'How many ferrets do you have?',
|
||||
author: util.ourNumber,
|
||||
id: Date.now() - 1000,
|
||||
},
|
||||
});
|
||||
const incoming = new Whisper.Message(Object.assign({}, outgoing.attributes, {
|
||||
source: '+12025550011',
|
||||
type: 'incoming',
|
||||
quote: Object.assign({}, outgoing.attributes.quote, {
|
||||
author: util.ourNumber,
|
||||
}),
|
||||
}));
|
||||
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
|
||||
|
|
|
@ -11,9 +11,9 @@ interface Props {
|
|||
authorProfileName?: string;
|
||||
authorTitle: string;
|
||||
i18n: (key: string, values?: Array<string>) => string;
|
||||
isFromMe: string;
|
||||
isIncoming: boolean;
|
||||
openQuotedMessage?: () => void;
|
||||
quoterAuthorColor?: string;
|
||||
onClick?: () => void;
|
||||
text: string;
|
||||
}
|
||||
|
||||
|
@ -68,10 +68,10 @@ export class Quote extends React.Component<Props, {}> {
|
|||
}
|
||||
|
||||
public renderIcon(icon: string) {
|
||||
const { authorColor, isIncoming, quoterAuthorColor } = this.props;
|
||||
const { authorColor, isIncoming } = this.props;
|
||||
|
||||
const backgroundColor = isIncoming ? 'white' : authorColor;
|
||||
const iconColor = isIncoming ? quoterAuthorColor : 'white';
|
||||
const iconColor = isIncoming ? authorColor : 'white';
|
||||
|
||||
return (
|
||||
<div className="icon-container">
|
||||
|
@ -138,12 +138,28 @@ export class Quote extends React.Component<Props, {}> {
|
|||
return <div className="filename-label">{fileName}</div>;
|
||||
}
|
||||
|
||||
public renderIOSLabel() {
|
||||
const { i18n, isIncoming, isFromMe, authorTitle, authorProfileName } = this.props;
|
||||
|
||||
const profileString = authorProfileName ? ` ~${authorProfileName}` : '';
|
||||
const authorName = `${authorTitle}${profileString}`;
|
||||
|
||||
const label = isFromMe
|
||||
? isIncoming
|
||||
? i18n('replyingToYou')
|
||||
: i18n('replyingToYourself')
|
||||
: i18n('replyingTo', [authorName]);
|
||||
|
||||
return <div className='ios-label'>{label}</div>;
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
authorTitle,
|
||||
authorProfileName,
|
||||
authorColor,
|
||||
openQuotedMessage,
|
||||
onClick,
|
||||
isFromMe,
|
||||
} = this.props;
|
||||
|
||||
if (!validateQuote(this.props)) {
|
||||
|
@ -155,8 +171,13 @@ export class Quote extends React.Component<Props, {}> {
|
|||
: null;
|
||||
|
||||
return (
|
||||
<div onClick={openQuotedMessage} className={classnames(authorColor, 'quote')} >
|
||||
<div onClick={onClick} className={classnames(
|
||||
authorColor,
|
||||
'quote',
|
||||
isFromMe ? 'from-me' : null
|
||||
)} >
|
||||
<div className="primary">
|
||||
{this.renderIOSLabel()}
|
||||
<div className={classnames(authorColor, 'author')}>
|
||||
{authorTitle}{' '}{authorProfileElement}
|
||||
</div>
|
||||
|
|
|
@ -141,9 +141,17 @@ const CONTACTS = COLORS.map((color, index) => {
|
|||
return parent.ConversationController.dangerouslyCreateAndAdd(contact);
|
||||
});
|
||||
|
||||
const me = parent.ConversationController.dangerouslyCreateAndAdd({
|
||||
id: ourNumber,
|
||||
name: 'Me!',
|
||||
type: 'private',
|
||||
color: 'light_blue',
|
||||
});
|
||||
|
||||
export {
|
||||
COLORS,
|
||||
CONTACTS,
|
||||
me,
|
||||
};
|
||||
|
||||
parent.textsecure.storage.user.getNumber = () => ourNumber;
|
||||
|
|
Loading…
Reference in a new issue